Versión 1.1 de la firma raíz

El propósito de la versión 1.1 de la firma raíz es permitir que las aplicaciones indiquen a los controladores cuando los descriptores de un montón de descriptores no cambien o los descriptores de datos apunten a que no cambiarán. Esto permite que los controladores realicen optimizaciones que podrían ser posibles sabiendo que un descriptor o la memoria a la que apunta es estático durante algún período de tiempo.

Información general

La versión 1.0 de la firma raíz permite cambiar libremente el contenido de los montones de descriptores y la memoria a la que apuntan libremente las aplicaciones en cualquier momento en que las listas o agrupaciones de comandos que hacen referencia a ellos están potencialmente en curso en la GPU. Sin embargo, con mucha frecuencia, las aplicaciones no necesitan realmente la flexibilidad de cambiar los descriptores o la memoria después de que se hayan registrado los comandos que hacen referencia a ellos.

Las aplicaciones suelen ser trivialmente capaces de:

  • Configure descriptores (y posiblemente la memoria a la que apuntan) antes de enlazar tablas descriptores o descriptores raíz en una lista o agrupación de comandos.
  • Asegúrese de que estos descriptores no cambiarán hasta que la lista de comandos /bundles haga referencia a ellos haya terminado de ejecutarse por última vez.
  • Asegúrese de que los datos a los que apuntan los descriptores no cambian durante la misma duración completa.

Como alternativa, una aplicación solo puede respetar que los datos no cambien durante un tiempo más corto. En concreto, los datos pueden ser estáticos para la ventana en el tiempo durante la ejecución de la lista de comandos que un enlace de parámetros raíz (tabla descriptor o descriptor raíz) apunta actualmente a los datos. Es decir, es posible que una aplicación quiera realizar la ejecución en la escala de tiempo de GPU que actualiza algunos datos entre períodos de tiempo en los que se establece a través de un parámetro raíz, sabiendo que cuando se establece será estático.

Si los descriptores o los descriptores de datos apuntan a, no cambiarán, los controladores de optimización específicos pueden ser específicos del proveedor de hardware y, lo que es importante, no cambian el comportamiento que no sea posiblemente mejorar el rendimiento. Conservar tanto conocimiento sobre la intención de la aplicación como sea posible no supone una carga en las aplicaciones.

Una optimización es que muchos controladores pueden producir accesos de memoria más eficientes por parte de los sombreadores si conocen las promesas que una aplicación puede realizar sobre la estática de descriptores y datos. Por ejemplo, los controladores podrían quitar un nivel de direccionamiento indirecto para acceder a un descriptor en un montón convirtiéndolo en un descriptor raíz si el hardware concreto no es sensible al tamaño del argumento raíz.

La tarea adicional para desarrolladores que usa la versión 1.1 es hacer promesas sobre la volatilidad y la estática de los datos siempre que sea posible, para que los controladores puedan hacer las optimizaciones que tienen sentido. Los desarrolladores no tienen que hacer ninguna promesa sobre la estática.

La versión 1.0 de la firma raíz sigue funcionando sin cambios, aunque las aplicaciones que vuelvan a compilar las firmas raíz tendrán como valor predeterminado La firma raíz 1.1 ahora (con una opción para forzar la versión 1.0 si lo desea).

Marcas estáticas y volátiles

Las marcas siguientes forman parte de la firma raíz para permitir que los controladores elijan una estrategia para controlar mejor los argumentos raíz individuales cuando se establecen, e inserten también las mismas suposiciones en objetos de estado de canalización (PSO) cuando se compilan originalmente, ya que la firma raíz forma parte de un ARCHIVO.

La aplicación establece las marcas siguientes y se aplica a descriptores o datos.

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

Con este conjunto de marcas, la aplicación puede cambiar los descriptores de un montón de descriptores a los que apunta una tabla de descriptores raíz en cualquier momento, excepto mientras la lista de comandos o agrupaciones que enlazan la tabla descriptor se han enviado y no han terminado de ejecutarse. Por ejemplo, la grabación de una lista de comandos y el cambio posterior de descriptores en un montón de descriptores al que hace referencia antes de enviar la lista de comandos para su ejecución es válida. Este es el único comportamiento admitido de la versión 1.0 de la firma raíz.

