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 返回代码之一。

注解

MapUnmap 可由多个线程安全地调用。 支持嵌套 映射 调用,并且会进行引用计数。 首次调用 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 不会修改资源时保持未映射状态,并随时使用严格、准确的范围。 这可实现工具(如 图形调试 和调试层)的最快模式。 此类工具需要跟踪 GPU 可以读取的内存的所有 CPU 修改。

高级使用模型

可以永久映射 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

另请参阅

ID3D12Resource

子资源

Unmap