Analisar formatos de vértice

É possível diagnosticar alguns problemas de desempenho relacionados ao vértice usando a criação de perfil de frame. Use o painel Commands para ver todas as chamadas de desenho que o jogo realiza em um determinado frame e a contagem de primitivos desenhados por chamada de desenho. Isso pode fornecer uma aproximação do número total de vértices enviados em um único frame.

Visualização de criação de perfil do frame para uma chamada de glDrawElements, com o cursor sobre os detalhes
            dos parâmetros de chamada de desenho.
Figura 1. Visualização de criação de perfil de frame para uma única chamada glDrawElements, mostrando 2.718 primitivas de triângulos renderizadas.

Compactação de atributos do vértice

Um problema comum que seu jogo pode enfrentar é um tamanho médio de vértice grande. Um grande número de vértices enviados com um tamanho médio de vértice alto resulta em uma largura de banda de leitura de memória de vértice grande quando lido pela GPU.

Para observar o formato do vértice para uma determinada chamada de desenho, siga estas etapas:

  1. Selecione uma chamada de desenho do seu interesse.

    Pode ser uma chamada de desenho típica para a cena, uma chamada de desenho com um grande número de vértices, uma chamada de desenho para um modelo de caracteres complexo ou algum outro tipo de chamada de desenho.

  2. Navegue até o painel Pipeline e clique em IA para montar a entrada. Isso define o formato dos vértices que chegam à GPU.

  3. Observe uma série de atributos e os respectivos formatos. Por exemplo, R32G32B32_SFLOAT é um flutuante assinado de 32 bits de três componentes.

Visualização de criação de perfil de frame para o conjunto de entrada de uma chamada de desenho, com
            atributos de vértice não compactados.
Figura 2. Conjunto de entrada para uma chamada de desenho, com atributos não compactados, resultando em um tamanho de vértice de 56 bytes

Muitas vezes, os atributos de vértice podem ser compactados com redução mínima na qualidade dos modelos desenhados. Especificamente, recomendamos:

  • Compactação da posição do vértice para flutuantes de 16 bits com meia precisão
  • Compactação de coordenadas de textura UV em ushorts inteiros não assinados de 16 bits
  • Compactar o espaço tangente codificando vetores normal, tangente e binormal usando quatérnios

Outros atributos diversos também podem ser considerados para tipos de precisão mais baixa, de acordo com cada caso.

Divisão de fluxo de vértices

Você também pode investigar se os fluxos de atributos do vértice estão divididos corretamente. Em arquiteturas de renderização em blocos, como GPUs para dispositivos móveis, as posições de vértice são usadas primeiro em um cartão de agrupamento para criar agrupamentos de primitivos processados em cada bloco. Se os atributos de vértice forem intercalados em um único buffer, todos os dados do vértice serão lidos no cache para agrupamento, mesmo que apenas posições de vértice sejam usadas.

Para reduzir a largura de banda da memória de leitura do vértice e melhorar a eficiência do cache, reduzindo o tempo gasto na passagem de agrupamento, os dados de vértice precisam ser divididos em dois streams separados, um para posições de vértice e outro para todos os outros atributos de vértice.

Para investigar se os atributos de vértice estão divididos corretamente:

  1. Selecione uma chamada de desenho e anote o número dela.

    Pode ser uma chamada de desenho típica para a cena, uma chamada de desenho com um grande número de vértices, uma chamada de desenho para um modelo de caracteres complexo ou algum outro tipo de chamada de desenho.

  2. Navegue até o painel Pipeline e clique em IA para montar a entrada. Isso define o formato de vértice para vértices que entram na GPU.

  3. Observe as vinculações dos atributos de vértice. Normalmente, elas podem aumentar linearmente (0, 1, 2, 3 etc.), mas esse nem sempre é o caso. A posição do vértice normalmente é o primeiro atributo de vértice listado.

  4. No painel State, encontre o LastDrawInfos e expanda o número da chamada de desenho correspondente. Em seguida, expanda a BoundVertexBuffers para essa chamada de desenho.

  5. Observe os buffers de vértice vinculados durante a chamada de desenho determinada, com índices correspondentes às vinculações de atributo de vértice anteriores.

  6. Expanda as vinculações dos atributos de vértice da chamada de desenho e amplie os buffers.

  7. Observe o VulkanHandle para os buffers, que representam a memória de origem dos dados do vértice. Se os VulkanHandles forem diferentes, isso significa que os atributos se originam de diferentes buffers. Se os VulkanHandles forem os mesmos, mas os deslocamentos forem grandes (por exemplo, maiores que 100), os atributos ainda poderão se originar de diferentes subbuffers, mas isso exige uma investigação mais aprofundada.

Visualização de criação de perfil do frame para o conjunto de entrada e o estado de uma chamada de desenho mostrando o buffer de vértice vinculado.
Figura 3. Conjunto de entrada para uma chamada de desenho, com o painel de estado à direita mostrando que os atributos na vinculação 0 e 1, posição do vértice e normal, compartilham um único buffer subjacente

Para mais detalhes sobre a divisão de fluxo de vértices e como resolver isso em vários mecanismos de jogos, consulte nossa postagem do blog (link em inglês) sobre o assunto.