Assinatura raiz versão 1.1

A finalidade da Assinatura Raiz versão 1.1 é permitir que os aplicativos indiquem aos drivers quando os descritores em um heap de descritor não forem alterados ou os descritores de dados apontarem para não forem alterados. Isso permite que os drivers façam otimizações que podem ser possíveis sabendo que um descritor ou a memória para a qual ele aponta está estático por algum período de tempo.

Visão geral

A Assinatura Raiz versão 1.0 permite que o conteúdo de heaps de descritor e a memória em que eles apontam sejam alterados livremente por aplicativos sempre que os pacotes/listas de comandos que fazem referência a eles estiverem potencialmente em versão de pré-lançamento na GPU. Muitas vezes, no entanto, os aplicativos não precisam realmente da flexibilidade para alterar descritores ou memória depois que comandos que os referenciam foram registrados.

Os aplicativos geralmente são facilmente capazes de:

  • Configure descritores (e possível a memória para a qual apontam) antes de associar tabelas de descritores ou descritores raiz em uma lista de comandos ou pacote.
  • Verifique se esses descritores não serão alterados até que a lista de comandos /bundles referenciando-os tenha terminado de ser executada pela última vez.
  • Verifique se os dados para os quais os descritores apontam não são alterados pela mesma duração completa.

Como alternativa, um aplicativo só pode ser capaz de respeitar que os dados não são alterados por uma duração mais curta no tempo. Em particular, os dados podem ser estáticos para a janela no tempo durante a execução da lista de comandos que uma associação de parâmetro raiz (tabela de descritor ou descritor raiz) atualmente aponta para os dados. Em outras palavras, um aplicativo pode desejar executar a execução na GPU linha do tempo que atualiza alguns dados entre períodos de tempo em que ele é definido por meio de um parâmetro raiz, sabendo que quando ele for definido será estático.

Se os descritores ou os descritores de dados apontarem para, não forem alterados, os drivers de otimização específicos poderão ser específicos do fornecedor de hardware e, importante, eles não alterarão o comportamento além de possivelmente melhorar o desempenho. Preservar o máximo de conhecimento possível sobre a intenção do aplicativo não sobrecarrega os aplicativos.

Uma otimização é que muitos drivers podem produzir acessos de memória mais eficientes por sombreadores se souberem as promessas que um aplicativo pode fazer sobre a estática de descritores e dados. Por exemplo, os drivers podem remover um nível de indireção para acessar um descritor em um heap convertendo-o em um descritor raiz se o hardware específico não for sensível ao tamanho do argumento raiz.

A tarefa adicional para o desenvolvedor que usa a versão 1.1 é fazer promessas sobre a volatilidade e a estática dos dados sempre que possível, para que os drivers possam fazer as otimizações que fazem sentido. Os desenvolvedores não precisam fazer promessas sobre estática.

A assinatura raiz versão 1.0 continua funcionando inalterada, embora os aplicativos que recompilem assinaturas raiz usarão como padrão a Assinatura Raiz 1.1 agora (com uma opção para forçar a versão 1.0, se desejado).

Sinalizadores estáticos e voláteis

Os sinalizadores a seguir fazem parte da assinatura raiz para permitir que os drivers escolham uma estratégia para lidar melhor com argumentos raiz individuais quando eles são definidos e também inserir as mesmas suposições em PSOs (Objetos de Estado do Pipeline) quando eles são compilados originalmente , já que a assinatura raiz faz parte de um PSO.

Os sinalizadores a seguir são definidos pelo aplicativo e se aplicam a descritores ou dados.

typedef enum D3D12_DESCRIPTOR_RANGE_FLAGS
{
    D3D12_DESCRIPTOR_RANGE_FLAG_NONE    = 0,
    D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE    = 0x1,
    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE   = 0x2,
    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE    = 0x4,
    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC = 0x8
} D3D12_DESCRIPTOR_RANGE_FLAGS;

typedef enum D3D12_ROOT_DESCRIPTOR_FLAGS
{
    D3D12_ROOT_DESCRIPTOR_FLAG_NONE = 0,
    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE    = 0x2,
    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
    D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC  = 0x8
} D3D12_ROOT_DESCRIPTOR_FLAGS;

DESCRIPTORS_VOLATILE

