获取指向资源中指定子资源的 CPU 指针,但可能不会向应用程序披露指针值。 映射 还在必要时使 CPU 缓存失效,以便 CPU 读取到此地址反映 GPU 所做的任何修改。
Syntax
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 返回代码之一。
注解
映射和取消映射可以安全地由多个线程调用。 支持嵌套 映射 调用并进行 ref 计数。 对 Map 的第一次调用为资源分配 CPU 虚拟地址范围。 对 Unmap 的最后一次调用会解除分配 CPU 虚拟地址范围。 CPU 虚拟地址通常返回到应用程序;但是,使用未知布局作纹理的内容排除了泄露 CPU 虚拟地址。 有关更多详细信息 ,请参阅 WriteToSubresource 。 除非 Map 持久嵌套,否则应用程序不能依赖地址保持一致。
不保证 Map 返回的指针具有普通指针的所有功能,但大多数应用程序不会注意到正常使用的差异。 例如,具有WRITE_COMBINE行为的指针的 CPU 内存排序保证比WRITE_BACK行为弱。 CPU 和 GPU 可访问的内存不能保证共享 CPU 具有的相同原子内存,因为 PCIe 限制。 使用围栏进行同步。
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 可访问堆上的资源可以永久映射,这意味着可以在创建资源后立即调用 映射 一次。 不需要调用 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 参考中的示例代码。
要求
| Requirement | 价值 |
|---|---|
| 目标平台 | Windows操作系统 |
| Header | d3d12.h |
| Library | D3D12.lib |
| DLL | D3D12.dll |