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.
Related
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);
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);
I am performing view frustum culling and generating draw commands on the GPU in a compute shader and I want to pass the bounding volumes in a SSBO. Currently I am using just a large uniform array but I want to go bigger thus the need to move to a SSBO.
The thing I want to accomplish is something a kin to the AZDO approach of using triple buffering in order to avoid sync issues when updating the SSBO by only updating one third of the buffer while guarding the rest with fences.
Is this possible to combine with the compute shader dispatch or should I just create three different SSBOs and then bind each of them accordingly?
The solution as I currently see it would be to somehow tell the following drawcall to only fetch data in the SSBO from a certain offset (0 * buffer_size, 1 * buffer_size, etc). Is this even possible?
Render loop
/* Fence creation omitted for clarity */
// Cycle round updating different parts of the buffer
const uint32_t buffer_idx = (frame % gl_state.bvb_num_partitions);
uint8_t* ptr = (uint8_t*)gl_state.bvbp + buffer_idx * gl_state.bvb_buffer_size;
std::memcpy(ptr, bounding_volumes.data(), gl_state.bvb_buffer_size);
const uint32_t gl_bv_binding_point = 3; // Shader hard coded
const uint32_t offset = buffer_idx * gl_state.bvb_buffer_size;
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, gl_bv_binding_point, gl_state.bvb, offset, gl_state.bvb_buffer_size);
// OLD WAY: glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres"), NUM_OBJECTS, &bounding_volumes[0].pos.x);
glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "frustum_planes"), 6, glm::value_ptr(frustum[0]));
glDispatchCompute(NUM_OBJECTS, 1, 1);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT); // Buffer objects affected by this bit are derived from the GL_DRAW_INDIRECT_BUFFER binding.
Bounding volume SSBO creation
// Bounding volume buffer
glGenBuffers(1, &gl_state.bvb);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, gl_state.bvb);
gl_state.bvb_buffer_size = NUM_OBJECTS * sizeof(BoundingVolume);
gl_state.bvb_num_partitions = 3; // 1 for application, 1 for OpenGL driver, 1 for GPU
GLbitfield flags = GL_MAP_COHERENT_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
glBufferStorage(GL_SHADER_STORAGE_BUFFER, gl_state.bvb_num_partitions * gl_state.bvb_buffer_size, nullptr, flags);
gl_state.bvbp = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, gl_state.bvb_buffer_size * gl_state.bvb_num_partitions, flags);
As I understand VAOs/VBOs currently, a VAO retains all the attribute information that has been set up since it was bound, eg. the offset, stride, number of components, etc. of a given vertex attribute within a VBO.
What I seem to be unclear on is how VAOs and VBOs work together. A lot of the examples I have seen specify the vertex attributes with respect to the currently bound VBO, and when the VAO is bound the data in the VBO become accessible. One way I can see of using VAOs in this way would be to have one per object (where each object uses its own VBO), but I've read that this is poor performance-wise because of switching between many VAOs unnecessarily. I also would rather like to avoid having to store all my object data in one monolithic VBO because I will need to add and remove objects within my scene at any time - as a 3D editor, I feel the application would be much better suited to having each geometry object own its own buffer, rather than in some large, preallocated VBO. (Is this a correct assumption?)
My question therefore is whether one VAO can store vertex attribute configurations independently of the VBOs? Would I be able to configure a VAO to expect data in a certain format (eg. position, normal, UV) and then "swap in" different VBOs as I draw the different geometry objects, or is the format information essentially bound only to the VBO itself? If the latter, is it worth me using VAOs at all?
ARB_vertex_attrib_binding allows you to separate Vao attribute format and buffer binding.
https://www.opengl.org/wiki/Vertex_Specification#Separate_attribute_format
Internally, when you configure your Vao, Vertex buffer is automatically associated with attribute index. With ARB_vertex_attrib_binding, you have new gl functions to define Attribute formats independently from the bound buffer, which may be switched with VertexBuffer functions.
Here some piece of code in c# with openTK: (full surce: https://github.com/jpbruyere/GGL/tree/ottd/Tetra )
The solution here is to build a VAO with all your meshes concatenated, keeping for each of them only
BaseVertex = the vertice offset in the VAO
IndicesOffset = the offset in the Element buffer (ebo index)
IndicesCount = and the total indice count of the model
protected void CreateVAOs()
{
//normal vao binding
vaoHandle = GL.GenVertexArray();
GL.BindVertexArray(vaoHandle);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
... other attrib bindings come here
//ARB vertex attrib binding use for fast instance buffers switching
//note that I use 4 attrib indices to bind a matrix
GL.VertexBindingDivisor (instanceBufferIndex, 1);
for (int i = 0; i < 4; i++) {
GL.EnableVertexAttribArray (instanceBufferIndex + i);
GL.VertexAttribBinding (instanceBufferIndex+i, instanceBufferIndex);
GL.VertexAttribFormat(instanceBufferIndex+i, 4, VertexAttribType.Float, false, Vector4.SizeInBytes * i);
}
if (indices != null)
GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
GL.BindVertexArray(0);
}
Then, I define Instances of mesh with just a Matrix array for each, that's a normal buffer creation, but not staticaly bound to the vao.
instancesVboId = GL.GenBuffer ();
GL.BindBuffer (BufferTarget.ArrayBuffer, instancesVboId);
GL.BufferData<Matrix4> (BufferTarget.ArrayBuffer,
new IntPtr (modelMats.Length * Vector4.SizeInBytes * 4),
modelMats, BufferUsageHint.DynamicDraw);
GL.BindBuffer (BufferTarget.ArrayBuffer, 0);
To render such vao, I loop inside my instance array:
public void Bind(){
GL.BindVertexArray(vaoHandle);
}
public void Render(PrimitiveType _primitiveType){
foreach (VAOItem item in Meshes) {
GL.ActiveTexture (TextureUnit.Texture1);
GL.BindTexture (TextureTarget.Texture2D, item.NormalMapTexture);
GL.ActiveTexture (TextureUnit.Texture0);
GL.BindTexture (TextureTarget.Texture2D, item.DiffuseTexture);
//Here I bind the Instance buffer with my matrices
//that's a fast switch without changing vao confing
GL.BindVertexBuffer (instanceBufferIndex, item.instancesVboId, IntPtr.Zero,Vector4.SizeInBytes * 4);
//here I draw instanced with base vertex
GL.DrawElementsInstancedBaseVertex(_primitiveType, item.IndicesCount,
DrawElementsType.UnsignedShort, new IntPtr(item.IndicesOffset*sizeof(ushort)),
item.modelMats.Length, item.BaseVertex);
}
}
The final VAO is bound only once.
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.