Com esse sinalizador definido, os descritores em um heap de descritor apontado por uma tabela de descritor raiz podem ser alterados pelo aplicativo a qualquer momento, exceto enquanto a lista de comandos/pacotes que associam a tabela do descritor foram enviados e não terminaram de ser executados. Por exemplo, a gravação de uma lista de comandos e a alteração subsequente de descritores em um heap de descritor a que se refere antes de enviar a lista de comandos para execução é válida. Esse é o único comportamento com suporte da Assinatura Raiz versão 1.0.

Se o sinalizador DESCRIPTORS_VOLATILE não estiver definido, os descritores serão estáticos. Não há nenhum sinalizador para esse modo. Descritores estáticos significam que os descritores em um heap de descritor apontados por uma tabela de descritor raiz foram inicializados no momento em que a tabela do descritor é definida em uma lista de comandos/pacote (durante a gravação) e os descritores não podem ser alterados até que a lista de comandos/pacote tenha terminado de ser executado pela última vez. Para a Assinatura Raiz versão 1.1, os descritores estáticos são a suposição padrão e o aplicativo precisa especificar o sinalizador DESCRIPTORS_VOLATILE quando necessário.

Para pacotes que usam tabelas de descritor com descritores estáticos, os descritores precisam estar prontos a partir do momento em que o pacote é registrado (em vez de quando o pacote é chamado) e não alterar até que o pacote tenha terminado de ser executado pela última vez. As tabelas de descritor que apontam para descritores estáticos precisam ser definidas durante a gravação do pacote e não herdadas no pacote. É válido que uma lista de comandos use uma tabela de descritores com descritores estáticos que foram definidos em um pacote e retornados de volta à lista de comandos.

Quando os descritores são estáticos, há outra alteração no comportamento que exige que o sinalizador DESCRIPTORS_VOLATILE seja definido. Os acessos fora dos limites a quaisquer exibições de buffer (em oposição às exibições Texture1D/2D/3D/Cube) são inválidos e produzem resultados indefinidos, incluindo possíveis redefinições de dispositivo, em vez de retornar valores padrão para leituras ou remoção de gravações. A finalidade de remover a capacidade dos aplicativos de depender do hardware fora dos limites de verificação de acesso é permitir que os drivers optem por promover acessos de descritor estático a acessos de descritor raiz se eles consideram isso mais eficiente. Os descritores raiz não dão suporte a nenhuma verificação fora dos limites.

Se os aplicativos dependerem do comportamento de acesso à memória fora dos limites ao acessar descritores, eles precisarão marcar os intervalos de descritores que acessam esses descritores como DESCRIPTORS_VOLATILE.

DATA_VOLATILE

Com esse sinalizador definido, os dados apontados por descritores podem ser alterados pela CPU a qualquer momento, exceto enquanto a lista de comandos/pacotes que associam a tabela de descritores foram enviados e não terminaram de ser executados. Esse é o único comportamento com suporte da Assinatura Raiz versão 1.0.

O sinalizador está disponível em sinalizadores de intervalo de descritor e sinalizadores de descritor raiz.

DATA_STATIC_WHILE_SET_AT_EXECUTE

Com esse sinalizador definido, os dados apontados por descritores não podem ser alterados a partir de quando a tabela de descritor raiz ou descritor subjacente é definida em uma lista de comandos/pacote durante a execução na linha do tempo de GPU e termina quando os próximos sorteios/expedições não referenciam mais os dados.

Antes que uma tabela de descritor ou descritor raiz tenha sido definida na GPU, esses dados podem ser alterados até mesmo pela mesma lista/pacote de comandos. Os dados também podem ser alterados enquanto uma tabela de descritor raiz ou descritor apontando para ela ainda estiver definida na lista/pacote de comandos, desde que o desenho/expedições que fazem referência a ele tenham sido concluídos. No entanto, isso exige que a tabela de descritores seja reexecutada na lista de comandos novamente antes da próxima vez que a tabela de descritor raiz ou descritor for desreferenciada. Isso permite que o driver saiba que os dados apontados por uma tabela de descritor raiz ou descritor foram alterados.

A diferença essencial entre DATA_STATIC_WHILE_SET_AT_EXECUTE e DATA_VOLATILE é com DATA_VOLATILE um driver não pode dizer se as cópias de dados em uma lista de comandos alteraram os dados apontados por um descritor, sem fazer um acompanhamento de estado extra. Portanto, se, por exemplo, um driver puder inserir qualquer tipo de comando de pré-busca de dados em sua lista de comandos (para tornar o acesso de sombreador a dados conhecidos mais eficiente, por exemplo), DATA_STATIC_WHILE_SET_AT_EXECUTE permitirá que o driver saiba que ele só precisa executar a busca prévia de dados no momento em que ele é definido por meio de SetGraphicsRootDescriptorTable, SetComputeRootDescriptorTable ou um dos métodos para definir a exibição de buffer constante, exibição de recurso de sombreador ou exibição de acesso não ordenado.