Si no se establece la marca DESCRIPTORS_VOLATILE, los descriptores son estáticos. No hay ninguna marca para este modo. Los descriptores estáticos significan que los descriptores de un montón de descriptores señalados por una tabla de descriptores raíz se han inicializado en el momento en que la tabla descriptor se establece en una lista o agrupación de comandos (durante la grabación), y los descriptores no se pueden cambiar hasta que la lista de comandos o el lote haya terminado de ejecutarse por última vez. Para la versión 1.1 de la firma raíz, los descriptores estáticos son la suposición predeterminada y la aplicación tiene que especificar la marca DESCRIPTORS_VOLATILE cuando sea necesario.

En el caso de las agrupaciones que usan tablas de descriptores con descriptores estáticos, los descriptores deben estar listos a partir del momento en que se registra la agrupación (en lugar de cuando se llama a la agrupación) y no cambian hasta que la agrupación haya terminado de ejecutarse por última vez. Las tablas descriptores que apuntan a descriptores estáticos deben establecerse durante la grabación de agrupación y no heredar en la agrupación. Es válido para que una lista de comandos use una tabla descriptor con descriptores estáticos que se han establecido en un lote y se devuelvan a la lista de comandos.

Cuando los descriptores son estáticos, hay otro cambio en el comportamiento que requiere que se establezca la marca DESCRIPTORS_VOLATILE. Los accesos fuera de los límites a las vistas de búfer (en lugar de las vistas Texture1D/2D/3D/Cube) no son válidos y generan resultados no definidos, incluido el posible restablecimiento del dispositivo, en lugar de devolver valores predeterminados para lecturas o quitar escrituras. El propósito de quitar la capacidad de las aplicaciones de depender del hardware fuera de la comprobación de acceso de los límites es permitir que los controladores elijan promover accesos de descriptor estáticos a accesos de descriptores raíz si consideran que son más eficaces. Los descriptores raíz no admiten ninguna comprobación fuera de los límites.

Si las aplicaciones dependen de un comportamiento de acceso a memoria delimitado seguro al acceder a descriptores, deben marcar los intervalos de descriptores que acceden a esos descriptores como DESCRIPTORS_VOLATILE.

DATA_VOLATILE

Con este conjunto de marcas, la CPU puede cambiar los datos a los que apuntan los descriptores en cualquier momento, excepto mientras la lista de comandos o agrupaciones que enlazan la tabla de descriptores se han enviado y no han terminado de ejecutarse. Este es el único comportamiento admitido de la versión 1.0 de la firma raíz.

La marca está disponible en las marcas de intervalo de descriptores y en las marcas de descriptor raíz.

DATA_STATIC_WHILE_SET_AT_EXECUTE

Con este conjunto de marcas, los datos a los que apuntan los descriptores no pueden cambiar a partir de cuando la tabla de descriptores o descriptores raíz subyacente se establece en una lista o agrupación de comandos durante la ejecución en la escala de tiempo de GPU y finaliza cuando los posteriores draws/dispatches ya no harán referencia a los datos.

Antes de establecer un descriptor raíz o una tabla de descriptores en la GPU, estos datos se pueden cambiar incluso mediante la misma lista o agrupación de comandos. Los datos también se pueden cambiar mientras que una tabla de descriptores o descriptores raíz que apunta a ellos sigue estando establecida en la lista de comandos o agrupación, siempre y cuando se hayan completado las referencias a draw/dispatches. Sin embargo, para ello es necesario que la tabla descriptor se vuelva a enlazar a la lista de comandos antes de la próxima vez que se desreferencia el descriptor raíz o la tabla de descriptores. Esto permite al controlador saber que los datos a los que apunta un descriptor raíz o una tabla descriptor han cambiado.

La diferencia esencial entre DATA_STATIC_WHILE_SET_AT_EXECUTE y DATA_VOLATILE es DATA_VOLATILE un controlador no puede saber si las copias de datos de una lista de comandos han cambiado los datos a los que apunta un descriptor, sin realizar un seguimiento de estado adicional. Por lo tanto, si, por ejemplo, un controlador puede insertar cualquier tipo de comandos de captura previa de datos en su lista de comandos (para que el sombreador tenga acceso a los datos conocidos, por ejemplo), DATA_STATIC_WHILE_SET_AT_EXECUTE permite al controlador saber que solo necesita realizar la captura previa de datos en el momento en que se establece mediante SetGraphicsRootDescriptorTable, SetComputeRootDescriptorTable o uno de los métodos para establecer la vista de búfer constante, vista de recursos del sombreador o vista de acceso desordenado.

