DirectX 11:使用 UpdateSubresource 更新顶点和索引缓冲区
DirectX 11: Use UpdateSubresource to update Vertex and Index buffers
在我的科学模拟中,我有大量的数据集(大约 600000 个顶点)要定期更新(大约 1 秒)。
对于第一个数据集,我创建了一个缓冲区,如下所示:
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;
我正在使用类似的调用来创建索引缓冲区。
1 秒后我想更新整个数据集。所以我想有点交换整个顶点和索引缓冲区。旧的顶点和索引被丢弃,而新的顶点和索引应该被写入缓冲区。
这一点引发了实际问题。我的代码现在看起来像这样:
deviceContext->UpdateSubresource(mVertexBuffer, 0, NULL, vertices, 0, 0);
以及索引缓冲区
deviceContext->UpdateSubresource(mIndexBuffer, 0, NULL, indices, 0, 0);
该代码(大部分时间)有效,但问题是缓冲区的大小不会自动扩展。
例如,首先我有一个包含 650000 个顶点的数据集,然后我有一个包含 700000 个顶点的数据集。第二组将填充到缓冲区中,但仅显示 650000 个顶点。有可见孔。我该如何应对?在 Web 或 Microsoft 帮助中找不到任何内容。
我应该使用 map/unmap 即使我没有更新每一帧吗?
感谢任何帮助!
编辑:
在我的例子中,UpdateSubresource() 似乎是错误的方法。我现在正在做的是删除旧缓冲区并创建一个新缓冲区。模拟仍然表现良好,"swapping" 以毫秒为单位完成。我的代码如下所示:
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;
还有其他建议吗?
VertexBufferDesc.ByteWidth
定义了资源的大小,并且在创建之后,无法像使用 e.g. 那样扩展它。 std::vector
。如果此缓冲区的大小有已知的上限,您可以简单地将 ByteWidth
设置为您需要的最大大小。如果大小变化很大,或者通常很小但有时会大很多,您可以使用某种滞后来决定何时创建新的顶点缓冲区。例如,如果 NewByteWidth > CurrentByteWidth
那么您可以创建一个两倍大的缓冲区,或者如果 NewByteWidth <= CurrentByteWidth / 4
那么您可以通过重新创建一半大的缓冲区来节省一些内存。
感谢您的回复!这解释了很多。
看来我每次更新实体时都必须创建一个新缓冲区。希望这不会花费太多性能。我会尝试稍后回复。
在我的科学模拟中,我有大量的数据集(大约 600000 个顶点)要定期更新(大约 1 秒)。
对于第一个数据集,我创建了一个缓冲区,如下所示:
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;
我正在使用类似的调用来创建索引缓冲区。
1 秒后我想更新整个数据集。所以我想有点交换整个顶点和索引缓冲区。旧的顶点和索引被丢弃,而新的顶点和索引应该被写入缓冲区。
这一点引发了实际问题。我的代码现在看起来像这样:
deviceContext->UpdateSubresource(mVertexBuffer, 0, NULL, vertices, 0, 0);
以及索引缓冲区
deviceContext->UpdateSubresource(mIndexBuffer, 0, NULL, indices, 0, 0);
该代码(大部分时间)有效,但问题是缓冲区的大小不会自动扩展。
例如,首先我有一个包含 650000 个顶点的数据集,然后我有一个包含 700000 个顶点的数据集。第二组将填充到缓冲区中,但仅显示 650000 个顶点。有可见孔。我该如何应对?在 Web 或 Microsoft 帮助中找不到任何内容。
我应该使用 map/unmap 即使我没有更新每一帧吗?
感谢任何帮助!
编辑:
在我的例子中,UpdateSubresource() 似乎是错误的方法。我现在正在做的是删除旧缓冲区并创建一个新缓冲区。模拟仍然表现良好,"swapping" 以毫秒为单位完成。我的代码如下所示:
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;
还有其他建议吗?
VertexBufferDesc.ByteWidth
定义了资源的大小,并且在创建之后,无法像使用 e.g. 那样扩展它。 std::vector
。如果此缓冲区的大小有已知的上限,您可以简单地将 ByteWidth
设置为您需要的最大大小。如果大小变化很大,或者通常很小但有时会大很多,您可以使用某种滞后来决定何时创建新的顶点缓冲区。例如,如果 NewByteWidth > CurrentByteWidth
那么您可以创建一个两倍大的缓冲区,或者如果 NewByteWidth <= CurrentByteWidth / 4
那么您可以通过重新创建一半大的缓冲区来节省一些内存。
感谢您的回复!这解释了很多。
看来我每次更新实体时都必须创建一个新缓冲区。希望这不会花费太多性能。我会尝试稍后回复。