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

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

Отправка данных текстуры через буферы

Приложения должны отправлять данные через ID3D12GraphicsCommandList::CopyTextureRegion или ID3D12GraphicsCommandList::CopyBufferRegion. Данные текстуры, скорее всего, будут большими, к их многократному обращению и воспользоваться улучшенной когерентностью кэша нелинейных макетов памяти, чем другие данные ресурсов. При использовании буферов в D3D12 приложения имеют полный контроль над размещением и упорядочением данных, связанными с копированием данных ресурсов, при условии, что требования к выравниванию памяти выполняются.

В примере показано, где приложение просто преобразует двухd-данные в 1D, прежде чем помещает их в буфер. В сценарии 2D mipmap приложение может либо дискретно преобразовать каждый подресурс в плоскую структуру и быстро использовать алгоритм подраспределения 1D, либо использовать более сложный метод выделения двухD-подраспределения, чтобы свести к минимуму использование видеопамяти. Ожидается, что первый метод будет использоваться чаще, так как он проще. Второй способ может быть полезен при упаковке данных на диск или по сети. В любом случае приложение должно по-прежнему вызывать 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, которая не имеет доступа к ЦП. Такой метод эффективно поддерживает дискретные GPU и их большие объемы недоступной для ЦП памяти, не нарушая архитектуры UMA.

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

const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256;
const UINT 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. В результате в некоторых сценариях сопоставление и отмена сопоставления могут даже быть оптимизированы.

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

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

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