Share via


Carregando dados de textura por meio de buffers

Carregar dados de textura 2D ou 3D é semelhante ao carregamento de dados 1D, exceto que os aplicativos precisam prestar mais atenção ao alinhamento de dados relacionado à inclinação de linha. Os buffers podem ser usados de forma ortogonal e simultânea de várias partes do pipeline gráfico e são muito flexíveis.

Carregar dados de textura por meio de buffers

Os aplicativos devem carregar dados por meio de ID3D12GraphicsCommandList::CopyTextureRegion ou ID3D12GraphicsCommandList::CopyBufferRegion. É muito mais provável que os dados de textura sejam maiores, acessados repetidamente e se beneficiem da coerência de cache aprimorada de layouts de memória não linear do que outros dados de recurso. Quando os buffers são usados no D3D12, os aplicativos têm controle total sobre o posicionamento e a organização dos dados associados à cópia de dados de recursos, desde que os requisitos de alinhamento de memória sejam atendidos.

O exemplo realça onde o aplicativo simplesmente nivela os dados 2D em 1D antes de colocá-los no buffer. Para o cenário de mipmap 2D, o aplicativo pode nivelar cada sub-recurso de forma discreta e usar rapidamente um algoritmo de sub-alocação 1D ou usar uma técnica de sublocação 2D mais complicada para minimizar a utilização da memória de vídeo. Espera-se que a primeira técnica seja usada com mais frequência, pois é mais simples. A segunda técnica pode ser útil ao empacotar dados em um disco ou em uma rede. Em ambos os casos, o aplicativo ainda deve chamar as APIs de cópia para cada sub-recurso.

// 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 );

Observe o uso das estruturas auxiliares CD3DX12_HEAP_PROPERTIES e CD3DX12_TEXTURE_COPY_LOCATION e os métodos CreateCommittedResource e CopyTextureRegion.

Copiando

Os métodos D3D12 permitem que os aplicativos substituam os dados iniciais do recurso UpdateSubresource, CopySubresourceRegion e D3D11. Um único sub-recurso 3D de dados de textura principal de linha pode estar localizado em recursos de buffer. CopyTextureRegion pode copiar esses dados de textura do buffer para um recurso de textura com um layout de textura desconhecido e vice-versa. Os aplicativos devem preferir esse tipo de técnica para preencher recursos de GPU acessados com frequência, criando buffers grandes em um heap upload enquanto criam os recursos de GPU acessados com frequência em um heap DEFAULT que não tem acesso à CPU. Essa técnica dá suporte eficiente a GPUs discretas e a grandes quantidades de memória inacessível da CPU, sem prejudicar normalmente as arquiteturas de UMA.

Observe as duas seguintes constantes:

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

Mapeamento e desmapeamento

Map e Unmap podem ser chamados por vários threads com segurança. A primeira chamada para Mapa aloca um intervalo de endereços virtuais da CPU para o recurso. A última chamada para Desalocar desaloca o intervalo de endereços virtuais da CPU. O endereço virtual da CPU normalmente é retornado ao aplicativo.

Sempre que os dados são passados entre a CPU e a GPU por meio de recursos em heaps de readback, Map e Unmap devem ser usados para dar suporte a todos os sistemas em que o D3D12 tem suporte. Manter os intervalos o mais apertado possível maximiza a eficiência nos sistemas que exigem intervalos (consulte D3D12_RANGE).

O desempenho das ferramentas de depuração beneficia-se não apenas do uso preciso de intervalos em todas as / chamadasDesmapear mapa, mas também de aplicativos desmapeando recursos quando modificações de CPU não serão mais feitas.

Não há suporte para o método D3D11 de usar Map (com o parâmetro DISCARD definido) para renomear recursos em D3D12. Os aplicativos devem implementar a renomeação de recursos por conta própria. Todas as chamadas de Mapa são implicitamente NO_OVERWRITE e multi-threaded. É responsabilidade do aplicativo garantir que qualquer trabalho de GPU relevante contido nas listas de comandos seja concluído antes do acesso aos dados com a CPU. As chamadas D3D12 para o Mapa não liberam implicitamente nenhum buffer de comando, nem bloqueiam a espera pela conclusão do trabalho da GPU. Como resultado, Map e Unmap podem até ser otimizados em alguns cenários.

Alinhamento do buffer

Restrições de alinhamento de buffer:

  • A cópia de sub-recurso linear deve ser alinhada a 512 bytes (com o tom de linha alinhado a D3D12_TEXTURE_DATA_PITCH_ALIGNMENT bytes).
  • As leituras de dados constantes devem ser um múltiplo de 256 bytes desde o início do heap (ou seja, somente de endereços alinhados a 256 bytes).
  • As leituras de dados de índice devem ser um múltiplo do tamanho do tipo de dados de índice (ou seja, somente de endereços naturalmente alinhados para os dados).
  • Os dados ID3D12GraphicsCommandList::ExecuteIndirect devem ser de deslocamentos que são múltiplos de 4 (ou seja, somente de endereços alinhados ao DWORD).