我有一个顶点缓冲区,其中的某些部分每帧只需更新一次,因此我使用 D3D11_CPU_ACCESS_WRITE
将其创建为 D3D11_USAGE_DYNAMIC
>.
由于有很多顶点(大约 150k),我不想迭代整个缓冲区,只想迭代标记为更新的部分。
为此,我使用 DirtyVertexBuffer
标志标记每个“区域”,然后跳过未标记的区域。为了更新缓冲区,我使用 D3D11_MAP_WRITE_NO_OVERWRITE
。代码是:
VertexType *vertices;
D3D11_MAPPED_SUBRESOURCE mappedResource;
Vertex *vertex;
HRESULT result;
result = context->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
if (FAILED(result))
return;
vertices = (DirectX::VertexPositionNormalTexture*)mappedResource.pData;
for (auto &material : materials) {
if ((material.dirty & Material::Dirty::VertexBuffer) == 0) continue;
material.dirty &= ~Material::Dirty::VertexBuffer;
// Update vertex data
}
// release the access to the buffer
context->Unmap(m_vertexBuffer, 0);
我的问题是:为什么这里需要 D3D_MAP_WRITE_NO_OVERWRITE
,而不是 D3D_MAP_WRITE_DISCARD
?
如果我使用后者,顶点缓冲区似乎被“归零”(仅渲染更改的区域)。 MSDN说:
D3D11_MAP_WRITE_DISCARD
Resource is mapped for writing; the previous contents of the resource will be undefined.
D3D11_MAP_WRITE_NO_OVERWRITE
Resource is mapped for writing; the existing contents of the resource cannot be overwritten (see Remarks).
但既然我映射了资源,难道不应该将整个缓冲区从 VRAM 复制到系统 RAM,然后当我取消映射时,返回到 VRAM 吗?
最佳答案
经过一番思考,我想我找到了答案,有人可以证实这一点吗?
当使用D3D11_USAGE_DYNAMIC
和D3D11_CPU_ACCESS_WRITE
时,CPU只能进行写入访问(好吧,这很清楚)。然后,在每次调用 ID3D11DeviceContext::Map
时,临时缓冲区(使用 _aligned_malloc
创建的东西),其状态未定义。
然后,当使用D3D11_MAP_WRITE_DISCARD
时,先前的顶点缓冲区将被丢弃,这意味着仅保留更改的部分,因为它们存在于该临时缓冲区中。
另一方面,在使用D3D11_MAP_WRITE_NO_OVERWRITE
时,将保留先前的顶点缓冲区,并且仅写入更改的部分。
关于c++ - DirectX11 D3D11_MAP 的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23368880/