Compartir a través de


Especificación de firmas de raíz en HLSL

Especificar firmas raíz en HLSL Shader Model 5.1 es una alternativa a especificarlas en código de C++.

Un ejemplo de firma raíz de HLSL

Una firma raíz se puede especificar en HLSL como una cadena. La cadena contiene una colección de cláusulas separadas por comas que describen los componentes constituyentes de la firma raíz. La firma raíz debe ser idéntica entre sombreadores para cualquier objeto de estado de canalización (MOLA). Este es un ejemplo:

Firma raíz versión 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 )"

Esta definición proporcionaría la siguiente firma raíz, teniendo en cuenta:

  • Uso de parámetros predeterminados.
  • b0 y (b0, space=1) no entran en conflicto
  • u0 solo es visible para el sombreador de geometría
  • u4 y u5 tienen el alias del mismo descriptor en un montón

una firma raíz especificada mediante el lenguaje de sombreador de alto nivel

Versión 1.1 de la firma raíz

La versión 1.1 de la firma raíz permite las optimizaciones de controladores en los descriptores de firma raíz y los datos.

#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 )"

El lenguaje de firma raíz HLSL se corresponde estrechamente con las API de firma raíz de C++ y tiene una potencia expresiva equivalente. La firma raíz se especifica como una secuencia de cláusulas, separadas por coma. El orden de las cláusulas es importante, ya que el orden de análisis determina la posición de ranura en la firma raíz. Cada cláusula toma uno o varios parámetros con nombre. Sin embargo, el orden de los parámetros no es importante.

RootFlags

La cláusula rootFlags opcional toma 0 (el valor predeterminado para indicar ninguna marca) o uno o varios de los valores de marcas raíz predefinidos, conectados a través del operador OR '|'. Los valores de marca raíz permitidos se definen mediante D3D12_ROOT_SIGNATURE_FLAGS.

Por ejemplo:

RootFlags(0) // default value – no flags
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)

Constantes raíz

La cláusula RootConstants especifica constantes raíz en la firma raíz. Dos parámetros obligatorios son: num32BitConstants y bReg (el registro correspondiente a BaseShaderRegister en las API de C++) del cbuffer. Los parámetros space (RegisterSpace in C++ APIs) y visibility (ShaderVisibility in C++) son opcionales y los valores predeterminados son:

RootConstants(num32BitConstants=N, bReg [, space=0, 
              visibility=SHADER_VISIBILITY_ALL ])

Por ejemplo:

RootConstants(num32BitConstants=3, b3)

Visibilidad

Visibility es un parámetro opcional que puede tener uno de los valores de D3D12_SHADER_VISIBILITY.

SHADER_VISIBILITY_ALL difunde los argumentos raíz a todos los sombreadores. En algún hardware esto no tiene costo, pero en otro hardware hay un costo para bifurcar los datos en todas las fases del sombreador. Establecer una de las opciones, como SHADER_VISIBILITY_VERTEX, limita el argumento raíz a una sola fase de sombreador.

Establecer argumentos raíz en fases de sombreador únicas permite usar el mismo nombre de enlace en diferentes fases. Por ejemplo, un enlace SRV de t0,SHADER_VISIBILITY_VERTEX y el enlace SRV de t0,SHADER_VISIBILITY_PIXEL serían válidos. Pero si la configuración de visibilidad fuera t0,SHADER_VISIBILITY_ALL para uno de los enlaces, la firma raíz no sería válida.

CBV de nivel raíz

La CBV cláusula (vista de búfer de constantes) especifica una entrada Reg del búfer de constantes de nivel raíz b-register. Tenga en cuenta que se trata de una entrada escalar; no es posible especificar un intervalo para el nivel raíz.

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 nivel raíz

La SRV cláusula (vista de recursos del sombreador) especifica una entrada Reg de registro de registro T de SRV de nivel raíz. Tenga en cuenta que se trata de una entrada escalar; no es posible especificar un intervalo para el nivel raíz.

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 nivel raíz

La UAV cláusula (vista de acceso desordenada) especifica una entrada Reg UAV u-register de nivel raíz. Tenga en cuenta que se trata de una entrada escalar; no es posible especificar un intervalo para el nivel raíz.

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 ejemplo:

UAV(u3)

Tabla de descriptores

La DescriptorTable cláusula es en sí misma una lista de cláusulas de tabla de descriptores separados por comas, así como un parámetro de visibilidad opcional. Las cláusulas DescriptorTable incluyen CBV, SRV, UAV y Sampler. Tenga en cuenta que sus parámetros difieren de los de las cláusulas de nivel raíz.

DescriptorTable( DTClause1, [ DTClause2, … DTClauseN,
                 visibility=SHADER_VISIBILITY_ALL ] )

La tabla CBV descriptor tiene la siguiente sintaxis:

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 ejemplo:

DescriptorTable(CBV(b0),SRV(t3, numDescriptors=unbounded))

El parámetro obligatorio bReg especifica el reg inicial del intervalo de cbuffer. El parámetro numDescriptors especifica el número de descriptores en el intervalo contiguo de cbuffer; el valor predeterminado es 1. La entrada declara un intervalo [Reg, Reg + numDescriptors - 1] de cbuffer, cuando numDescriptors es un número. Si numDescriptors es igual a "sin enlazar", el intervalo es [Reg, UINT_MAX], lo que significa que la aplicación debe asegurarse de que no hace referencia a un área fuera de límites. El campo offset representa el parámetro OffsetInDescriptorsFromTableStart en las API de C++, es decir, el desplazamiento (en descriptores) desde el principio de la tabla. Si el desplazamiento se establece en DESCRIPTOR_RANGE_OFFSET_APPEND (valor predeterminado), significa que el intervalo está directamente después del intervalo anterior. Sin embargo, especificar desplazamientos específicos permite que los intervalos se superpongan entre sí, lo que permite el alias de registro.

La tabla SRV descriptor tiene la siguiente sintaxis:

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 ])

Esto es similar a la entrada de la tabla CBV descriptor, excepto que el intervalo especificado es para las vistas de recursos del sombreador.

La tabla UAV descriptor tiene la siguiente sintaxis:

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 ])

Esto es similar a la entrada de la tabla CBV descriptor, excepto que el intervalo especificado es para las vistas de acceso desordenadas.

La tabla Sampler descriptor tiene la siguiente sintaxis:

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 ])

Esto es similar a la entrada de la tabla CBV descriptor, excepto que el intervalo especificado es para los muestreadores de sombreador. Tenga en cuenta que los samplers no se pueden mezclar con otros tipos de descriptores de la misma tabla de descriptores (ya que están en un montón de descriptores independiente).

Sampler estático

El sampler estático representa la estructura D3D12_STATIC_SAMPLER_DESC . El parámetro obligatorio para StaticSampler es un reg escalar y de registro s-register del sampler. Otros parámetros son opcionales con los valores predeterminados que se muestran a continuación. La mayoría de los campos aceptan un conjunto de enumeraciones 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 ejemplo:

StaticSampler(s4, filter=FILTER_MIN_MAG_MIP_LINEAR)

Las opciones de parámetro son muy similares a las llamadas API de C++, excepto borderColor, que está restringida a una enumeración en HLSL.

El campo de filtro puede ser uno de D3D12_FILTER.

Los campos de dirección pueden ser uno de D3D12_TEXTURE_ADDRESS_MODE.

La función de comparación puede ser una de D3D12_COMPARISON_FUNC.

El campo de color del borde puede ser uno de D3D12_STATIC_BORDER_COLOR.

La visibilidad puede ser una de D3D12_SHADER_VISIBILITY.

Compilación de una firma raíz de HLSL

Hay dos mecanismos para compilar una firma raíz HLSL. En primer lugar, es posible adjuntar una cadena de firma raíz a un sombreador determinado a través del atributo RootSignature (en el ejemplo siguiente, mediante el punto de entrada MyRS1 ):

[RootSignature(MyRS1)]
float4 main(float4 coord : COORD) : SV_Target
{
…
}

