¿Por qué es tan importante la seguridad de subprocesos para las API de gráficos?

21

Se afirma que tanto Vulkan como DirectX12 se pueden usar de manera segura para subprocesos. La gente parece estar entusiasmada con eso.

¿Por qué se considera esto una característica tan grande? El procesamiento "real" se lanza sobre el puente de memoria en una unidad de procesamiento separada de todos modos.

Además, si es tan grande, ¿por qué no es hasta ahora que salió una API de gráficos segura para subprocesos?

monstruo de trinquete
fuente
Este artículo está mucho más "centrado en el jugador", pero podría darle algunas ideas ... pcgamer.com/what-directx-12-means-for-gamers-and-developers
glampert

Respuestas:

13

La principal ganancia sería que sería más fácil dividir las tareas de la CPU en múltiples subprocesos, sin tener que resolver todos los problemas difíciles con el acceso a la API de gráficos. Normalmente, tendría que actualizar el contexto (lo que podría tener implicaciones de mal rendimiento) o proporcionar una cola y llamar a la API de gráficos en un solo hilo. No creo que se obtenga ningún rendimiento de esta manera, porque la GPU de hecho los procesa secuencialmente de todos modos, pero hace que el trabajo del desarrollador sea mucho más fácil.

La razón por la que no se hizo hasta ahora probablemente se deba a que directx y opengl se crearon en un momento en el que el subprocesamiento múltiple no era realmente aparente. Además, el tablero de Khronos es muy conservador al cambiar la API. Su punto de vista sobre Vulkan también es que coexistirá junto a OpenGL, porque ambos sirven para diferentes propósitos. Probablemente no fue hasta hace poco que el paralismo se volvió tan importante, ya que los consumidores tienen acceso a más y más procesadores.

EDITAR: No me refiero a que no se obtiene rendimiento al trabajar en múltiples CPU, no es útil dividir sus llamadas en múltiples hilos para crear texturas / sombreadores más rápido. Más bien, el rendimiento se obtiene debido a que hay más procesadores ocupados y a mantener a la gpu ocupada con cosas para realizar.

Maurice Laveaux
fuente
1
Como nota adicional, OpenGL generalmente solo funciona en un hilo, por lo que una aplicación de gráficos intensivos podría maximizar un núcleo. Algo así como Vulkan permite que varios subprocesos envíen comandos a una cola, lo que significa que se pueden realizar muchas llamadas de gráficos desde múltiples subprocesos.
Jabonosa
9

Se necesita mucho trabajo en la CPU para configurar un marco para la GPU, y una buena parte de ese trabajo está dentro del controlador de gráficos. Antes de DX12 / Vulkan, el diseño de la API obligaba esencialmente a que el trabajo del controlador de gráficos tuviera un solo subproceso.

La esperanza es que DX12 / Vulkan levante esa restricción, permitiendo que el trabajo del controlador se realice en paralelo en múltiples hilos de CPU dentro de un marco. Esto permitirá un uso más eficiente de las CPU multinúcleo, lo que permitirá a los motores de los juegos impulsar escenas más complejas sin comprometerse con la CPU. Esa es la esperanza: si se realizará en la práctica es algo que tendremos que esperar para ver en los próximos años.

Para elaborar un poco: la salida de un procesador de juego es una secuencia de llamadas API DX / GL que describen la secuencia de operaciones para representar un marco. Sin embargo, hay una gran distancia entre el flujo de llamadas API y los búferes de comandos binarios reales que consume el hardware de la GPU. El controlador tiene que "compilar" las llamadas API en el lenguaje de máquina de la GPU, por así decirlo. Ese no es un proceso trivial: implica una gran cantidad de traducción de conceptos de API a realidades de hardware de bajo nivel, validación para asegurarse de que la GPU nunca se establece en un estado no válido, disputas de asignaciones de memoria y datos, seguimiento de cambios de estado para emitir el comandos correctos de bajo nivel, y así sucesivamente. El controlador de gráficos es responsable de todo esto.

