> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Map

> 获取指向资源中指定子资源的 CPU 指针，但可能不会向应用程序公开该指针值。Map 还会使 CPU 缓存失效。

获取指向资源中指定子资源的 CPU 指针，但可能不会向应用程序公开该指针值。**Map** 还会在必要时使 CPU 缓存失效，以便 CPU 对该地址的读取能够反映 GPU 所做的任何修改。

## 语法

```cpp theme={null}
HRESULT Map(
    UINT Subresource,
    const D3D12_RANGE  pReadRange,
    void  ppData
)
```

### 参数

*Subresource*<br />类型：UINT

指定子资源的索引编号。

*pReadRange \[in, optional]*<br />类型：const D3D12\_RANGE \*

指向 [D3D12\_RANGE](/reference/graphics/d3d12/structs/d3d12_range_public) 结构的指针，该结构描述要访问的内存范围。

这表示 CPU 可能读取的区域，坐标相对于子资源。空指针表示 CPU 可能会读取整个子资源。通过传递 **End** 小于或等于 **Begin** 的范围来指定 CPU 不会读取任何数据是有效的。

*ppData \[out, optional]*<br />类型：void \*\*

指向一个内存块的指针，该内存块接收指向资源数据的指针。

空指针也是有效的，可用于缓存 CPU 虚拟地址范围，供 [WriteToSubresource](/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_writetosubresource_public) 等方法使用。当 <i>ppData</i> 不为 NULL 时，返回的指针永远不会因 <i>pReadRange</i> 中的任何值而发生偏移。

### 返回值

类型：HRESULT

此方法返回 [Direct3D 12 返回代码](https://learn.microsoft.com/en-us/windows/desktop/direct3d12/d3d12-graphics-reference-returnvalues)之一。

## 备注

**Map** 和 [Unmap](/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_unmap_public) 可由多个线程安全地调用。支持嵌套的 **Map** 调用，并使用引用计数。首次调用 **Map** 时会为该资源分配一个 CPU 虚拟地址范围。最后一次调用 **Unmap** 时会释放该 CPU 虚拟地址范围。CPU 虚拟地址通常会返回给应用程序；但操纵具有未知布局的纹理内容将不允许公开该 CPU 虚拟地址。有关详细信息，请参阅 [WriteToSubresource](/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_writetosubresource_public)。除非 **Map** 一直保持嵌套状态，否则应用程序不能依赖该地址的一致性。

**Map** 返回的指针不保证具有普通指针的所有功能，但大多数应用程序在正常使用中不会察觉到差异。例如，具有 WRITE\_COMBINE 行为的指针相比 WRITE\_BACK 行为具有较弱的 CPU 内存排序保证。由于 PCIe 的限制，CPU 和 GPU 都可访问的内存不保证与 CPU 具有相同的原子内存保证。请使用围栏进行同步。

**Map** 有两类使用模型：简单和高级。简单使用模型可以最大化工具的性能，因此建议应用程序坚持使用简单模型，除非应用程序确定确实需要高级模型。

<h3><a id="Simple_Usage_Models" /><a id="simple_usage_models" /><a id="SIMPLE_USAGE_MODELS" />简单使用模型</h3> 应用程序应坚持使用 UPLOAD、DEFAULT 和 READBACK 这些堆类型抽象，以便合理地支持所有适配器架构。

应用程序应避免对 UPLOAD 堆上的资源指针进行 CPU 读取，甚至是意外读取。CPU 读取虽然可以工作，但在许多常见的 GPU 架构上速度慢得令人无法接受，因此需要考虑以下事项：

<ul>
  <li>
    不要让 CPU 从与 D3D12\_HEAP\_TYPE\_UPLOAD 或具有 D3D12\_CPU\_PAGE\_PROPERTY\_WRITE\_COMBINE 的堆关联的资源进行读取。
  </li>

  <li>
    **pData** 指向的内存区域可能以 [PAGE\_WRITECOMBINE](https://learn.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants) 分配，你的应用必须遵守与此类内存关联的所有限制。
  </li>

  <li>
    即使是下面的 C++ 代码也可以从内存中读取并触发性能损失，因为该代码可以展开为以下 x86 汇编代码。

    C++ 代码：

    ```
    *((int*)MappedResource.pData) = 0;
    ```

    x86 汇编代码：

    ```
    AND DWORD PTR [EAX],0
    ```
  </li>

  <li>
    使用合适的优化设置和语言结构以避免这种性能损失。例如，可以使用 **volatile** 指针，或针对代码速度而非代码大小进行优化，从而避免异或优化。
  </li>
</ul>

在 CPU 不修改资源时，鼓励应用程序保持资源处于未映射状态，并始终使用紧凑、精确的范围。这可以使工具（如[图形调试](https://learn.microsoft.com/en-us/visualstudio/debugger/visual-studio-graphics-diagnostics)和调试层）以最快的模式运行。此类工具需要跟踪 GPU 可能读取的所有 CPU 内存修改。

<h3><a id="Advanced_Usage_Models" /><a id="advanced_usage_models" /><a id="ADVANCED_USAGE_MODELS" />高级使用模型</h3> CPU 可访问堆上的资源可以持久映射，也就是说 **Map** 可以在资源创建后立即调用一次。永远不需要调用 [Unmap](/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_unmap_public)，但在最后一次引用该资源被释放后，不得再使用从 **Map** 返回的地址。使用持久映射时，应用程序必须确保 CPU 在 GPU 执行读取或写入该内存的命令列表之前已完成向内存写入数据。在常见场景中，应用程序只需在调用 [ExecuteCommandLists](/reference/graphics/d3d12_x/interfaces/id3d12commandqueue/methods/id3d12commandqueue_executecommandlists) 之前写入内存；但使用围栏来延迟命令列表执行同样有效。

所有 CPU 可访问内存类型都支持持久映射用法，即资源已映射但从未取消映射，前提是应用程序在资源被销毁后不再访问该指针。

#### 示例

[D3D12Bundles](https://learn.microsoft.com/en-us/windows/desktop/direct3d12/working-samples) 示例按如下方式使用 **ID3D12Resource::Map**：

将三角形数据复制到顶点缓冲区。

```cpp theme={null}
// 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);
```

为常量缓冲区创建上传堆。

```cpp theme={null}
// 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 参考中的示例代码](https://learn.microsoft.com/en-us/windows/desktop/direct3d12/notes-on-example-code)。

<div class="code" />

## 要求

**头文件：** d3d12\_xs.h 或 d3d12\_x.h<br />**库：** d3d12\_xs.lib 或 d3d12\_x.lib<br />**支持的平台**：XBOX Series 主机和 XBOX One 系列

## 另请参阅

[ID3D12Resource](/reference/graphics/d3d12_xs/interfaces/ID3D12Resource/id3d12resource_xs)

[子资源](https://learn.microsoft.com/en-us/windows/desktop/direct3d12/subresources)

[Unmap](/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_unmap_public)


## Related topics

- [XMemMapPhysicalPages](/zh-CN/reference/system/xmem/functions/xmemmapphysicalpages.md)
- [ApuMapApuAddress](/zh-CN/reference/audio/apu/functions/apumapapuaddress.md)
- [ApuMapVirtualAddress](/zh-CN/reference/audio/apu/functions/apumapvirtualaddress.md)
- [XMemMapPhysicalPagesScatter](/zh-CN/reference/system/xmem/functions/xmemmapphysicalpagesscatter.md)
- [CopyTileMappings](/zh-CN/reference/graphics/d3d12/interfaces/id3d12commandqueue/methods/id3d12commandqueue_copytilemappings_public.md)
