Información general sobre los montones de descriptores

Los montones de descriptores contienen muchos tipos de objetos que no forman parte de un objeto de estado de canalización (PV), como vistas de recursos de sombreador (SRV), vistas de acceso sin ordenar (UMV), vistas de búfer de constantes (CBV) y samplers.

El propósito de los montones de descriptores

El propósito principal de un montón de descriptores es abarcar la mayor parte de la asignación de memoria necesaria para almacenar las especificaciones de descriptor de tipos de objeto a las que hacen referencia los sombreadores para un tamaño tan grande de una ventana de representación como sea posible (idealmente un marco completo de representación o más). Si una aplicación cambia las texturas que la canalización ve rápidamente desde la API, debe haber espacio en el montón del descriptor para definir tablas de descriptores sobre la marcha para cada conjunto de estados necesario. La aplicación puede optar por reutilizar definiciones si los recursos se usan de nuevo en otro objeto, por ejemplo, o simplemente asignar el espacio del montón secuencialmente a medida que cambia varios tipos de objetos.

Los montones de descriptores también permiten que los componentes de software individuales administren el almacenamiento de descriptores por separado entre sí.

Todos los montones son visibles para la CPU. La aplicación también puede solicitar qué propiedades de acceso a la CPU debe tener un montón de descriptores (si existe): escritura combinada, reescritura, etc. Las aplicaciones pueden crear tantos montones de descriptores como desee con las propiedades deseadas. Las aplicaciones siempre tienen la opción de crear montones de descriptores que son exclusivamente para fines de almacenamiento provisional sin restricciones de tamaño y copiar en montones de descriptores que se usan para representarlos según sea necesario.

Hay algunas restricciones en lo que puede ir en el mismo montón de descriptores. Las entradas CBV, UAV y SRV pueden estar en el mismo montón de descriptores. Sin embargo, las entradas samplers no pueden compartir un montón con entradas CBV, UAV o SRV. Normalmente, hay dos conjuntos de montones de descriptores, uno para los recursos comunes y el segundo para Samplers.

El uso de montones de descriptores de Direct3D 12 refleja lo que hace la mayoría del hardware de GPU, que es requerir descriptores que solo residen en montones de descriptores, o simplemente que se necesitan menos bits de direccionamiento si se usan estos montones. Direct3D 12 requiere el uso de montones de descriptores, no hay ninguna opción para colocar descriptores en cualquier parte de la memoria.

Los montones de descriptores solo se pueden editar inmediatamente mediante la CPU, no hay ninguna opción para editar un montón de descriptores mediante la GPU.

Synchronization

El contenido del montón de descriptores se puede cambiar antes, durante y después de grabar listas de comandos que hacen referencia a él. Sin embargo, los descriptores no se pueden cambiar mientras una lista de comandos enviada para su ejecución podría hacer referencia a esa ubicación, ya que esto podría invocar una condición de carrera.

Enlace

Como máximo, un montón combinado CBV/SRV/UAV y un montón de sampler se puede enlazar en cualquier momento. Estos montones se comparten entre las canalizaciones de gráficos y proceso (descritas en sus SPO).

Cambio de montones

Es aceptable que una aplicación cambie los montones dentro de la misma lista de comandos o en diferentes mediante las API SetDescriptorHeaps y Reset . En algún hardware, esto puede ser una operación costosa, lo que requiere una detención de GPU para vaciar todo el trabajo que depende del montón de descriptores enlazados actualmente. Como resultado, si se deben cambiar los montones de descriptores, las aplicaciones deben intentar hacerlo cuando la carga de trabajo de GPU sea relativamente ligera, quizás limitando los cambios al inicio de una lista de comandos.

Agrupaciones

Con las agrupaciones solo puede haber una llamada al método SetDescriptorHeaps y los montones de descriptores establecidos deben coincidir exactamente con los de la lista de comandos que llama a la agrupación. Si la agrupación no cambia las tablas de descriptores, no es necesario establecer los montones de descriptores.

Para obtener una lista de llamadas API que no se pueden usar con agrupaciones, consulte Creación y grabación de listas de comandos y agrupaciones.

Administración

Para representar todos los objetos de una escena, se necesitarán muchos descriptores y hay algunas estrategias de administración diferentes que se pueden seguir.

La estrategia más básica sería rellenar un área nueva del montón de descriptores con todos los requisitos para la siguiente llamada a draw. Por lo tanto, justo antes de emitir la llamada draw en la lista de comandos, un puntero de tabla descriptor se establecería en el inicio de la tabla recién rellenada. El revés es que no es necesario registrar dónde se encuentra ningún descriptor determinado en el montón.

El inconveniente de esta estrategia es que podría haber una gran repetición de descriptores en el montón de descriptores, especialmente cuando se representa una escena muy similar, y ese espacio de montón de descriptores se va a usar rápidamente. Es probable que sea necesario separar los montones de descriptores para los que se representan en la GPU y para los registrados por la CPU para evitar conflictos. Como alternativa, se podría usar un sistema de subasignación.

Además, el sistema básico podría optimizarse aún más mediante el uso cuidadoso de tablas de descriptores superpuestas de una llamada de dibujo a la siguiente, de modo que solo se agreguen los nuevos descriptores necesarios.

Una estrategia más eficaz que la básica sería rellenar previamente los montones de descriptores con descriptores necesarios para los objetos (o materiales) que se sabe que forman parte de la escena. La idea aquí es que solo es necesario establecer la tabla de descriptores en tiempo de dibujo, ya que el montón del descriptor se rellena con antelación.

Una variación de la estrategia de relleno previo es tratar el montón del descriptor como una matriz enorme, que contiene todos los descriptores necesarios en ubicaciones conocidas fijas. A continuación, la llamada a draw solo necesita recibir un conjunto de constantes que son los índices en la matriz de donde se deben usar los descriptores.

Una optimización adicional consiste en garantizar que las constantes raíz y los descriptores raíz contengan aquellos que cambian con más frecuencia, en lugar de colocar constantes en el montón del descriptor. Para la mayoría del hardware, esta es una manera eficaz de controlar constantes.

En la práctica, un motor de gráficos podría usar una estrategia diferente en diferentes situaciones y combinar elementos de cada estrategia para adaptarse a los requisitos de dibujo concretos.

Montones de descriptores