我有一个顶点缓冲区,它的某些部分需要每帧更新一次,因此我使用D3D11_USAGE_DYNAMIC
将其创建为D3D11_CPU_ACCESS_WRITE
。
由于有很多顶点(大约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
资源被映射用于写入;以前的资源内容将是未定义的。
D3D11_MAP_WRITE_NO_OVERWRITE
资源被映射用于写入;资源的现有内容不能被覆盖(请参阅备注)。
但是由于我映射了资源,不应该将整个缓冲区从VRAM复制到系统RAM,然后,当我取消映射它时,返回VRAM?
答案 0 :(得分:1)
经过一番思考后,我想我找到了答案,有人可以证实这一点吗?
使用D3D11_USAGE_DYNAMIC
和D3D11_CPU_ACCESS_WRITE
时,CPU只能进行写入访问(确定,非常清楚)。然后,在每次调用ID3D11DeviceContext::Map
时,临时缓冲区(使用_aligned_malloc
创建的东西),状态未定义。
然后,当使用D3D11_MAP_WRITE_DISCARD
时,前一个顶点缓冲区被丢弃,这意味着只保留更改的部分,因为它们存在于该临时缓冲区中。
另一方面,在使用D3D11_MAP_WRITE_NO_OVERWRITE
时,保留前一个顶点缓冲区,只写入更改的部分。