取得 CPU 指標指向該資源中指定的子資源,但不得向應用程式揭露指標值。 Map 也會在必要時使 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 可能讀取的區域,座標是子資源相關的。 空指標表示 CPU 可能會讀取整個子資源。 透過傳遞一個範圍,讓 End 小於或等於 Begin 來指定 CPU 不會讀取任何資料是合理的。
[out, optional] ppData
類型: 無效**
指向記憶體區塊的指標,該區塊接收到資源資料的指標。
空指標有效且有助於快取 CPU 虛擬位址範圍,用於像 WriteToSubresource 這類方法。 當 ppData 非 NULL 時,回傳的指標不會被 pReadRange 中的任何值所偏移。
返回值
類型: HRESULT
此方法會回傳 Direct3D 12 回傳碼之一。
備註
Map 和Unmap 可以被多個執行緒安全地呼叫。 支援巢狀 地圖 呼叫並有參考資料。 第一次呼叫 Map 會為資源分配一個 CPU 虛擬位址範圍。 最後一次呼叫 Unmap 會釋放 CPU 虛擬位址範圍。 CPU 虛擬位址通常會回傳給應用程式;但若操作紋理內容且配置未知,則無法揭露 CPU 虛擬位址。 更多詳情請參見 WriteToSubresource 。 應用程式無法依賴位址一致性,除非 Map 持續巢狀。
Map 回傳的指標不保證具備一般指標的所有功能,但大多數應用程式不會察覺正常使用中的差異。 例如,具有WRITE_COMBINE行為的指標,CPU 記憶體排序的保證比WRITE_BACK行為弱。 由於 PCIe 限制,CPU 與 GPU 可存取的記憶體無法保證共享 CPU 所擁有的相同原子記憶體。 用圍欄來同步。
Map 有兩個使用模型類別,簡單型和進階型。 簡單使用模型能最大化工具效能,因此建議應用程式在應用程式證明進階模型為必需品前,先堅持使用簡單模型。
簡單使用模型
應用程式應遵循堆積類型的抽象,如上傳(UPLOAD)、預設(DEFAULT)和讀回(READBACK),以便合理地支援所有介面卡架構。應用程式應避免 CPU 從指標讀取 UPLOAD 堆積資源,即使不小心也行。 CPU 讀取雖然可行,但在許多常見 GPU 架構上速度過慢,請考慮以下幾點:
- 不要讓 CPU 從與堆積D3D12_HEAP_TYPE_UPLOAD或有 D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE 的資源中讀取。
- pData 點可分配到的記憶體區域PAGE_WRITECOMBINE,且你的應用程式必須遵守與該記憶體相關的所有限制。
-
甚至後續的 C++ 程式碼也可能從記憶體讀取,並因程式碼可擴展成 x86 組合語言而觸發效能損失。
C++ 程式碼:
*((int*)MappedResource.pData) = 0;x86 組合語言代碼:
AND DWORD PTR [EAX],0 - 使用適當的優化設定與語言結構,以避免此效能損失。 例如,你可以透過使用 揮發性 指標或優化程式碼速度而非程式碼大小來避免異或優化。
進階使用模型
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 參考文獻中的範例程式碼。
需求
| Requirement | 價值觀 |
|---|---|
| 目標平臺 | 窗戶 |
| Header | d3d12.h |
| Library | D3D12.lib |
| DLL | D3D12.dll |