透過緩衝區上傳紋理資料

上傳 2D 或 3D 紋理資料類似于上傳 1D 資料,不同之處在于應用程式需要更仔細注意與資料列間距相關的資料對齊。 緩衝區可以正交使用,也可以同時從圖形管線的多個部分使用,而且非常有彈性。

透過緩衝區上傳紋理資料

應用程式必須透過 ID3D12GraphicsCommandList::CopyTextureRegionID3D12GraphicsCommandList::CopyBufferRegion上傳資料。 紋理資料比其他資源資料更可能較大、重複存取,並受益于改善的非線性記憶體配置快取一致性。 在 D3D12 中使用緩衝區時,只要滿足記憶體對齊需求,應用程式就能夠完全控制與複製資源資料相關的資料放置和相片順序。

此範例會醒目提示應用程式只會將 2D 資料扁平化為 1D,再將其放在緩衝區中。 針對 mipmap 2D 案例,應用程式可以離散地扁平化每個子資源,並快速使用 1D 子配置演算法,或使用更複雜的 2D 子配置技術,將視訊記憶體使用率降到最低。 第一個技術應該更頻繁地使用,因為它比較簡單。 將資料封裝到磁片或透過網路時,第二個技術可能很有用。 不論是哪一種情況,應用程式都必須呼叫每個子資源的複製 API。

// Prepare a pBitmap in memory, with bitmapWidth, bitmapHeight, and pixel format of DXGI_FORMAT_B8G8R8A8_UNORM. 
//
// Sub-allocate from the buffer for texture data.
//

D3D12_SUBRESOURCE_FOOTPRINT pitchedDesc = { 0 };
pitchedDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
pitchedDesc.Width = bitmapWidth;
pitchedDesc.Height = bitmapHeight;
pitchedDesc.Depth = 1;
pitchedDesc.RowPitch = Align(bitmapWidth * sizeof(DWORD), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);

//
// Note that the helper function UpdateSubresource in D3DX12.h, and ID3D12Device::GetCopyableFootprints 
// can help applications fill out D3D12_SUBRESOURCE_FOOTPRINT and D3D12_PLACED_SUBRESOURCE_FOOTPRINT structures.
//
// Refer to the D3D12 Code example for the previous section "Uploading Different Types of Resources"
// for the code for SuballocateFromBuffer.
//

SuballocateFromBuffer(
    pitchedDesc.Height * pitchedDesc.RowPitch,
    D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT
    );

D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedTexture2D = { 0 };
placedTexture2D.Offset = m_pDataCur – m_pDataBegin;
placedTexture2D.Footprint = pitchedDesc;

//
// Copy texture data from DWORD* pBitmap->pixels to the buffer
//

for (UINT y = 0; y < bitmapHeight; y++)
{
  UINT8 *pScan = m_pDataBegin + placedTexture2D.Offset + y * pitchedDesc.RowPitch;
  memcpy( pScan, &(pBitmap->pixels[y * bitmapWidth]), sizeof(DWORD) * bitmapWidth );
}

//
// Create default texture2D resource.
//

D3D12_RESOURCE_DESC  textureDesc { ... };

CComPtr<ID3D12Resource> texture2D;
d3dDevice->CreateCommittedResource( 
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), 
        D3D12_HEAP_FLAG_NONE, &textureDesc, 
        D3D12_RESOURCE_STATE_COPY_DEST, 
        nullptr, 
        IID_PPV_ARGS(&texture2D) );

//
// Copy heap data to texture2D.
//

commandList->CopyTextureRegion( 
        &CD3DX12_TEXTURE_COPY_LOCATION( texture2D, 0 ), 
        0, 0, 0, 
        &CD3DX12_TEXTURE_COPY_LOCATION( m_spUploadHeap, placedTexture2D ), 
        nullptr );

請注意協助程式結構的用法 CD3DX12_HEAP_PROPERTIESCD3DX12_TEXTURE_COPY_LOCATION,以及 CreateCommittedResourceCopyTextureRegion方法。

複製

D3D12 方法可讓應用程式取代 D3D11 UpdateSubresourceCopySubresourceRegion和資源初始資料。 資料列主要紋理資料的單一 3D 子資源可能位於緩衝區資源中。 CopyTextureRegion 可以將該紋理資料從緩衝區複製到具有未知紋理配置的紋理資源,反之亦然。 應用程式應該偏好這種技術來填入經常存取的 GPU 資源,方法是在 UPLOAD 堆積中建立大型緩衝區,同時在沒有 CPU 存取的 DEFAULT 堆積中建立經常存取的 GPU 資源。 這類技術有效率地支援離散 GPU 及其大量 CPU 無法存取的記憶體,而不會影響 UMA 架構。

請注意下列兩個常數:

const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256;
const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512;

對應和取消對應

多個 執行緒可以安全地呼叫 Map 和 Unmap 。 對應的第一次呼叫 會配置資源的 CPU 虛擬位址範圍。 最後一次 呼叫 Unmap 會解除配置 CPU 虛擬位址範圍。 CPU 虛擬位址通常會傳回至應用程式。

每當透過讀取堆積中的資源在 CPU 和 GPU 之間傳遞資料時,都必須使用 MapUnmap 來支援所有系統 D3D12。 盡可能讓範圍保持緊密,在需要範圍 (參照D3D12_RANGE) 系統上,將效率最大化。

偵錯工具的效能不僅受益于所有Map / Unmap呼叫上的正確範圍使用方式,也會受益于不再進行 CPU 修改時取消對應資源的應用程式。

D3D12 不支援在 D3D12 中使用 Map (搭配 DISCARD 參數集) 重新命名資源的 D3D11 方法。 應用程式必須實作資源重新命名本身。 所有 Map 呼叫都會隱含地NO_OVERWRITE和多執行緒。 應用程式必須負責確保命令清單中所包含的任何相關 GPU 工作都已完成,再使用 CPU 存取資料。 對 Map 的 D3D12 呼叫不會隱含排清任何命令緩衝區,也不會封鎖等候 GPU 完成工作。 因此,在某些情況下, MapUnmap 甚至可能會優化。

緩衝區對齊

緩衝區對齊限制:

  • 線性子資源複製必須對齊 512 個位元組, (對齊對齊D3D12_TEXTURE_DATA_PITCH_ALIGNMENT位元組) 的資料列間距。
  • 常數資料讀取必須是堆積開頭的 256 個位元組的倍數 (,也就是只有 256 位元組對齊的位址) 。
  • 索引資料讀取必須是索引資料類型大小的倍數 (,亦即只有針對資料) 自然對齊的位址。
  • ID3D12GraphicsCommandList::ExecuteIndirect 資料必須來自 4 (倍數的位移,亦即只有 DWORD 對齊的位址) 。