Search code examples
c++directxbufferindicesvertices

DirectX 11: Use UpdateSubresource to update Vertex and Index buffers


in my sientific simulation I have got huge data sets (around 600000 vertices) to update in regular time intervals (around 1sec).

For the first data set I create a buffer like follows:

mVertexStride = sizeof(VertexType);

D3D11_BUFFER_DESC VertexBufferDesc;
ZeroMemory(&VertexBufferDesc, sizeof(VertexBufferDesc));
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.ByteWidth = sizeof(VertexType) * numOfVertices;
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; //use as a vertex buffer
VertexBufferDesc.CPUAccessFlags = 0; 
VertexBufferDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA InitialSubData;
ZeroMemory(&InitialSubData, sizeof(InitialSubData));
InitialSubData.pSysMem = vertices;

HRESULT hr = device->CreateBuffer(&VertexBufferDesc, &InitialSubData, &mVertexBuffer);
if (FAILED(hr)) { return false; }
return true;

I'm using similar calls to create an index buffer.

Then after 1 sec I wanna update the entire data set. So I wanna kinda swap the whole vertex and index buffer. The old vertices and indices are discarded while the new ones are supposed to be written to the buffers.

That point gives rise to the actual question. My code looks like this right now:

deviceContext->UpdateSubresource(mVertexBuffer, 0, NULL, vertices, 0, 0);

And for the index buffer

deviceContext->UpdateSubresource(mIndexBuffer, 0, NULL, indices, 0, 0);

That code works (most of the time) but the problem is that the size of the buffer does not expand automatically.

For example first I have a data set with 650000 vertices and then I have one with 700000 vertices. The second set will be filled into the buffer but only shows 650000 vertices. There are visible holes. How do I cope with that? Could not find anything on the web or in the Microsoft help.

Should I use map/unmap even if I'm not updating every frame?

Any help is appreciated!

Edit:

In my case UpdateSubresource() seems the wrong approach. What I am doing now is deleting the old buffer and creating a new one. The simulation still performs well, the "swapping" is done in milliseconds. My code looks like follows:

if (mVertexBuffer != NULL)
{
    mVertexBuffer->Release();
    mVertexBuffer = NULL;
}

mVertexStride = sizeof(VertexType);

D3D11_BUFFER_DESC VertexBufferDesc;
ZeroMemory(&VertexBufferDesc, sizeof(VertexBufferDesc));
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.ByteWidth = sizeof(VertexType) * numOfVertices;
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; //use as a vertex buffer
VertexBufferDesc.CPUAccessFlags = 0; //D3D11_CPU_ACCESS_WRITE; //allow CPU to write in buffer
VertexBufferDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA InitialSubData;
ZeroMemory(&InitialSubData, sizeof(InitialSubData));
InitialSubData.pSysMem = vertices;

HRESULT hr = device->CreateBuffer(&VertexBufferDesc, &InitialSubData, &mVertexBuffer); // 1a) create input buffer
if (FAILED(hr)) { return false; }
return true;

Any other suggestions?


Solution

  • VertexBufferDesc.ByteWidth defines the size of the resource, and after creation, there's no way to expand it as there is with e.g. std::vector. If there's a known upper limit on the size of this buffer, you can simply set ByteWidth to the maximum size you'll need. If the size varies widely, or is usually small but sometimes much larger, you can use some kind of hysteresis to decide when to create a new vertex buffer. For example, if NewByteWidth > CurrentByteWidth then you can create a buffer that's twice as large, or if NewByteWidth <= CurrentByteWidth / 4 then you could save some memory by recreating it as half as large.