Передача данных текстуры через буферы

Отправка данных текстуры 2D или трехмерной текстуры аналогична отправке 1D-данных, за исключением того, что приложениям необходимо обратить пристальное внимание на выравнивание данных, связанных с шагом строки. Буферы можно использовать ортогонально и одновременно из нескольких частей графического конвейера и очень гибки.

Отправка данных текстуры с помощью буферов

Приложения должны передавать данные через ID3D12GraphicsCommandList::CopyTextureRegion или ID3D12GraphicsCommandList::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_PROPERTIES и CD3DX12_TEXTURE_COPY_LOCATION, а также методов CreateCommittedResource и CopyTextureRegion.

Копирование

Методы D3D12 позволяют приложениям заменить D3D11 UpdateSubresource, CopySubresourceRegion и исходные данные ресурсов. Один трехмерный подресурс данных текстуры с порядком хранения "строка-основная" может находиться в буферных ресурсах. CopyTextureRegion может копировать данные текстуры из буфера в ресурс текстуры с неизвестным макетом текстуры и наоборот. Приложения должны предпочитать этот метод для заполнения часто используемых ресурсов GPU путем создания больших буферов в куче UPLOAD, создавая часто используемые ресурсы GPU в куче DEFAULT, которая не обеспечена доступом ЦП. Такой метод эффективно поддерживает дискретные графические процессоры и их большие объемы недоступной памяти ЦП без обычного нарушения архитектуры UMA.

Обратите внимание на следующие две константы:

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

Шаг строки каждого подресурса должен быть выровнен по кратным D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256), а начальное смещение каждого подресурса должно быть выровнено по кратным D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512), если D3D12_FEATURE_DATA_D3D12_OPTIONS13::UnrestrictedBufferTextureCopyPitchSupported не равно TRUE.

В случаях, когда шаг строки меньше D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256), что характерно для самых маленьких мип-уровней текстуры, вероятно, что выравнивание по смещению подресурса D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512) добавит дополнительное заполнение между подресурсами сверх заполнения, добавляемого выравниванием шага строки.

Сопоставление и отмена сопоставления

Отображение и Разотображение можно безопасно вызывать несколькими потоками. Первый вызов map выделяет диапазон виртуальных адресов ЦП для ресурса. Последний вызов unmap освобождает диапазон виртуальных адресов центрального процессора. Виртуальный адрес ЦП обычно возвращается приложению.

Всякий раз, когда данные передаются между ЦП и GPU через ресурсы в кучах обратного чтения, Map и Unmap должны использоваться для поддержки всех систем D3D12. Поддержание диапазонов на как можно более узком уровне повышает эффективность для систем, требующих диапазонов (см. D3D12_RANGE).

Производительность средств отладки повышается не только благодаря точному использованию диапазонов во всех вызовах Map / Unmap, но также благодаря приложениям, размаплирующим ресурсы, когда изменения процессора больше не требуются.

Метод D3D11 с использованием Map (с параметром DISCARD) для переименования ресурсов не поддерживается в D3D12. Приложения должны реализовать переименование ресурсов. Все вызовы Map неявно NO_OVERWRITE и многопоточные. Это ответственность приложения, чтобы убедиться, что любая соответствующая работа GPU, содержащаяся в списках команд, завершена перед доступом к данным с ЦП. Вызовы D3D12 к Map не сбрасывают буферы команд и не блокируют процесс ожидания завершения работы GPU. В результате функции Map и Unmap могут даже быть оптимизированы в некоторых сценариях.

Выравнивание буфера

Ограничения выравнивания буфера:

  • Линейное копирование подресурсов должно быть выровнено по D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512) байтов (с выравниванием шага строки по D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256) байтов).
  • Чтение константных данных должно быть кратным 256 байтам от начала области кучи (т. е. только из адресов с выравниванием по 256 байтам).
  • Данные индекса должны быть кратны размеру типа данных индекса (т. е. только из адресов, которые естественно выровнены для данного типа данных).
  • Данные ID3D12GraphicsCommandList::ExecuteIndirect должны быть из смещений, кратных 4 (т. е. только с адресов, которые выровнены по границе DWORD).