Compartilhar via


Desenho indireto

O desenho indireto permite que algumas travessias de cena e abate sejam movidos da CPU para a GPU, o que pode melhorar o desempenho. O buffer de comando pode ser gerado pela CPU ou GPU.

Assinaturas de comando

O objeto de assinatura de comando (ID3D12CommandSignature) permite que os aplicativos especifiquem o desenho indireto, em particular definindo o seguinte:

Na inicialização, um aplicativo cria um pequeno conjunto de assinaturas de comando. Em tempo de execução, o aplicativo preenche um buffer com comandos (por meio de qualquer meio que o desenvolvedor do aplicativo escolher). Os comandos opcionalmente contêm estado a ser definido para exibições de buffer de vértice, exibições de buffer de índice, constantes de raiz e descritores de raiz (SRV/UAV/CBVs brutos ou estruturados). Esses layouts de argumento não são específicos de hardware para que os aplicativos possam gerar os buffers diretamente. A assinatura do comando herda o estado restante da lista de comandos. Em seguida, o aplicativo chama ExecuteIndirect para instruir a GPU a interpretar o conteúdo do buffer de argumento indireto de acordo com o formato definido por uma assinatura de comando específica.

Se a assinatura de comando alterar quaisquer argumentos de raiz, isso será armazenado na assinatura de comando como um subconjunto de uma assinatura raiz.

Nenhum estado de assinatura de comando vaza de volta para a lista de comandos após a conclusão da execução. Mas, após ExecuteIndirect, todas as ligações são redefinidas para valores conhecidos. Especialmente:

  • Se a assinatura do comando vincular um buffer de vértice a um slot específico, depois que ExecuteIndirect for chamado, um buffer de vértice NULL será vinculado a esse slot.
  • Se a assinatura do comando vincular um buffer de índice, depois de ExecuteIndirect, um buffer de índice NULL será vinculado.
  • Se a assinatura do comando definir uma constante raiz, depois que ExecuteIndirect for chamado, o valor da constante raiz será definido como 0.
  • Se a assinatura de comando definir uma exibição raiz (CBV/SRV/UAV), depois que ExecuteIndirect for chamada, a exibição raiz será definida como uma exibição NULL.

Como exemplo de uso de assinaturas de comando: suponha que um desenvolvedor de aplicativo queira que uma constante raiz exclusiva seja especificada por chamada por desenho no buffer de argumento indireto. O aplicativo criaria uma assinatura de comando que permite que o buffer de argumento indireto especifique os seguintes parâmetros por chamada de desenho:

  • O valor de uma constante de raiz.
  • Os argumentos de desenho (contagem de vértices, contagem de instâncias, etc.).

O buffer de argumento indireto gerado pelo aplicativo conteria uma matriz de registros de tamanho fixo. Cada estrutura corresponde a uma chamada de sorteio. Cada estrutura contém os argumentos de desenho e o valor da constante raiz. O número de chamadas de desenho é especificado em um buffer visível de GPU separado.

Segue-se um exemplo de buffer de comando gerado pelo aplicativo:

formato do buffer de comando

Estruturas de buffer de argumento indireto

As estruturas a seguir definem como argumentos específicos aparecem em um buffer de argumento indireto. Essas estruturas não aparecem em nenhuma API D3D12. Os aplicativos usam essas definições ao gravar em um buffer de argumento indireto (com a CPU ou GPU):

Criação de assinatura de comando

Para criar uma assinatura de comando, use os seguintes itens de API:

A ordem dos argumentos dentro de um buffer de argumento indireto é definida para corresponder exatamente à ordem dos argumentos especificada no parâmetro pArguments de D3D12_COMMAND_SIGNATURE_DESC. Todos os argumentos para uma chamada de desenho (gráficos)/despacho (computação) dentro de um buffer de argumento indireto são compactados corretamente. No entanto, os aplicativos têm permissão para especificar uma etapa de bytes arbitrária entre comandos draw/dispatch em um buffer de argumento indireto.

A assinatura raiz deve ser especificada se e somente se a assinatura do comando alterar um dos argumentos raiz.

Para raiz SRV/UAV/CBV, o tamanho especificado do aplicativo é em bytes. A camada de depuração validará as seguintes restrições no endereço:

  • CBV – o endereço deve ser um múltiplo de 256 bytes.
  • SRV/UAV bruto – o endereço deve ser um múltiplo de 4 bytes.
  • SRV/UAV estruturado – o endereço deve ser um múltiplo da etapa de byte da estrutura (declarada no sombreador).

Uma determinada assinatura de comando é uma assinatura de desenho ou de comando de computação. Se uma assinatura de comando contiver uma operação de desenho, ela será uma assinatura de comando gráfico. Caso contrário, a assinatura de comando deve conter uma operação de despacho e é uma assinatura de comando de computação.

As seções a seguir mostram alguns exemplos de assinaturas de comando.

Sem alterações de argumento

Neste exemplo, o buffer de argumento indireto gerado pelo aplicativo contém uma matriz de estruturas de 36 bytes. Cada estrutura contém apenas os cinco parâmetros passados para DrawIndexedInstanced (mais preenchimento).

O código para criar a descrição da assinatura de comando segue:

D3D12_INDIRECT_ARGUMENT_DESC Args[1];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 36;
ProgramDesc.NumArgumentDescs = 1;
ProgramDesc.pArguments = Args;

O layout de uma única estrutura dentro de um buffer de argumento indireto é:

Bytes Descrição
0:3 IndexCountPerInstance
4:7 InstanceCount
8:11 StartIndexLocation
12:15 BaseVertexLocalização
16:19 StartInstanceLocation
20:35 Preenchimento

 

Constantes de raiz e buffers de vértice

Neste exemplo, cada estrutura em um buffer de argumento indireto altera duas constantes de raiz, altera uma associação de buffer de vértice e executa uma operação de desenho não indexada. Não há acolchoamento entre as estruturas.

O código para criar a descrição da assinatura do comando é:

D3D12_INDIRECT_ARGUMENT_DESC Args[4];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[0].Constant.RootParameterIndex = 2;
Args[0].Constant.DestOffsetIn32BitValues = 0;
Args[0].Constant.Num32BitValuesToSet = 1;

Args[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[1].Constant.RootParameterIndex = 6;
Args[1].Constant.DestOffsetIn32BitValues = 0;
Args[1].Constant.Num32BitValuesToSet = 1;

Args[2].Type = D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW;
Args[2].VertexBuffer.Slot = 3;

Args[3].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 40;
ProgramDesc.NumArgumentDescs = 4;
ProgramDesc.pArguments = Args;

O layout de uma única estrutura dentro do buffer de argumento indireto é o seguinte:

Bytes Descrição
0:3 Dados para o índice de parâmetro raiz 2
4:7 Dados para o índice de parâmetro raiz 6
8:15 Endereço virtual do VB no slot 3 (64 bits)
16:19 Tamanho VB
20:23 Passo VB
24:27 VertexCountPerInstance
28:31 InstanceCount
32:35 StartVertexLocalização
36:39 StartInstanceLocation

 

Tutoriais em vídeo de aprendizado avançado do DirectX: Executar eliminação de GPU indireta e assíncrona

Desenho indireto e eliminação de GPU: passo a passo de código

Renderização