ID3D12Resource::Map 方法 (d3d12.h)

获取指向资源中指定子资源的 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 不会修改它们,并随时使用严格、准确的范围。 这为工具(如 图形调试 和调试层)启用最快的模式。 这些工具需要跟踪 GPU 可以读取的内存的所有 CPU 修改。

高级使用模型

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

另请参阅

ID3D12Resource

子资源

取消映射