performance - overdraw - unity optimize scene
¿Por qué las llamadas al sorteo son caras? (3)
En primer lugar, supongo que con "llamar llamadas", te refieres al comando que le dice a la GPU que represente un cierto conjunto de vértices como triángulos con un cierto estado (sombreadores, estado de mezcla, etc.).
Las llamadas al sorteo no son necesariamente costosas. En las versiones anteriores de Direct3D, muchas llamadas requerían un cambio de contexto, que era costoso, pero esto no es cierto en las versiones más recientes.
La razón principal para hacer menos llamadas al sistema es que el hardware de gráficos puede transformar y representar triángulos mucho más rápido de lo que puede enviarlos. Si envía pocos triángulos con cada llamada, quedará completamente limitado por la CPU y la GPU estará prácticamente inactiva. La CPU no podrá alimentar la GPU lo suficientemente rápido.
Hacer una sola llamada a un sorteo con dos triángulos es barato, pero si envía muy pocos datos con cada llamada, no tendrá suficiente tiempo de CPU para enviar tanta geometría a la GPU como podría haberlo hecho.
Hay algunos costos reales al realizar llamadas, requiere configurar un montón de estado (qué conjunto de vértices usar, qué sombreado usar y demás) y los cambios de estado tienen un costo tanto en el hardware (actualizando un montón de registros) y en el lado del conductor (validar y traducir sus llamadas que establecen el estado).
Pero las principales llamadas al costo de sorteo solo se aplican si cada llamada presenta muy pocos datos , ya que esto hará que se limite a la CPU y le impida utilizar el hardware por completo.
Al igual que dijo Josh, las llamadas al sorteo también pueden hacer que se vacíe el búfer de comando, pero en mi experiencia eso suele suceder cuando llamas a SwapBuffers, no cuando envías geometría. Por lo general, los controladores de video intentan almacenar tanto como puedan (con algunos fotogramas a veces) para extraer todo el paralelismo posible de la GPU.
¡Debería leer la presentación de nVidia Batch Batch Batch! , es bastante viejo pero cubre exactamente este tema.
suponiendo que los datos de textura, vértice y sombreado ya están en la tarjeta gráfica, no necesita enviar demasiados datos a la tarjeta. hay unos pocos bytes para identificar los datos, y presumiblemente una matriz de 4x4, y algunos otros parámetros surtidos.
Entonces, ¿de dónde vienen todos los gastos generales? ¿las operaciones requieren un apretón de manos de algún tipo con el gpu?
¿Por qué enviar una malla única que contiene un grupo de modelos pequeños, calculados en la CPU, a menudo más rápido que enviar las matrices de id y de transformación de vértice? (la segunda opción parece que debería haber menos datos enviados, a menos que los modelos sean más pequeños que una matriz de 4x4)
Las API de gráficos como Direct3D traducen sus llamadas de nivel API en comandos independientes del dispositivo y los ponen en cola en un búfer. Enjuagar ese buffer, para realizar el trabajo real, es costoso, tanto porque implica que ahora se está realizando el trabajo real, y porque puede incurrir en un cambio de usuario a modo kernel en el chip (y viceversa), que no es eso barato.
Hasta que se vacíe el búfer, la GPU puede realizar algunos trabajos de preparación en paralelo con la CPU, siempre que la CPU no realice una solicitud de bloqueo (como asignar datos a la CPU). Pero la GPU no preparará -y no puede- todo hasta que realmente necesite dibujar. El hecho de que algunos datos de vértices o texturas estén en la tarjeta no significa que estén arreglados apropiadamente todavía, y pueden no ser arreglables hasta que los diseños de vértices estén establecidos o los sombreadores estén vinculados, etcétera. La mayor parte del trabajo real ocurre durante el comando de vaciado y extracción de llamadas.
El SDK de DirectX tiene una sección sobre cómo perfilar con precisión el rendimiento de D3D que, aunque no está directamente relacionado con su pregunta, puede proporcionar algunas pistas sobre lo que es y no es caro y (en algunos casos) por qué.
Más relevante es esta publicación de blog (y las publicaciones de seguimiento here y here ), que proporcionan una buena visión general del proceso operativo lógico de bajo nivel de la GPU.
Pero, esencialmente (para intentar responder directamente a sus preguntas), la razón por la que las llamadas son costosas no es que haya necesariamente una gran cantidad de datos para transferir, sino que existe un gran volumen de trabajo más allá del envío de datos a través del bus. eso se difiere hasta que se vacía el búfer de comando.
Respuesta corta: el controlador almacena una parte o la totalidad del trabajo real hasta que llame al sorteo. Esto se mostrará como una cantidad relativamente predecible de tiempo invertido en la llamada al sorteo, dependiendo de cuánto ha cambiado el estado.
Esto se hace por algunas razones:
- para evitar hacer un trabajo innecesario: si (innecesariamente) establece el mismo estado varias veces antes de dibujar, puede evitar hacer un trabajo costoso cada vez que esto ocurra. Esto realmente se convierte en una ocurrencia bastante común en una gran base de código, digamos un motor de juego de producción.
- ser capaz de conciliar lo que internamente son estados interdependientes en lugar de procesarlos inmediatamente con información incompleta
Respuesta (s) alternativa (s):
- El búfer que el controlador usa para almacenar los comandos de representación está lleno y la aplicación está efectivamente esperando que la GPU procese parte del trabajo anterior. Esto generalmente se mostrará como bloqueos de tiempo extremadamente grandes en una llamada al azar dentro de un marco.
- Se ha alcanzado el número de fotogramas que el controlador puede almacenar en búfer y la aplicación está esperando a que la GPU procese uno de ellos. Esto típicamente se mostrará como un gran bloque de tiempo en la primera llamada de dibujo dentro de un cuadro, o en Presente al final del cuadro anterior.