Para pacotes, a promessa de que os dados são estáticos enquanto definidos em execução se aplica exclusivamente a cada execução do pacote.

O sinalizador está disponível em sinalizadores de intervalo de descritor e sinalizadores de descritor raiz.

DATA_STATIC

Se esse sinalizador for definido, os dados apontados por descritores serão inicializados quando uma tabela de descritor raiz ou descritor referenciar a memória tiver sido definida em uma lista de comandos/pacote durante a gravação e os dados não poderão ser alterados até que a lista de comandos/pacote tenha terminado de ser executada pela última vez.

Para pacotes, a duração estática começa na configuração de tabela de descritor raiz ou descritor durante a gravação do pacote, em vez de gravar uma lista de comandos de chamada. Além disso, uma tabela de descritor que aponta para dados estáticos deve ser definida no pacote e não herdada. É válido que uma lista de comandos use uma tabela de descritor apontando para dados estáticos que foram definidos em um pacote e retornados de volta para a lista de comandos.

O sinalizador está disponível em sinalizadores de intervalo de descritor e sinalizadores de descritor raiz.

Combinar sinalizadores

No máximo um dos sinalizadores DATA pode ser especificado por vez, exceto para intervalos de descritor de sampler que não dão suporte a sinalizadores DATA, pois os samplers não apontam para dados.

A ausência de sinalizadores DATA para intervalos de descritor SRV e CBV significa que um padrão de comportamento de DATA_STATIC_WHILE_SET_AT_EXECUTE é assumido. O motivo pelo qual esse padrão é escolhido em vez de DATA_STATIC é que DATA_STATIC_WHILE_SET_AT_EXECUTE é muito mais provável que seja um padrão seguro para a maioria dos casos, ao mesmo tempo em que produz alguma oportunidade de otimização melhor do que a padronização para DATA_VOLATILE.

A ausência de sinalizadores DATA para intervalos de descritores UAV significa que um padrão de comportamento de DATA_VOLATILE é assumido, dado que normalmente os UAVs são gravados.

DESCRIPTORS_VOLATILE não pode ser combinado com DATA_STATIC, mas pode ser combinado com os outros sinalizadores DATA. O motivo pelo qual DESCRIPTORS_VOLATILE pode ser combinado com DATA_STATIC_WHILE_SET_AT_EXECUTE é que os descritores voláteis ainda exigem que os descritores estejam prontos durante a lista de comandos/execução do pacote, e DATA_STATIC_WHILE_SET_AT_EXECUTE só está fazendo promessas sobre a estática dentro de um subconjunto de lista de comandos/execução de pacote.

Resumo do Sinalizador

As tabelas a seguir resumem as combinações de sinalizadores que podem ser empregadas.

Configurações de D3D12_DESCRIPTOR_RANGE_FLAGS válidas Descrição
Nenhum sinalizador definido Os descritores são estáticos (o padrão). Suposições padrão para dados: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE e para UAV: DATA_VOLATILE. Esses padrões para SRV/CBV se ajustarão com segurança aos padrões de uso para a maioria das assinaturas raiz.
DATA_STATIC Os descritores e os dados são estáticos. Isso maximiza o potencial de otimização do driver.
DATA_VOLATILE Os descritores são estáticos e os dados são voláteis.
DATA_STATIC_WHILE_SET_AT_EXECUTE Os descritores são estáticos e os dados são estáticos enquanto definidos em execução.
DESCRIPTORS_VOLATILE Os descritores são voláteis e são feitas suposições padrão sobre os dados: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE e para UAV: DATA_VOLATILE.
DESCRIPTORS_VOLATILE | DATA_VOLATILE Os descritores e os dados são voláteis, equivalentes à Assinatura Raiz 1.0.
DESCRIPTORS_VOLATILE | DATA_STATIC_WHILE_SET_AT_EXECUTE Os descritores são voláteis, mas observe que ainda não permite que eles sejam alterados durante a execução da lista de comandos. Portanto, é válido combinar a declaração adicional de que os dados são estáticos enquanto definidos por meio da tabela de descritor raiz durante a execução – os descritores subjacentes são efetivamente estáticos por mais tempo do que os dados estão sendo prometidos para serem estáticos.

 