En DX11 / GL4 y API anteriores, este trabajo generalmente lo realiza un solo subproceso de controlador. Incluso si llama a la API desde varios subprocesos (lo que puede hacer usando las listas de comandos diferidos DX11, por ejemplo), simplemente agrega algo de trabajo a una cola para que el subproceso del controlador lo mastique más tarde. Una gran razón para esto es el seguimiento del estado que mencioné antes. Muchos de los detalles de configuración de GPU a nivel de hardware requieren conocer el estado actual de la canalización de gráficos, por lo que no hay una buena manera de dividir la lista de comandos en fragmentos que puedan procesarse en paralelo: cada fragmento tendría que saber exactamente en qué estado debe comenzar con, a pesar de que el fragmento anterior aún no se ha procesado.

Esa es una de las grandes cosas que cambió en DX12 / Vulkan. Por un lado, incorporan casi todos los estados de canalización de gráficos en un objeto, y para otro (al menos en DX12) cuando comienza a crear una lista de comandos, debe proporcionar un estado de canalización inicial; el estado no se hereda de una lista de comandos a la siguiente. En principio, esto permite que el controlador no tenga que saber nada sobre las listas de comandos anteriores antes de que pueda comenzar a compilar, y eso a su vez permite que la aplicación divida su representación en fragmentos paralelizables, produciendo listas de comandos completamente compiladas, que luego pueden ser compiladas. concatenados juntos y enviados a la GPU con un mínimo de alboroto.

Por supuesto, hay muchos otros cambios en las nuevas API, pero en lo que respecta al subprocesamiento múltiple, esa es la parte más importante.

Nathan Reed
fuente
5

Las GPU modernas generalmente tienen una única sección de interfaz que procesa una secuencia completamente lineal de comandos desde la CPU. Es discutible si este es un diseño de hardware natural o si simplemente evolucionó a partir de los días en que había un solo núcleo que generaba comandos de CPU para la GPU, pero es la realidad por ahora. Entonces, si genera una sola secuencia lineal de comandos con estado, ¡por supuesto, tiene sentido generar esa secuencia linealmente en un solo hilo en la CPU! ¿Correcto?

Bueno, las GPU modernas también generalmente tienen un backend unificado muy flexible que puede funcionar en muchas cosas diferentes a la vez. En términos generales, la GPU funciona en vértices y píxeles con granularidad bastante fina. No hay mucha diferencia entre una GPU que procesa 1024 vértices en un dibujo y 512 + 512 vértices en dos dibujos diferentes.

Eso sugiere una forma bastante natural de hacer menos trabajo: en lugar de arrojar una gran cantidad de vértices a la GPU en una sola llamada de sorteo, divida su modelo en secciones, elimine groseras en esas secciones y envíe cada fragmento individualmente si pasa el prueba de sacrificio ¡Si lo haces con la granularidad correcta, deberías obtener una buena aceleración!

Desafortunadamente, en la realidad actual de la API de gráficos, las llamadas de extracción son extremadamente caras en la CPU. Una explicación simplificada de por qué: los cambios de estado en la GPU pueden no corresponder directamente a las llamadas a la API de gráficos, por lo que muchas llamadas a la API de gráficos simplemente establecen algún estado dentro del controlador, y la llamada de sorteo que dependería de este nuevo estado va y analiza todos los estado que está marcado como cambiado desde el último sorteo, lo escribe en la secuencia de comandos para la GPU y luego inicia el sorteo. Todo este trabajo se realiza en un intento de obtener una secuencia de comandos ligera y media para la unidad de interfaz de GPU.

Lo que se reduce a esto es que tiene un presupuesto para llamadas de extracción que está totalmente impuesto por los gastos generales del conductor . (Creo que escuché que en estos días puedes salirte con alrededor de 5,000 por fotograma para un título de 60 FPS). Puedes aumentar eso en un gran porcentaje construyendo esta secuencia de comandos en fragmentos paralelos.

También hay otras razones (por ejemplo, distorsión de tiempo asíncrona para las mejoras de latencia de realidad virtual), pero esta es una gran razón para los juegos vinculados a gráficos y otros softwares pesados ​​(como los paquetes de modelado 3D).

John Calsbeek
fuente