【问题标题】:DirectX 11: Use UpdateSubresource to update Vertex and Index buffersDirectX 11:使用 UpdateSubresource 更新顶点和索引缓冲区
【发布时间】:2015-10-15 21:37:27
【问题描述】:

在我的科学模拟中,我有大量数据集(大约 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() 似乎是错误的方法。我现在正在做的是删除旧缓冲区并创建一个新缓冲区。模拟仍然表现良好,“交换”在几毫秒内完成。我的代码如下所示:

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;

还有其他建议吗?

【问题讨论】:

    标签: c++ directx buffer indices vertices


    【解决方案1】:

    VertexBufferDesc.ByteWidth 定义资源的大小,创建后,无法像例如std::vector。如果这个缓冲区的大小有一个已知的上限,您可以简单地将ByteWidth 设置为您需要的最大大小。如果大小变化很大,或者通常很小但有时大得多,则可以使用某种滞后来决定何时创建新的顶点缓冲区。例如,如果NewByteWidth > CurrentByteWidth,那么您可以创建一个两倍大的缓冲区,或者如果NewByteWidth <= CurrentByteWidth / 4,那么您可以通过重新创建一半大小来节省一些内存。

    【讨论】:

    • @MPQ 看来我每次都要创建一个新缓冲区 - 不一定。如果您的数据大小范围从例如500K 顶点到 800K 顶点,只需创建一次缓冲区,并为 800K 顶点提供足够的空间。只有在 95% 的时间您将使用少于 10K 的顶点,但在 5% 的时间您将使用 1M+ 顶点时,您才需要考虑重新创建它。
    • 感谢您的建议。我尝试了这种方法,只是将 ByteWidth 设置为 1M。问题是,我有 200 多个流体数据集,它们的顶点数变化很大。有时我从一个有 200000 个顶点的流体对象开始,然后下一个对象有大约 500000 个。所以我很难预测哪个数据集将是最大的。此外,我认为创建新缓冲区的性能并不比更新现有缓冲区差多少。
    【解决方案2】:

    感谢您的回复!这说明了很多。

    似乎每次更新实体时我都必须创建一个新缓冲区。希望这不会花费太多的性能。我会尝试稍后回复。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-23
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      相关资源
      最近更新 更多