Configurações de D3D12_ROOT_DESCRIPTOR_FLAGS válidas Descrição
Nenhum sinalizador definido Suposições padrão para dados: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE e para UAV: DATA_VOLATILE. Esses padrões para SRV/CBV se ajustarão com segurança aos padrões de uso para a maioria das assinaturas raiz.
DATA_STATIC Os dados são estáticos, o melhor potencial para a otimização do driver.
DATA_STATIC_WHILE_SET_AT_EXECUTE Os dados são estáticos enquanto definidos em execução.
DATA_VOLATILE Equivalente à Assinatura Raiz 1.0.

 

Resumo da API versão 1.1

As chamadas à API a seguir habilitam a versão 1.1.

Enumerações

Essas enumerações contêm os principais sinalizadores para especificar o descritor e a volatilidade dos dados.

Estruturas

As estruturas atualizadas (da versão 1.0) contêm referências aos sinalizadores estáticos/de volatilidade.

Funções

Os métodos listados aqui substituem as funções originais D3D12SerializeRootSignature e D3D12CreateRootSignatureDeserializer , pois são projetados para funcionar em qualquer versão da assinatura raiz. O formulário serializado é o que é passado para a API CreateRootSignature . Se um sombreador tiver sido criado com uma assinatura raiz, o sombreador compilado já conterá uma assinatura raiz serializada nele.

Métodos

A interface ID3D12VersionedRootSignatureDeserializer é criada para desserializar a estrutura de dados de assinatura raiz.

Estruturas auxiliares

Estruturas auxiliares foram adicionadas para auxiliar na inicialização de algumas das estruturas da versão 1.1.

  • CD3DX12_DESCRIPTOR_RANGE1
  • CD3DX12_ROOT_PARAMETER1
  • CD3DX12_STATIC_SAMPLER1
  • CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC

Consulte Estruturas auxiliares e funções para D3D12.

Consequências da violação de sinalizadores estáticos

O descritor e os sinalizadores de dados descritos acima (bem como os padrões implícitos pela ausência de sinalizadores específicos) definem uma promessa do aplicativo ao driver sobre como ele vai se comportar. Se um aplicativo violar a promessa, esse é um comportamento inválido: os resultados são indefinidos e podem ser diferentes em diferentes drivers e hardware.

A camada de depuração tem opções para validar se os aplicativos cumprem suas promessas, incluindo as promessas padrão que vêm com o uso da Assinatura Raiz versão 1.1 sem definir nenhum sinalizador.

Gerenciamento de versão

Ao compilar assinaturas raiz anexadas a sombreadores, os compiladores HLSL mais recentes usarão como padrão compilar a assinatura raiz na versão 1.1, enquanto os compiladores HLSL antigos só dão suporte a 1.0. Observe que as assinaturas raiz 1.1 não funcionarão nos sistemas operacionais que não dão suporte à assinatura raiz 1.1.

A versão de assinatura raiz compilada com um sombreador pode ser forçada a uma versão específica usando /force_rootsig_ver <version>. Forçar a versão terá êxito se o compilador puder preservar o comportamento da assinatura raiz que está sendo compilada na versão forçada, por exemplo, soltando sinalizadores sem suporte na assinatura raiz que servem apenas para fins de otimização, mas não afetam o comportamento.

Dessa forma, um aplicativo pode, por exemplo, compilar uma assinatura raiz 1.1 para 1.0 e 1.1 ao criar o aplicativo e selecionar a versão apropriada em runtime, dependendo do nível de suporte do sistema operacional. No entanto, seria mais eficiente no espaço para um aplicativo compilar assinaturas raiz individualmente (especialmente se várias versões forem necessárias), separadamente dos sombreadores. Mesmo que os sombreadores não sejam compilados inicialmente com uma assinatura raiz anexada, o benefício da validação do compilador da compatibilidade de assinatura raiz com um sombreador pode ser preservado usando a opção do /verifyrootsignature compilador. Posteriormente no runtime, os PSOs podem ser criados usando sombreadores que não têm assinaturas raiz neles ao passar a assinatura raiz desejada (talvez a versão apropriada compatível com o sistema operacional) como um parâmetro separado.

Como criar uma assinatura raiz

Assinaturas raiz

Como especificar assinaturas raiz no HLSL