Como especificar assinaturas raiz no HLSL
Especificar assinaturas raiz no Modelo de Sombreador HLSL 5.1 é uma alternativa para especificá-las no código C++.
- Um exemplo de assinatura raiz HLSL
- Rootflags
- Constantes raiz
- Visibilidade
- CBV de nível raiz
- SRV de nível raiz
- UAV de nível raiz
- Tabela do descritor
- Amostragem estática
- Compilando uma assinatura raiz HLSL
- Manipulando assinaturas raiz com o compilador FXC
- Observações
- Tópicos relacionados
Um exemplo de assinatura raiz HLSL
Uma assinatura raiz pode ser especificada em HLSL como uma cadeia de caracteres. A cadeia de caracteres contém uma coleção de cláusulas separadas por vírgulas que descrevem componentes constituintes de assinatura raiz. A assinatura raiz deve ser idêntica entre sombreadores para qualquer PSO (objeto de estado de pipeline). Veja um exemplo:
Assinatura raiz versão 1.0
#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
"DENY_VERTEX_SHADER_ROOT_ACCESS), " \
"CBV(b0, space = 1), " \
"SRV(t0), " \
"UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY), " \
"DescriptorTable( CBV(b0), " \
"UAV(u1, numDescriptors = 2), " \
"SRV(t1, numDescriptors = unbounded)), " \
"DescriptorTable(Sampler(s0, numDescriptors = 2)), " \
"RootConstants(num32BitConstants=1, b9), " \
"DescriptorTable( UAV(u3), " \
"UAV(u4), " \
"UAV(u5, offset=1)), " \
"StaticSampler(s2)," \
"StaticSampler(s3, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"filter = FILTER_MIN_MAG_MIP_LINEAR )"
Essa definição daria a seguinte assinatura raiz, observando:
- O uso de parâmetros padrão.
- b0 e (b0, space=1) não entram em conflito
- u0 só é visível para o sombreador de geometria
- u4 e u5 são aliased para o mesmo descritor em um heap
Assinatura raiz versão 1.1
A Versão 1.1 da Assinatura Raiz permite otimizações de driver em descritores e dados de assinatura raiz.
#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
"DENY_VERTEX_SHADER_ROOT_ACCESS), " \
"CBV(b0, space = 1, flags = DATA_STATIC), " \
"SRV(t0), " \
"UAV(u0), " \
"DescriptorTable( CBV(b1), " \
"SRV(t1, numDescriptors = 8, " \
" flags = DESCRIPTORS_VOLATILE), " \
"UAV(u1, numDescriptors = unbounded, " \
" flags = DESCRIPTORS_VOLATILE)), " \
"DescriptorTable(Sampler(s0, space=1, numDescriptors = 4)), " \
"RootConstants(num32BitConstants=3, b10), " \
"StaticSampler(s1)," \
"StaticSampler(s2, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"filter = FILTER_MIN_MAG_MIP_LINEAR )"
A linguagem de assinatura raiz HLSL corresponde de perto às APIs de assinatura raiz do C++ e tem potência expressiva equivalente. A assinatura raiz é especificada como uma sequência de cláusulas, separadas por vírgula. A ordem das cláusulas é importante, pois a ordem de análise determina a posição do slot na assinatura raiz. Cada cláusula usa um ou mais parâmetros nomeados. No entanto, a ordem dos parâmetros não é importante.
Rootflags
A cláusula RootFlags opcional usa 0 (o valor padrão para indicar nenhum sinalizador) ou um ou vários valores de sinalizadores raiz predefinidos, conectados por meio do operador OR '|'. Os valores de sinalizador raiz permitidos são definidos por D3D12_ROOT_SIGNATURE_FLAGS.
Por exemplo:
RootFlags(0) // default value – no flags
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)
Constantes raiz
A cláusula RootConstants especifica constantes raiz na assinatura raiz. Dois parâmetros obrigatórios são: num32BitConstants e bReg (o registro correspondente a BaseShaderRegister em APIs C++) do cbuffer. Os parâmetros espaço (RegisterSpace em APIs C++) e visibilidade (ShaderVisibility em C++) são opcionais e os valores padrão são:
RootConstants(num32BitConstants=N, bReg [, space=0,
visibility=SHADER_VISIBILITY_ALL ])
Por exemplo:
RootConstants(num32BitConstants=3, b3)
Visibilidade
Visibility é um parâmetro opcional que pode ter um dos valores de D3D12_SHADER_VISIBILITY.
SHADER_VISIBILITY_ALL transmite os argumentos raiz para todos os sombreadores. Em algum hardware, isso não tem custo, mas em outros hardwares há um custo para bifurcar os dados em todos os estágios do sombreador. Definir uma das opções, como SHADER_VISIBILITY_VERTEX, limita o argumento raiz a um único estágio de sombreador.
Definir argumentos raiz como estágios de sombreador único permite que o mesmo nome de associação seja usado em estágios diferentes. Por exemplo, uma associação SRV de t0,SHADER_VISIBILITY_VERTEX
e associação SRV de t0,SHADER_VISIBILITY_PIXEL
seria válida. Mas se a configuração de visibilidade fosse t0,SHADER_VISIBILITY_ALL
para uma das associações, a assinatura raiz seria inválida.
CBV de nível raiz
A CBV
cláusula (exibição de buffer constante) especifica uma entrada reg de registro de buffer constante de nível raiz. Observe que essa é uma entrada escalar; não é possível especificar um intervalo para o nível raiz.
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
SRV de nível raiz
A SRV
cláusula (exibição de recurso de sombreador) especifica uma entrada reg de registro t SRV de nível raiz. Observe que essa é uma entrada escalar; não é possível especificar um intervalo para o nível raiz.
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
UAV de nível raiz
A UAV
cláusula (modo de exibição de acesso não ordenado) especifica uma entrada reg de u-register do UAV no nível raiz. Observe que essa é uma entrada escalar; não é possível especificar um intervalo para o nível raiz.
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_VOLATILE ])
Por exemplo:
UAV(u3)
Tabela do descritor
A DescriptorTable
cláusula é, em si, uma lista de cláusulas de tabela de descritor separadas por vírgulas, bem como um parâmetro de visibilidade opcional. As cláusulas DescriptorTable incluem CBV, SRV, UAV e Sampler. Observe que seus parâmetros diferem daqueles das cláusulas de nível raiz.
DescriptorTable( DTClause1, [ DTClause2, … DTClauseN,
visibility=SHADER_VISIBILITY_ALL ] )
A Tabela CBV
do Descritor tem a seguinte sintaxe:
CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND // Version 1.1
, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
Por exemplo:
DescriptorTable(CBV(b0),SRV(t3, numDescriptors=unbounded))
O parâmetro obrigatório bReg especifica o Reg inicial do intervalo cbuffer. O parâmetro numDescriptors especifica o número de descritores no intervalo cbuffer contíguo; o valor padrão é 1. A entrada declara um intervalo [Reg, Reg + numDescriptors - 1]
cbuffer, quando numDescriptors é um número. Se numDescriptors for igual a "unbounded", o intervalo será [Reg, UINT_MAX]
, o que significa que o aplicativo deve garantir que ele não está fazendo referência a uma área fora dos limites. O campo de deslocamento representa o parâmetro OffsetInDescriptorsFromTableStart nas APIs do C++, ou seja, o deslocamento (em descritores) do início da tabela. Se o deslocamento for definido como DESCRIPTOR_RANGE_OFFSET_APPEND (o padrão), isso significa que o intervalo é diretamente após o intervalo anterior. No entanto, a inserção de deslocamentos específicos permite que os intervalos se sobreponham uns aos outros, permitindo o registro de alias.
A Tabela SRV
do Descritor tem a seguinte sintaxe:
SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
Isso é semelhante à entrada da tabela CBV
do descritor, exceto que o intervalo especificado é para exibições de recursos de sombreador.
A Tabela UAV
do Descritor tem a seguinte sintaxe:
UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=DATA_VOLATILE ])
Isso é semelhante à entrada da tabela CBV
do descritor, exceto que o intervalo especificado é para exibições de acesso não ordenadas.
A Tabela Sampler
do Descritor tem a seguinte sintaxe:
Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=0 ])
Isso é semelhante à entrada da tabela CBV
de descritor, exceto que o intervalo especificado é para amostradores de sombreador. Observe que samplers não podem ser misturados com outros tipos de descritores na mesma tabela de descritor (já que eles estão em um heap de descritor separado).
Amostragem estática
O sampler estático representa a estrutura D3D12_STATIC_SAMPLER_DESC . O parâmetro obrigatório para StaticSampler é um Reg escalar de registro s do sampler. Outros parâmetros são opcionais com valores padrão mostrados abaixo. A maioria dos campos aceita um conjunto de enumerações predefinidas.
StaticSampler( sReg,
[ filter = FILTER_ANISOTROPIC,
addressU = TEXTURE_ADDRESS_WRAP,
addressV = TEXTURE_ADDRESS_WRAP,
addressW = TEXTURE_ADDRESS_WRAP,
mipLODBias = 0.f,
maxAnisotropy = 16,
comparisonFunc = COMPARISON_LESS_EQUAL,
borderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE,
minLOD = 0.f,
maxLOD = 3.402823466e+38f,
space = 0,
visibility = SHADER_VISIBILITY_ALL ])
Por exemplo:
StaticSampler(s4, filter=FILTER_MIN_MAG_MIP_LINEAR)
As opções de parâmetro são muito semelhantes às chamadas à API do C++, exceto borderColor, que é restrita a uma enumeração em HLSL.
O campo de filtro pode ser um dos D3D12_FILTER.
Cada um dos campos de endereço pode ser um dos D3D12_TEXTURE_ADDRESS_MODE.
A função de comparação pode ser uma das D3D12_COMPARISON_FUNC.
O campo de cor da borda pode ser um dos D3D12_STATIC_BORDER_COLOR.
A visibilidade pode ser uma das D3D12_SHADER_VISIBILITY.
Compilando uma assinatura raiz HLSL
Há dois mecanismos para compilar uma assinatura raiz HLSL. Primeiro, é possível anexar uma cadeia de caracteres de assinatura raiz a um sombreador específico por meio do atributo RootSignature (no exemplo a seguir, usando o ponto de entrada MyRS1 ):
[RootSignature(MyRS1)]
float4 main(float4 coord : COORD) : SV_Target
{
…
}
O compilador criará e verificará o blob de assinatura raiz do sombreador e o inserirá junto com o código de bytes do sombreador no blob do sombreador. O compilador dá suporte à sintaxe de assinatura raiz para o modelo de sombreador 5.0 e superior. Se uma assinatura raiz for inserida em um sombreador de modelo de sombreador 5.0 e esse sombreador for enviado para o runtime D3D11, em vez de D3D12, a parte de assinatura raiz será silenciosamente ignorada por D3D11.
O outro mecanismo é criar um blob de assinatura raiz autônomo, talvez para reutilizá-lo com um grande conjunto de sombreadores, economizando espaço. A FXC (Effect-Compiler Tool ) dá suporte a modelos de sombreador rootsig_1_0 erootsig_1_1 . O nome da cadeia de caracteres de definição é especificado por meio do argumento /E usual. Por exemplo:
fxc.exe /T rootsig_1_1 MyRS1.hlsl /E MyRS1 /Fo MyRS1.fxo
Observe que a cadeia de caracteres de assinatura raiz definida também pode ser passada na linha de comando, por exemplo, /D MyRS1="...".
Manipulando assinaturas raiz com o compilador FXC
O compilador FXC cria código de byte de sombreador de arquivos de origem HLSL. Há muitos parâmetros opcionais para esse compilador, consulte a Ferramenta do Compilador de Efeito.
Para gerenciar assinaturas raiz criadas pelo HLSL, a tabela a seguir fornece alguns exemplos de como usar FXC.
Linha | Linha de comando | Descrição |
---|---|---|
1 | fxc /T ps_5_1 shaderWithRootSig.hlsl /Fo rs1.fxo |
Compila um sombreador para o destino do sombreador de pixel 5.1, a origem do sombreador está no arquivo shaderWithRootSig.hlsl, que inclui uma assinatura raiz. O sombreador e a assinatura raiz são compilados como blobs separados no arquivo binário rs1.fxo. |
2 | fxc /dumpbin rs1.fxo /extractrootsignature /Fo rs1.rs.fxo |
Extrai a assinatura raiz do arquivo criado pela linha 1, portanto, o arquivo rs1.rs.fxo contém apenas uma assinatura raiz. |
3 | fxc /dumpbin rs1.fxo /Qstrip_rootsignature /Fo rs1.stripped.fxo |
Remove a assinatura raiz do arquivo criado pela linha 1, portanto, o arquivo rs1.stripped.fxo contém um sombreador sem assinatura raiz. |
4 | fxc /dumpbin rs1.stripped.fxo /setrootsignature rs1.rs.fxo /Fo rs1.new.fxo |
Combina um sombreador e uma assinatura raiz que estão em arquivos separados em um arquivo binário que contém ambos os blobs. Neste exemplo, rs1.new.fx0 seria idêntico a rs1.fx0 na linha 1. |
5 | fxc /T rootsig_1_0 rootSigAndMaybeShaderInHereToo.hlsl /E RS1 /Fo rs2.fxo |
Cria um arquivo binário de assinatura raiz autônoma de uma origem que pode conter mais do que apenas uma assinatura raiz. Observe o destino rootsig_1_0 e que RS1 é o nome da cadeia de caracteres de macro de assinatura raiz (#define) no arquivo HLSL. |
A funcionalidade disponível por meio do FXC também está disponível programaticamente usando a função D3DCompile . Essa chamada compila um sombreador com uma assinatura raiz ou uma assinatura raiz autônoma (definindo o destino rootsig_1_0). D3DGetBlobPart e D3DSetBlobPart podem extrair e anexar assinaturas raiz a um blob existente. D3D_BLOB_ROOT_SIGNATURE é usado para especificar o tipo de parte de blob de assinatura raiz. D3DStripShader remove a assinatura raiz (usando o sinalizador D3DCOMPILER_STRIP_ROOT_SIGNATURE) do blob.
Observações
Observação
Enquanto a compilação offline de sombreadores é altamente recomendada, se os sombreadores precisarem ser compilados em runtime, consulte as observações de D3DCompile2.
Observação
Os ativos HLSL existentes não precisam ser alterados para lidar com assinaturas raiz a serem usadas com eles.
Tópicos relacionados