El compilador creará y comprobará el blob de firma raíz del sombreador y lo insertará junto con el código de bytes del sombreador en el blob del sombreador. El compilador admite la sintaxis de firma raíz para el modelo de sombreador 5.0 y versiones posteriores. Si una firma raíz está incrustada en un sombreador de modelo 5.0 y ese sombreador se envía al tiempo de ejecución D3D11, en lugar de D3D12, la parte de la firma raíz se omitirá silenciosamente por D3D11.

El otro mecanismo consiste en crear un blob de firma raíz independiente, quizás reutilizarlo con un gran conjunto de sombreadores, lo que ahorra espacio. Effect-Compiler Tool (FXC) admite modelos de sombreador de rootsig_1_0 yrootsig_1_1. El nombre de la cadena de definición se especifica a través del argumento /E habitual. Por ejemplo:

fxc.exe /T rootsig_1_1 MyRS1.hlsl /E MyRS1 /Fo MyRS1.fxo

Tenga en cuenta que la definición de la cadena de firma raíz también se puede pasar en la línea de comandos, por ejemplo, /D MyRS1="...".

Manipulación de firmas raíz con el compilador FXC

El compilador FXC crea código de bytes del sombreador a partir de archivos de código fuente HLSL. Hay muchos parámetros opcionales para este compilador, consulte la herramienta Effect-Compiler.

Para administrar firmas raíz creadas por HLSL, en la tabla siguiente se proporcionan algunos ejemplos de uso de FXC.

Línea Línea de comandos Descripción
1 fxc /T ps_5_1 shaderWithRootSig.hlsl /Fo rs1.fxo Compila un sombreador para el destino 5.1 del sombreador de píxeles, el origen del sombreador se encuentra en el archivo shaderWithRootSig.hlsl, que incluye una firma raíz. El sombreador y la firma raíz se compilan como blobs independientes en el archivo binario rs1.fxo.
2 fxc /dumpbin rs1.fxo /extractrootsignature /Fo rs1.rs.fxo Extrae la firma raíz del archivo creado por la línea 1, por lo que el archivo rs1.rs.fxo contiene solo una firma raíz.
3 fxc /dumpbin rs1.fxo /Qstrip_rootsignature /Fo rs1.stripped.fxo Quita la firma raíz del archivo creado por la línea 1, por lo que el archivo rs1.stripped.fxo contiene un sombreador sin firma raíz.
4 fxc /dumpbin rs1.stripped.fxo /setrootsignature rs1.rs.fxo /Fo rs1.new.fxo Combina un sombreador y una firma raíz que están en archivos independientes en un archivo binario que contiene ambos blobs. En este ejemplo rs1.new.fx0 sería idéntico a rs1.fx0 en la línea 1.
5 fxc /T rootsig_1_0 rootSigAndMaybeShaderInHereToo.hlsl /E RS1 /Fo rs2.fxo Crea un archivo binario de firma raíz independiente a partir de un origen que puede contener más que una firma raíz. Observe el destino rootsig_1_0 y que RS1 es el nombre de la cadena de macro de firma raíz (#define) en el archivo HLSL.

 

La funcionalidad disponible a través de FXC también está disponible mediante programación mediante la función D3DCompile . Esta llamada compila un sombreador con una firma raíz o una firma raíz independiente (estableciendo el destino rootsig_1_0). D3DGetBlobPart y D3DSetBlobPart pueden extraer y adjuntar firmas raíz a un blob existente.  D3D_BLOB_ROOT_SIGNATURE se usa para especificar el tipo de elemento de blob de firma raíz. D3DStripShader quita la firma raíz (mediante la marca D3DCOMPILER_STRIP_ROOT_SIGNATURE) del blob.

Notas

Nota

Mientras que la compilación sin conexión de sombreadores se recomienda encarecidamente, si los sombreadores deben compilarse en tiempo de ejecución, consulte los comentarios de D3DCompile2.

 

Nota

No es necesario cambiar los recursos de HLSL existentes para controlar las firmas raíz que se van a usar con ellos.

 

Indexado dinámico mediante HLSL 5.1

Características del sombreador HLSL 5.1 para Direct3D 12

Enlace de recursos

Enlace de recursos en HLSL

Firmas raíz

Modelo de sombreador 5.1

Valor de la referencia de galería de símbolos especificado por el sombreador

Cargas de vistas de acceso sin ordenar con tipo