Compartilhar via


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 são alterados ou os descritores de dados que apontam não serão alterados. Isso permite que os drivers façam otimizações que podem ser possíveis sabendo que um descritor ou a memória que ele aponta é 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 referenciados 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 após comandos que os referenciam terem sido registrados.

Os aplicativos geralmente são trivialmente capazes de:

  • Configure descritores (e possível a memória para a qual eles apontam) antes de associar tabelas de descritor 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 /pacotes que fazem referência a eles tenha terminado de executar pela última vez.
  • Verifique se os dados que os descritores apontam não são alterados pela mesma duração completa.

Como alternativa, um aplicativo só pode ser capaz de honrar que os dados não sejam 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) aponta atualmente para os dados. Em outras palavras, um aplicativo pode desejar executar a execução na linha do tempo da GPU 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 ele 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 padrão para 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 de 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 conjunto de sinalizadores, os descritores em um heap de descritor apontados 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 executar. Por exemplo, gravar uma lista de comandos e alterar posteriormente os descritores em um heap de descritor refere-se a antes de enviar a lista de comandos para execução é válido. Esse é o único comportamento com suporte da Assinatura Raiz versão 1.0.

Se o sinalizador de DESCRIPTORS_VOLATILE não 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 apontado por uma tabela de descritor raiz foram inicializados quando a tabela de 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 Assinatura Raiz versão 1.1, descritores estáticos são a suposição padrãoe o aplicativo precisa especificar o sinalizador de 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 são alterados 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 para uma lista de comandos usar uma tabela de descritor 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 de DESCRIPTORS_VOLATILE seja definido. 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 gravações de remoção. 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 considerarem isso mais eficiente. Os descritores raiz não dão suporte a nenhuma verificação fora dos limites.

Se os aplicativos dependerem do comportamento seguro 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 conjunto de sinalizadores, os dados apontados por descritores podem ser alterados pela CPU 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. 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 conjunto de sinalizadores, os dados apontados por descritores não podem ser alterados a partir de quando o descritor raiz subjacente ou a tabela de descritor está definida em uma lista de comandos/pacote durante a execução na linha do tempo da GPU e terminar quando os sorteios/expedições subsequentes não fizerem mais referência aos dados.

Antes que uma tabela de descritor raiz ou descritor tenha sido definida na GPU, esse de dados pode ser alterados até mesmo pela mesma lista de comandos/pacote. Os dados também podem ser alterados enquanto uma tabela de descritor raiz ou descritor apontando para ela ainda estiver definida na lista de comandos/pacote, desde que o desenho/expedições que fazem referência a ele tenha sido concluído. No entanto, isso requer que a tabela de descritor seja repercutida 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 um descritor raiz ou tabela de 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 comandos 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, o modo de exibição de recurso do sombreador ou a 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 no momento em que um descritor raiz ou uma tabela de descritor referenciando 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 da 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 para uma lista de comandos usar uma tabela de descritor apontando para dados estáticos que foram definidos em um pacote e retornados de volta à lista de comandos.

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

Combinando 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 ainda gera alguma oportunidade de otimização melhor do que o padrã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 está apenas 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 conjunto de sinalizadores 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 as suposições padrão são feitas 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 mudem 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 conjunto de sinalizadores 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 durante a 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 de volatilidade/estáticos.

Funções

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

Métodos

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

Estruturas auxiliares

Estruturas auxiliares foram adicionadas para ajudar 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 paraD3D12.

Consequências de violar 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 entre drivers e hardware diferentes.

A camada de depuração tem opções para validar que 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 terão o padrão de compilar a assinatura raiz na versão 1.1, enquanto os compiladores HLSL antigos dão suporte apenas a 1.0. Observe que as assinaturas raiz 1.1 não funcionarão em 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 compilar o aplicativo e selecionar a versão apropriada em runtime, dependendo do nível de suporte do sistema operacional. No entanto, seria mais eficiente 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 /verifyrootsignature compilador. Posteriormente no runtime, os PSOs podem ser criados usando sombreadores que não têm assinaturas raiz neles enquanto passam a assinatura raiz desejada (talvez a versão apropriada com suporte do sistema operacional) como um parâmetro separado.

criando um de assinatura raiz

assinaturas raiz

especificando assinaturas raiz no HLSL