ID3D12Resource::Map 方法 (d3d12.h)
获取指向资源中指定子资源的 CPU 指针,但可能不会向应用程序公开指针值。 映射 还会在必要时使 CPU 缓存失效,以便 CPU 读取到此地址时反映 GPU 所做的任何修改。
语法
HRESULT Map(
UINT Subresource,
[in, optional] const D3D12_RANGE *pReadRange,
[out, optional] void **ppData
);
参数
Subresource
类型: UINT
指定子资源的索引号。
[in, optional] pReadRange
类型: const D3D12_RANGE*
指向描述要访问的内存范围的 D3D12_RANGE 结构的指针。
这表示 CPU 可能读取的区域,并且坐标是子资源相对的。 null 指针指示 CPU 可能读取整个子资源。 通过传递 End 小于或等于 Begin 的范围,指定 CPU 不会读取任何数据是有效的。
[out, optional] ppData
类型: void**
指向内存块的指针,该内存块接收指向资源数据的指针。
null 指针有效,可用于缓存 WriteToSubresource 等方法的 CPU 虚拟地址范围。 当 ppData 不为 NULL 时,返回的指针永远不会被 pReadRange 中的任何值偏移。
返回值
类型: HRESULT
此方法返回 Direct3D 12 返回代码之一。
注解
Map 和 Unmap 可由多个线程安全地调用。 支持嵌套 映射 调用,并且会进行引用计数。 首次调用 Map 可为资源分配 CPU 虚拟地址范围。 最后一次调用 Unmap 可取消分配 CPU 虚拟地址范围。 CPU 虚拟地址通常返回到应用程序;但是,使用未知布局操作纹理的内容会阻止泄露 CPU 虚拟地址。 有关更多详细信息,请参阅 WriteToSubresource 。 除非 Map 是永久嵌套的,否则应用程序不能依赖于地址保持一致。
Map 返回的指针不保证具有普通指针的所有功能,但大多数应用程序不会注意到正常用法的差异。 例如,与WRITE_BACK行为相比,具有WRITE_COMBINE行为的指针具有较弱的 CPU 内存排序保证。 由于 PCIe 限制,不保证 CPU 和 GPU 均可访问的内存共享 CPU 具有的相同原子内存保证。 使用围栏进行同步。
Map 有两种使用模型类别:简单和高级。 简单使用模型可最大程度地提高工具性能,因此建议应用程序坚持使用简单模型,直到应用需要高级模型。
简单使用模型
应用程序应坚持使用 UPLOAD、DEFAULT 和 READBACK 的堆类型抽象,以便合理地支持所有适配器体系结构。应用程序应避免从指向 UPLOAD 堆上的资源的指针进行 CPU 读取,即使是意外的。 CPU 读取将正常工作,但在许多常见的 GPU 体系结构上速度非常缓慢,因此请考虑以下事项:
- 不要从与D3D12_HEAP_TYPE_UPLOAD或具有D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE的堆关联的资源读取 CPU。
- 可以使用PAGE_WRITECOMBINE分配 pData 点的内存区域,你的应用必须遵守与此类内存关联的所有限制。
-
即使以下 C++ 代码也可以从内存中读取并触发性能损失,因为该代码可能会扩展到以下 x86 程序集代码。
C++ 代码:
*((int*)MappedResource.pData) = 0;
x86 程序集代码:
AND DWORD PTR [EAX],0
- 使用适当的优化设置和语言构造来帮助避免这种性能损失。 例如,可以通过使用 可变 指针或通过优化代码速度而不是代码大小来避免 xor 优化。
高级使用模型
可以永久映射 CPU 可访问的堆上的资源,这意味着可以在创建资源后立即调用 Map 一次。 永远不需要调用 Unmap,但在释放对资源的最后一个引用后,不得再使用从 Map 返回的地址。 使用永久性映射时,应用程序必须确保 CPU 在 GPU 执行读取或写入内存的命令列表之前完成将数据写入内存。 在常见情况下,应用程序只需在调用 ExecuteCommandLists 之前写入内存;但使用围栏来延迟命令列表执行也有效。所有 CPU 可访问的内存类型都支持持久性映射使用,其中资源已映射,但之后永远不会取消映射,前提是应用程序在释放资源后无法访问指针。
示例
D3D12Bundles 示例使用 ID3D12Resource::Map,如下所示:
将三角形数据复制到顶点缓冲区。
// Copy the triangle data to the vertex buffer.
UINT8* pVertexDataBegin;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
m_vertexBuffer->Unmap(0, nullptr);
为常量缓冲区创建上传堆。
// Create an upload heap for the constant buffers.
ThrowIfFailed(pDevice->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(sizeof(ConstantBuffer) * m_cityRowCount * m_cityColumnCount),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_cbvUploadHeap)));
// Map the constant buffers. Note that unlike D3D11, the resource
// does not need to be unmapped for use by the GPU. In this sample,
// the resource stays 'permanently' mapped to avoid overhead with
// mapping/unmapping each frame.
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
ThrowIfFailed(m_cbvUploadHeap->Map(0, &readRange, reinterpret_cast<void**>(&m_pConstantBuffers)));
请参阅 D3D12 参考中的示例代码。
要求
要求 | 值 |
---|---|
目标平台 | Windows |
标头 | d3d12.h |
Library | D3D12.lib |
DLL | D3D12.dll |