¿Qué es una GPU?
La GPU, también conocida como unidad de procesamiento de gráficos, es un componente vital en la actualidad. Esencialmente, la GPU es una CPU especializada en procesar y enviar gráficos a la pantalla. A medida que los sistemas operativos modernos y las aplicaciones multimedia han evolucionado, la GPU se ha vuelto aún más crucial.
En los primeros días de los gráficos por computadora, la CPU era responsable de procesar todos los gráficos, lo que resultaba en una carga excesiva. Sin embargo, con la aparición de los primeros aceleradores gráficos 3D, que dieron paso a las tarjetas gráficas modernas, la GPU se encarga de tareas de iluminación, sombreado, renderizado 3D y otros efectos gráficos, lo que reduce la carga sobre la CPU. Cabe destacar que la CPU y la GPU trabajan juntas, con la CPU indicando a la GPU qué tareas debe realizar según el software que se esté ejecutando. Esto es fundamental para comprender el proceso completo.
Me gustaría destacar algunos puntos adicionales que considero importantes. Cuando la CPU ejecuta el software y envía los datos a la GPU a través del bus del sistema, lo primero que se encuentra es el procesador de comandos. Este procesador se encarga de interpretar los comandos que llegan a través de la API y convertirlos en un lenguaje que pueda entender los drivers de la GPU.
Una vez que los datos llegan al procesador de comandos, se reciben los vectores o vértices, que luego se envían a las unidades de geometría para su procesamiento. A continuación, pasan a las unidades de generación de fragmentos y, finalmente, a las unidades de imagen. Es importante tener en cuenta que todos estos pasos dependerán de la arquitectura de la GPU, ya que algunas unidades pueden ser diferentes o no estar presentes en todas las GPUs.
En el caso de las GPUs integradas, como las iGPU presentes en SoCs y APUs, el proceso es similar, pero no dependen del bus del sistema ya que están integradas en el mismo chip o paquete. Sin embargo, es importante destacar que estas no tienen memoria VRAM dedicada, sino que comparten la RAM con la CPU en un sistema unificado.
Las GPUs actuales son increíblemente rápidas y capaces de mostrar imágenes en la pantalla en tiempo real debido a su avanzada arquitectura, altamente paralela a nivel de núcleo, con cientos o miles de núcleos en GPUs como AMD Radeon, NVIDIA GeForce o Intel Arc. Además, emplean diversas técnicas para maximizar su velocidad, aunque este tema es bastante complejo y merece su propio análisis.
Lo que quiero que entiendas acerca del paralelismo es que las unidades de procesamiento son SIMD, lo que significa que pueden manejar varios datos con una sola instrucción. Con tantos núcleos, cuando se ejecuta una solicitud, se distribuye entre todos los núcleos para que se complete rápidamente.
En las instrucciones que se envían a la GPU también hay bifurcaciones o ramificaciones, es una ISA completa, como la de una CPU, pero especial. Estas bifurcaciones pueden reducir el rendimiento, al igual que ocurre con la CPU, aunque este es un tema distinto que no trataré aquí. En algunos casos, es posible que no todas las unidades de cálculo finalicen su proceso. Además, al igual que con la CPU, también es necesario mantener la coherencia de la memoria.
¿Qué es una API gráfica?
Es importante entender lo que es una API gráfica para comprender el proceso de generación de gráficos. Estas APIs permiten que el software pueda enviar los comandos necesarios a la GPU para que procese los gráficos o animaciones.
Hay varias APIs gráficas, como OpenGL, Vulkan, WebGL o DirectX 3D. Estas APIs son colecciones de bibliotecas y comandos que permiten al hardware crear animaciones 2D y 3D. Para mantenerse actualizadas, deben incluir todas las funciones modernas que las actuales GPUs pueden desarrollar, como Ray Tracing, entre otras.
El software de terceros, como un videojuego, puede usar las funciones implementadas en la API. Cuando se necesita dibujar algo en pantalla, el software hará una llamada a la función o funciones necesarias de la API. La API, a su vez, enviará un comando a la tarjeta gráfica o GPU. Sin embargo, estos comandos enviados por la API no serían comprensibles para la GPU sin una pieza clave, que es el driver o controlador de la gráfica. El controlador traducirá los comandos para que sean instrucciones comprensibles para la GPU.
¿Qué es un motor gráfico?
Antes de adentrarnos en el proceso de generación de gráficos de la GPU, es importante entender lo que es un motor gráfico o motor de videojuegos (game engine). Aunque pueda parecer similar a una API gráfica, es un software de desarrollo que se utiliza para crear videojuegos, animaciones, simulaciones y gemelos digitales. Algunos ejemplos de motores gráficos populares son Unreal Engine, CryEngine, Godot, Unity 3D, Source, Rockstar Advanced Engine y DOOM Engine, entre otros. Estos motores gráficos son utilizados para crear videojuegos, tanto para juegos específicos como para otros títulos.
El motor gráfico es una herramienta de desarrollo que se encuentra por encima del nivel de la API gráfica, aunque haga uso de ella para crear los gráficos. Básicamente, estos motores proporcionan un marco de trabajo que facilita la creación de gráficos en lugar de tener que hacerlo desde cero. Incluyen herramientas como un entorno de desarrollo integrado (IDE), editores gráficos y motores de renderizado 2D o 3D.
En resumen, un motor gráfico proporciona las herramientas necesarias para que el creador de contenido pueda renderizar gráficos en 2D o 3D, incluyendo un motor físico que simula las leyes físicas (colisiones, reflejos, ondas, etc.), animación, scripting, sonido, inteligencia artificial para el juego, y más.
¿Cómo se genera un gráfico?
Ahora que ya conocemos lo básico, ahora es el momento de ver qué sucede realmente dentro de la tarjeta gráfica o GPU. Recopilando todo lo anterior, la pila gráfica o jerarquía de elementos que intervienen en la creación de un gráfico computacional tenemos:
- El software que necesita dibujar el gráfico, como puede ser un videojuego (gracias al motor gráfico) o una ventana gráfica de un programa, hará uso de la API gráfica para dibujarlo.
- La API, mediante sus funciones o comandos, podrá comunicarle a la CPU lo que se necesita procesar para generar el gráfico deseado.
- El driver o controlador de la GPU se encargará de traducir las instrucciones para que sean comprensibles por la GPU, de esta forma, el software es independiente de la arquitectura de GPU, que podría cambiar y seguir siendo compatible.
- Por último, la GPU se dedicará a procesar los gráficos necesarios y a cargarlos en la memoria para que sean enviados a la pantalla a través de la interfaz en la que esté conectada.
El proceso para que los fotogramas lleguen al framebuffer y se muestren en la pantalla implica una serie de etapas que van desde los elementos más simples hasta las imágenes más elaboradas. En los siguientes apartados, explicaré detalladamente este proceso.
Es fascinante cómo los gráficos y personajes que vemos en los videojuegos actuales se originan a partir de puntos simples que se transforman en triángulos, polígonos más complejos, y finalmente adquieren textura, color e iluminación en cuestión de milisegundos.
La CPU inicia el trabajo…
Lo primero que hay que decir es que será el software el que se ejecute en la CPU para generar esos gráficos a través de comandos u objetos mediante la API gráfica y demás elementos necesarios como he citado anteriormente.
De esta forma, la CPU puede enviar a la GPU una serie de instrucciones que se necesitan ejecutar para presentar el gráfico en pantalla y que se consiguen gracias a la traducción que hace el driver de la GPU. Una vez llegan a la GPU, se hará uso de las unidades de sombreado o shaders, como las Compute Unit de AMD o los núcleos CUDA de NVIDIA.
La GPU le sigue: Se inicia el proceso en la pipeline de la representación
Una vez llegan los datos necesarios y las instrucciones a la GPU, es decir, a la pipeline, se inicia lo que se conoce como Rendering Pipeline, o canalización de renderizado. Y éste constará de 6 etapas concretas:
Operación de vértice (Per-Vertex Operation)
Una vez se inicia el proceso en la GPU, se procesarán los vértices (Vertex Shader) que serán ejecutadas mediante una serie de operaciones matemáticas de coma flotante por las unidades de sombreado. Mediante unas multiplicadores de matrices se realizará una transformación para establecer las coordenadas de la imagen a representar.
Ensamblaje de primitiva (Primitive Assembly)
Lo siguiente será ensamblar las primitivas o 3 vértices que se han conseguido en el paso anterior. De esta forma se crea triángulos, con muchos de estos triángulos se podrá general la imagen similar a estas montañas representadas únicamente con triángulos:
Procesamiento de primitivas (Primitive Processing)
La siguiente etapa que se produce en la canalización de la GPU es lo que se conoce como recorte o clipping. Como puedes comprender, no toda la imagen se muestra en pantalla, sino que solo se verá una parte de la escena en la pantalla, por eso se debe recortar todo aquello que queda fuera de la pantalla (el espacio de la pantalla se denomina View-Volume). Así no se desperdiciarán recursos de hardware en las siguientes etapas al tener que procesar partes del gráfico que no servirán para nada.
Rasterización o renderizado (Rasterization)
Ahora que ya tenemos los vértices para la triangulación y solo el recorte que se mostrará, se necesitan crear píxeles para los fotogramas o frames. De esto se volverán a ocupar las unidades de cómputo de la GPU, de convertir todo lo que queda dentro de los polígonos en píxeles.
Procesamiento de fragmentos (Fragment Processing)
En este paso, la GPU, mediante sus unidades de sombreado o un shader denominado Fragment Shader, aplicará el color, la textura, la iluminación necesaria, etc., a los píxeles conseguidos en el paso anterior. Por supuesto, en las modernas gráficas también se llevan a cabo otras tareas como el Ray Tracing, anti-aliasing, etc.
Operación de fragmento (Per-Fragment Operation)
Ahora los píxeles del gráfico que se desea generar ya tiene su color, textura, posición, y todo lo necesario. Es el momento en el que la GPU lo guarda en el framebuffer o buffer de fotogramas. Concretamente se agruparán los fotogramas creados en lo que se denomina Default-Framebuffer.
Finalmente, la pantalla muestra la imagen representada
Y, para finalizar el proceso, una vez tenemos los frames en el buffer, estos fotogramas pasarán a una determinada velocidad (FPS) hacia el bus o interfaz por la cual esté conectada la pantalla a la tarjeta gráfica para que vaya refrescando la imagen. Todo este proceso pasa en cuestión de muy poco tiempo, ya que cuando realizas alguna acción, de forma instantánea tienes el gráfico en pantalla.