En el caso de las agrupaciones, la promesa de que los datos son estáticos mientras se establecen en la ejecución se aplican de forma única a cada ejecución de la agrupación.

La marca está disponible en las marcas de intervalo de descriptores y en las marcas de descriptor raíz.

DATA_STATIC

Si se establece esta marca, los datos a los que apuntan los descriptores se han inicializado en el momento en que un descriptor raíz o una tabla descriptor que hace referencia a la memoria se ha establecido en una lista de comandos o agrupación durante la grabación, y los datos no se pueden cambiar hasta que la lista o agrupación de comandos haya terminado de ejecutarse por última vez.

En el caso de las agrupaciones, la duración estática se inicia en la configuración de la tabla descriptor o descriptor raíz durante la grabación de la agrupación, en lugar de en la grabación de una lista de comandos que llama. Además, una tabla de descriptores que apunte a datos estáticos debe establecerse en la agrupación y no heredar. Es válido para que una lista de comandos use una tabla descriptor que apunte a datos estáticos que se han establecido en una agrupación y que se devuelvan a la lista de comandos.

La marca está disponible en las marcas de intervalo de descriptores y en las marcas de descriptor raíz.

Combinación de marcas

Como máximo, se puede especificar una de las marcas DATA a la vez, excepto los intervalos de descriptores de Sampler que no admiten marcas DATA en absoluto, ya que los muestreadores no apuntan a datos.

La ausencia de las marcas DATA para los intervalos de descriptores SRV y CBV significa que se supone un valor predeterminado de DATA_STATIC_WHILE_SET_AT_EXECUTE comportamiento. La razón por la que se elige este valor predeterminado en lugar de DATA_STATIC es que DATA_STATIC_WHILE_SET_AT_EXECUTE es mucho más probable que sea un valor predeterminado seguro para la mayoría de los casos, a la vez que se produce una oportunidad de optimización mejor que la predeterminada para DATA_VOLATILE.

La ausencia de marcas data para los intervalos de descriptores UAV significa que se supone un valor predeterminado de DATA_VOLATILE comportamiento, dado que normalmente se escriben uaV.

DESCRIPTORS_VOLATILE no se pueden combinar con DATA_STATIC, pero se pueden combinar con las otras marcas DATA. El motivo por el que DESCRIPTORS_VOLATILE se puede combinar con DATA_STATIC_WHILE_SET_AT_EXECUTE es que los descriptores volátiles todavía requieren que los descriptores estén listos durante la ejecución de la lista o agrupación de comandos, y DATA_STATIC_WHILE_SET_AT_EXECUTE solo realiza promesas sobre la estática en un subconjunto de la ejecución de la lista o agrupación de comandos.

Resumen de marcas

En las tablas siguientes se resumen las combinaciones de marcas que podrían emplearse.

Configuración de D3D12_DESCRIPTOR_RANGE_FLAGS válida Descripción
No se estableció ninguna marca Los descriptores son estáticos (el valor predeterminado). Suposiciones predeterminadas para los datos: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE y para UAV: DATA_VOLATILE. Estos valores predeterminados para SRV/CBV se ajustarán de forma segura a los patrones de uso de la mayoría de las firmas raíz.
DATA_STATIC Tanto los descriptores como los datos son estáticos. Esto maximiza el potencial de optimización de controladores.
DATA_VOLATILE Los descriptores son estáticos y los datos son volátiles.
DATA_STATIC_WHILE_SET_AT_EXECUTE Los descriptores son estáticos y los datos son estáticos mientras se establecen en ejecución.
DESCRIPTORS_VOLATILE Los descriptores son volátiles y se realizan suposiciones predeterminadas sobre los datos: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE y para UAV: DATA_VOLATILE.
DESCRIPTORS_VOLATILE | DATA_VOLATILE Tanto los descriptores como los datos son volátiles, equivalentes a La firma raíz 1.0.
DESCRIPTORS_VOLATILE | DATA_STATIC_WHILE_SET_AT_EXECUTE Los descriptores son volátiles, pero tenga en cuenta que aún no les permite cambiar durante la ejecución de la lista de comandos. Por lo tanto, es válido combinar la declaración adicional de que los datos son estáticos mientras se establecen a través de la tabla de descriptores raíz durante la ejecución; los descriptores subyacentes son realmente estáticos durante más tiempo que los datos se prometen como estáticos.

 

