Vulkan: update uniform buffer each frame - c++

I want to update uniform buffer each frame, but I don't want to create separate buffers per frame.
I want to have one buffer per material for simplicity.
What is the best method for update this buffer?
I've tried to use mapped buffer, but I have some rendering artifacts, when buffer is updating.
Now I'm trying to use vkCmdCopyBuffer with vkCmdPipelineBarrier and I use temprorary CommandBuffer (s_cmd) because frame's CommandBuffer is within a render pass instance.
Everything looks fine, but I'm not sure if this is correct.
auto s_cmd = getVulkanRenderer()->beginSingleTimeCommands();
VulkanBuffer stagingBuffer(
vk::BufferUsageFlagBits::eTransferSrc,
sizeof(glm::mat4[2]),
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT
);
stagingBuffer.updateRange(data, sizeof(data), 0);
auto buffer_barrier_1 = vk::BufferMemoryBarrier{}
.setBuffer(material_instance->uniformBuffer->getNativeHandle())
.setOffset(0)
.setSize(sizeof(glm::mat4[2]))
.setSrcAccessMask(vk::AccessFlagBits::eHostWrite)
.setDstAccessMask(vk::AccessFlagBits::eTransferRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
s_cmd.pipelineBarrier(
vk::PipelineStageFlagBits::eHost,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlags{},
{},
{buffer_barrier_1},
{}
);
s_cmd.copyBuffer(stagingBuffer.getNativeHandle(), material_instance->uniformBuffer->getNativeHandle(), {
vk::BufferCopy(0, 0, sizeof(glm::mat4[2]))
});
auto buffer_barrier_2 = vk::BufferMemoryBarrier{}
.setBuffer(material_instance->uniformBuffer->getNativeHandle())
.setOffset(0)
.setSize(sizeof(glm::mat4[2]))
.setSrcAccessMask(vk::AccessFlagBits::eTransferRead)
.setDstAccessMask(vk::AccessFlagBits::eVertexAttributeRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
s_cmd.pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eVertexInput,
vk::DependencyFlags{},
{},
{buffer_barrier_2},
{}
);
getVulkanRenderer()->endSingleTimeCommands(s_cmd);

Related

Having a dificult time with Directx11 dynamic texture Map/Unmap

I have been trying to upload a dynamic texture with Map/Unmap but no luck so far.
Here's the code im working with
D3D11_MAPPED_SUBRESOURCE subResource = {};
ImmediateContext->Map(dx11Texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
Memory::copy(subResource.pData, (const void*)desc.DataSet[0], texture->get_width() * texture->get_height() * GraphicsFormatUtils::get_format_size(texture->get_format()));
subResource.RowPitch = texture->get_width() * GraphicsFormatUtils::get_format_size(texture->get_format());
subResource.DepthPitch = 0;
ImmediateContext->Unmap(dx11Texture, 0);
I have created the texture with immutable state and supplying the data upfront, that worked out well but when i try to create it with a dynamic flag and upload the same data my texture shows a noisy visual.
This is the texture with immutable creation flags and updating the data upfront on the texture creation phase.
Immutable texture
This is the texture with dynamic creation flags and updating the data after the texture creation phase with Map/Unmap mehtods.
Dynamic texture
Any input would be appreciated.
When using map, the subResource rowPitch that is returned by the map function is the one that is expected for you to perform the copy (you can notice that you never send it back to the deviceContext, so it's read only).
It is generally a power of 2, for memory alignment purposes.
When you provide initial data in an (immutable or other) texture, this copy operation is hidden from you, but still happens behind the scene, so in that case, you need to perform the pitch test yourself.
The process of copying a dynamic texture is as follow :
int myDataRowPitch =; //width * format size (if you don't pad)
D3D11_MAPPED_SUBRESOURCE subResource = {};
ImmediateContext->Map(dx11Texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
if (myDataRowPitch == subResource.RowPitch)
{
//you can do a standard mem copy here
}
else
{
// here you need to copy line per line
}
ImmediateContext->Unmap(dx11Texture, 0);

Handle multiply cameras in Vulkan

I'm trying to implement rendering with different cameras.
When I use only one camera, everything is ok. But when I have two cameras with different transformation, rendering doesn't work properly, first scene is rendered with second camera transformation.
void Setup() {
...
// create uniform buffer (vmaCreateBuffer)
global_uniform_buffer = ...
// allocate descriptor set
global_descriptor_set = ...
// write descriptor set
...
}
void SetCameraProperties(Camera* camera) {
auto proj_view = camera->GetProjectionMatrix() * camera->GetViewMatrix();
global_uniform_buffer->update(&proj_view, sizeof(glm::mat4));
}
void BindGlobalDescriptorSet(vk::CommandBuffer cmd, vk::PipelineLayout pipeline_layout) {
cmd.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics,
pipeline_layout,
0,
{ global_descriptor_set },
{}
);
}
void DrawScene() {
...
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
BindGlobalDescriptorSet(cmd, pipeline_layout);
cmd.bindVertexBuffers(0, vtx->handle, vk::DeviceSize{0});
cmd.bindIndexBuffer(idx->handle, vk::DeviceSize{0}, vk::IndexType::eUint16);
cmd.drawIndexed(3, 1, 0, 0, 0);
...
}
void Loop() {
... // begin render pass with scene framebuffer
SetCameraProperties(Editor::Get()->GetEditorCamera()):
DrawScene();
... // end previous render pass
... // begin render pass with game frame buffer
SetCameraProperties(CameraSystem::Get()->GetMainCamera()):
DrawScene();
... // end previous render pass
... // present
}
Looking at your code, you change the same uniform buffer between two draw calls at command buffer creation time. But the contents of the bound uniform buffer are consumed at submission time instead and not at creation time. So by the time you submit your command buffer, it uses the uniform buffer contents from your last update.
So your current setup won't work in Vulkan that way. To make this work, you could use one UBO per camera or one dynamic UBO with separate ranges for the cameras.

Applying HLSL Pixel Shaders to Win32 Screen Capture

A little background: I'm attempting to make a Windows (10) application which makes the screen look like an old CRT monitor, scanlines, blur, and all. I'm using this official Microsoft screen capture demo as a starting point: At this stage I can capture a window, and display it back in a new mouse-through window as if it were the original window.
I am attempting to use the CRT-Royale CRT shaders which are generally considered the best CRT shaders; these are available in .cg format. I transpile them with cgc to hlsl, then compile the hlsl files to compiled shader byte code with fxc. I am able to successfully load the compiled shaders and create the pixel shader. I then set the pixel shader in the d3d context. I then attempt to copy the capture surface frame to a pixel shader resource and set the created shaders resource. All of this builds and runs, but I do not see any difference in the output image and am not sure how to proceed. Below is the relevant code. I am not a c++ developer and am making this as a personal project which I plan on open sourcing once I have a primitive working version. Any advice is appreciated, thanks.
SimpleCapture::SimpleCapture(
IDirect3DDevice const& device,
GraphicsCaptureItem const& item)
{
m_item = item;
m_device = device;
// Set up
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
d3dDevice->GetImmediateContext(m_d3dContext.put());
auto size = m_item.Size();
m_swapChain = CreateDXGISwapChain(
d3dDevice,
static_cast<uint32_t>(size.Width),
static_cast<uint32_t>(size.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
2);
// ADDED THIS
HRESULT hr1 = D3DReadFileToBlob(L"crt-royale-first-pass-ps_4_0.fxc", &ps_1_buffer);
HRESULT hr = d3dDevice->CreatePixelShader(
ps_1_buffer->GetBufferPointer(),
ps_1_buffer->GetBufferSize(),
nullptr,
&ps_1
);
m_d3dContext->PSSetShader(
ps_1,
nullptr,
0
);
// END OF ADDED CHANGES
// Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and frame size.
m_framePool = Direct3D11CaptureFramePool::Create(
m_device,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2,
size);
m_session = m_framePool.CreateCaptureSession(m_item);
m_lastSize = size;
m_frameArrived = m_framePool.FrameArrived(auto_revoke, { this, &SimpleCapture::OnFrameArrived });
}
void SimpleCapture::OnFrameArrived(
Direct3D11CaptureFramePool const& sender,
winrt::Windows::Foundation::IInspectable const&)
{
auto newSize = false;
{
auto frame = sender.TryGetNextFrame();
auto frameContentSize = frame.ContentSize();
if (frameContentSize.Width != m_lastSize.Width ||
frameContentSize.Height != m_lastSize.Height)
{
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
newSize = true;
m_lastSize = frameContentSize;
m_swapChain->ResizeBuffers(
2,
static_cast<uint32_t>(m_lastSize.Width),
static_cast<uint32_t>(m_lastSize.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
0);
}
{
auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
com_ptr<ID3D11Texture2D> backBuffer;
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
// ADDED THIS
D3D11_TEXTURE2D_DESC txtDesc = {};
txtDesc.MipLevels = txtDesc.ArraySize = 1;
txtDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
txtDesc.SampleDesc.Count = 1;
txtDesc.Usage = D3D11_USAGE_IMMUTABLE;
txtDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
ID3D11Texture2D *tex;
d3dDevice->CreateTexture2D(&txtDesc, NULL,
&tex);
frameSurface.copy_to(&tex);
d3dDevice->CreateShaderResourceView(
tex,
nullptr,
srv_1
);
auto texture = srv_1;
m_d3dContext->PSSetShaderResources(0, 1, texture);
// END OF ADDED CHANGES
m_d3dContext->CopyResource(backBuffer.get(), frameSurface.get());
}
}
DXGI_PRESENT_PARAMETERS presentParameters = { 0 };
m_swapChain->Present1(1, 0, &presentParameters);
... // Truncated
Shaders define how things are drawn. However, you don't draw anything - you just copy, which is why the shader doesn't do anything.
What you should do is to remove the CopyResource call, and instead draw a full screen quad on the back buffer (Which requires you to create a vertex buffer that you can bind, then set the back buffer as render target, and finally call Draw/DrawIndexed to actually render something, which then will invoke the shader).
Also - since I'm not sure whether you already do this and just stripped it from the shown code - functions like CreatePixelShader don't return HRESULTs just for the fun of it - you should check what is actually returned, because DirectX silently returns most errors and expects you to handle them, instead of crashing your program.

Direct3D c++ api how to update vertex buffer?

So how can one update values in vertex buffer bound into device object using IASetVertexBuffers method? Also will changing values in this buffer before call to Draw() and Present()? Also will the image be updated according to these new values in buffer?
To update a vertex buffer by the CPU, you must first create a dynamic vertex buffer that allows the CPU to write to it. To do this, call ID3D11Device::CreateBufferwith Usage set to D3D11_USAGE_DYNAMIC and CPUAccessFlags set to D3D11_CPU_ACCESS_WRITE. Example:
D3D11_BUFFER_DESC desc;
ZeroMemory( &desc, sizeof( desc ) );
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = size;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
d3dDevice->CreateBuffer( &desc, initialVertexData, &vertexBuffer );
Now that you have a dynamic vertex buffer, you can update it using ID3D11DeviceContext::Map and ID3D11DeviceContext::Unmap. Example:
D3D11_MAPPED_SUBRESOURCE resource;
d3dDeviceContext->Map( vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource );
memcpy( resource.pData, sourceData, vertexDataSize );
d3dDeviceContext->Unmap( vertexBuffer, 0 );
where sourceData is the new vertex data you want to put into the buffer.
This is one method for updating a vertex buffer where you are uploading a whole new set of vertex data and discarding previous contents. There are also other ways to update a vertex buffer. For example, you could leave the current contents and only modify certain values, or you could update only certain regions of the vertex buffer instead of the whole thing.
Each method will have its own usage and performance characteristics. It all depends on what your data is and how you intend on using it. This NVIDIA presentation gives some advice on the best way to update your buffers for different usages.
Yes, you will want to call this and IASetVertexBuffers before Draw() and Present() to see the updated results for the current frame. You don't necessarily need to update the vertex buffer contents before calling IASetVertexBuffers. Those can be in either order.

(DirectX 11) Dynamic Vertex/Index Buffers implementation with constant scene content changes

Been delving into un-managed DirectX 11 for the first time (bear with me) and there's an issue that, although asked several times over the forums still leaves me with questions.
I am developing as app in which objects are added to the scene over time. On each render loop I want to collect all vertices in the scene and render them reusing a single vertex and index buffer for performance and best practice. My question is regarding the usage of dynamic vertex and index buffers. I haven't been able to fully understand their correct usage when scene content changes.
vertexBufferDescription.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertexBufferDescription.MiscFlags = 0;
vertexBufferDescription.StructureByteStride = 0;
Should I create the buffers when the scene is initialized and somehow update their content in every frame? If so, what ByteSize should I set in the buffer description? And what do I initialize it with?
Or, should I create it the first time the scene is rendered (frame 1) using the current vertex count as its size? If so, when I add another object to the scene, don't I need to recreate the buffer and changing the buffer description's ByteWidth to the new vertex count? If my scene keeps updating its vertices on each frame, the usage of a single dynamic buffer would loose its purpose this way...
I've been testing initializing the buffer on the first time the scene is rendered, and from there on, using Map/Unmap on each frame. I start by filling in a vector list with all the scene objects and then update the resource like so:
void Scene::Render()
{
(...)
std::vector<VERTEX> totalVertices;
std::vector<int> totalIndices;
int totalVertexCount = 0;
int totalIndexCount = 0;
for (shapeIterator = models.begin(); shapeIterator != models.end(); ++shapeIterator)
{
Model* currentModel = (*shapeIterator);
// totalVertices gets filled here...
}
// At this point totalVertices and totalIndices have all scene data
if (isVertexBufferSet)
{
// This is where it copies the new vertices to the buffer.
// but it's causing flickering in the entire screen...
D3D11_MAPPED_SUBRESOURCE resource;
context->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));
context->Unmap(vertexBuffer, 0);
}
else
{
// This is run in the first frame. But what if new vertices are added to the scene?
vertexBufferDescription.ByteWidth = sizeof(VERTEX) * totalVertexCount;
UINT stride = sizeof(VERTEX);
UINT offset = 0;
D3D11_SUBRESOURCE_DATA resourceData;
ZeroMemory(&resourceData, sizeof(resourceData));
resourceData.pSysMem = &totalVertices[0];
device->CreateBuffer(&vertexBufferDescription, &resourceData, &vertexBuffer);
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
isVertexBufferSet = true;
}
In the end of the render loop, while keeping track of the buffer position of the vertices for each object, I finally invoke Draw():
context->Draw(objectVertexCount, currentVertexOffset);
}
My current implementation is causing my whole scene to flicker. But no memory leaks. Wonder if it has anything to do with the way I am using the Map/Unmap API?
Also, in this scenario, when would it be ideal to invoke buffer->Release()?
Tips or code sample would be great! Thanks in advance!
At the memcpy into the vertex buffer you do the following:
memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));
sizeof( totalVertices ) is just asking for the size of a std::vector< VERTEX > which is not what you want.
Try the following code:
memcpy(resource.pData, &totalVertices[0], sizeof( VERTEX ) * totalVertices.size() );
Also you don't appear to calling IASetVertexBuffers when isVertexBufferSet is true. Make sure you do so.