Configuración de D3D12_ROOT_DESCRIPTOR_FLAGS válida Descripción
No se estableció ninguna marca Suposiciones predeterminadas para los datos: para SRV/CBV: DATA_STATIC_WHILE_SET_AT_EXECUTE y para UAV: DATA_VOLATILE. Estos valores predeterminados para SRV/CBV se ajustarán de forma segura a los patrones de uso de la mayoría de las firmas raíz.
DATA_STATIC Los datos son estáticos, el mejor potencial para la optimización de controladores.
DATA_STATIC_WHILE_SET_AT_EXECUTE Los datos son estáticos mientras se establecen en ejecución.
DATA_VOLATILE Equivalente a La firma raíz 1.0.

 

Resumen de la API de la versión 1.1

Las siguientes llamadas API habilitan la versión 1.1.

Enumeraciones

Estas enumeraciones contienen las marcas clave para especificar la volatilidad de los datos y descriptores.

Estructuras

Las estructuras actualizadas (de la versión 1.0) contienen referencias a las marcas de volatilidad/estáticas.

Functions

Los métodos enumerados aquí reemplazan las funciones D3D12SerializeRootSignature y D3D12CreateRootSignatureDeserializer originales, ya que están diseñadas para funcionar en cualquier versión de la firma raíz. El formulario serializado es lo que se pasa a createRootSignature API. Si se ha creado un sombreador con una firma raíz en él, el sombreador compilado contendrá una firma raíz serializada en ella.

Métodos

La interfaz ID3D12VersionedRootSignatureDeserializer se crea para deserializar la estructura de datos de firma raíz.

Estructuras auxiliares

Se han agregado estructuras auxiliares para ayudar en la inicialización de algunas de las estructuras de la versión 1.1.

  • CD3DX12_DESCRIPTOR_RANGE1
  • CD3DX12_ROOT_PARAMETER1
  • CD3DX12_STATIC_SAMPLER1
  • CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC

Consulte Estructuras y funciones auxiliares para D3D12.

Consecuencias de infringir las marcas de static-ness

El descriptor y las marcas de datos descritas anteriormente (así como los valores predeterminados implícitos en la ausencia de marcas concretas) definen una promesa por parte de la aplicación al controlador sobre cómo se va a comportar. Si una aplicación infringe la promesa, este comportamiento no es válido: los resultados no están definidos y pueden ser diferentes en distintos controladores y hardware.

La capa de depuración tiene opciones para validar que las aplicaciones respetan sus promesas, incluidas las promesas predeterminadas que se incluyen con la versión 1.1 de la firma raíz sin establecer ninguna marca.

Administración de versiones

Al compilar firmas raíz asociadas a sombreadores, los compiladores HLSL más recientes solo admiten la versión 1.0 para compilar la firma raíz en la versión 1.1, mientras que los compiladores HLSL antiguos solo admiten la versión 1.0. Tenga en cuenta que las firmas raíz 1.1 no funcionarán en los sistemas operativos que no admiten la firma raíz 1.1.

La versión de firma raíz compilada con un sombreador se puede forzar a una versión determinada mediante /force_rootsig_ver <version>. Forzar la versión se realizará correctamente si el compilador puede conservar el comportamiento de la firma raíz que se compila en la versión forzada, por ejemplo, quitando marcas no admitidas en la firma raíz que solo sirven con fines de optimización, pero no afectan al comportamiento.

De este modo, una aplicación puede, por ejemplo, compilar una firma raíz 1.1 en 1.0 y 1.1 al compilar la aplicación y seleccionar la versión adecuada en tiempo de ejecución en función del nivel de compatibilidad del sistema operativo. Sin embargo, sería más eficaz el espacio para que una aplicación compile firmas raíz individualmente (especialmente si se necesitan varias versiones), independientemente de los sombreadores. Incluso si los sombreadores no se compilan inicialmente con una firma raíz asociada, la ventaja de la validación del compilador de compatibilidad de firma raíz con un sombreador se puede conservar mediante la /verifyrootsignature opción del compilador. Más adelante en tiempo de ejecución, se pueden crear PSO mediante sombreadores que no tienen firmas raíz en ellas mientras se pasa la firma raíz deseada (quizás la versión adecuada compatible con el sistema operativo) como parámetro independiente.

Creación de una firma raíz

Firmas raíz

Especificación de firmas de raíz en HLSL