Soy James Fulop, programador sénior de motor del equipo de Guild Wars 2. La transición a DirectX11 es un proyecto que lleva mucho tiempo preparándose. En esta publicación voy a repasar algunas de las decisiones técnicas de alto nivel que tomamos para determinar qué forma tendría este proyecto, así como un ejemplo de nuestro tiempo de ejecución de gráficos y de cómo el renderizador de DirectX11 afecta al rendimiento.
La beta comenzará el 21 de septiembre de 2021. Para participar en la beta dentro del juego id al menú de Opciones gráficas. El cambio tendrá efecto en cuanto reiniciéis el juego.
Para empezar, ¿por qué decidimos actualizar a DirectX11? El rendimiento del cliente es una prioridad para nosotros, y queremos que todos puedan jugar con el mayor número de fotogramas por segundo, o framerate. Detectamos que, a veces, el juego se paraba a esperar a que se completara el trabajo de renderizado. Guild Wars 2 se lanzó hace nueve años, así que implementar funciones que dependan de DirectX11 puede ayudar a que el juego siga viéndose bonito después de tanto tiempo.
DirectX11 también ofrece algunas opciones de tecnología moderna que no están disponibles en DirectX9. Actualizar a DirectX11 es el primero paso para que podamos hacer más cosas vistosas.
Tras una investigación cuidadosa, decidimos integrar en Guild Wars 2 la librería de renderizado de código abierto BGFX. BGFX está bien escrito y da soporte a varias funciones gráficas de backend, además de que ya se usa en muchos juegos en toda la industria. Podéis ver más información al respecto en su sitio web oficial.
Dado que el ecosistema gráfico en la industria informática está en continua evolución, BGFX nos permite trabajar juntos como una comunidad de ingenieros de renderizado, en vez de tener que ”reinventar la rueda” en cada estudio. ArenaNet ha contribuido al desarrollo de BGFX, y seguirá haciéndolo.
Escogimos usar DirectX11 en vez de DirectX12 o Vulkan porque descubrimos que cambiar a la implementación de DirectX11 de BGFX nos daba un impulso de rendimiento suficiente como para que las funciones gráficas de backend ya no limitaran el rendimiento del cliente. DirectX11 es muy estable, y ya lo han usado miles de juegos a lo largo de la última década. Nos permite volver a dar soporte para Windows Vista, mientras que el apoyo de Vulkan solo llega hasta Windows 7, y el de DirectX12, solo hasta Windows 10. En cuanto a las funciones gráficas, saltar de DirectX9 a DirectX11 nos da muchas opciones para añadir funciones interesantes al motor en un futuro. Si diéramos soporte para más de una de estas funciones de backend, eso dispararía el trabajo de control de calidad para solo conseguir beneficios muy poco tangibles.
El renderizador actual de DirectX9 no ha sido alterado de manera significativa. Una de las filosofías que tenía mientras trabajaba en esto era que el renderizador de DirectX11 se viera igual que en DirectX9. Si realizara cambios en los dos al mismo tiempo, no habría una base real con que comparar el aspecto del juego. Al final, cuando el nuevo renderizador sea estable, el de DirectX9 se descontinuará y después se eliminará.
Análisis de los fotogramas
Ahora me gustaría hablar sobre cómo el renderizador de DirectX11 afecta al rendimiento del juego. Para empezar con lo más básico, los videojuegos funcionan como películas, en el sentido de que en realidad estáis viendo imágenes estáticas que se presentan ante vosotros a gran velocidad. A cada una de estas imágenes estáticas se le llama fotograma (frame en inglés). De este proceso viene el término fotogramas por segundo, o FPS. Cuanto mayor sea el número de FPS, más suaves parecen las acciones, hasta llegar al límite físico de vuestro monitor. Este proceso de responder continuamente a los dispositivos de entrada (teclado y ratón) y producir fotogramas se llama bucle del juego.
Aquí tenéis algunas imágenes de cómo es uno de estos bucles del juego. Tomo todos estos datos de esta ubicación en Arco del León usando la configuración gráfica “Mejor aspecto”.
He elegido este punto porque hay muchas cosas que renderizar. Está toda la ciudad, y luego está la técnica que usamos para los reflejos en tiempo real, que consiste en renderizar el mundo entero una segunda vez, pero boca abajo.
Para esta prueba, he usado un ordenador con CPU Intel I7-6700 y con GPU NVidia 1080.
Aquí tenéis una captura de pantalla de una herramienta de visualización que usamos, llamada Telemetry, desarrollada por RAD Game Tools. Esto visualiza cómo se distribuye el trabajo de renderizado del juego por los núcleos de la CPU. El tiempo se representa de forma horizontal. Esto muestra dos fotogramas del juego. He emborronado muchos de los identificadores para que esta foto sea un poco más clara.
Cada fila horizontal representa un hilo lógico. Aquí podéis ver que tengo seis hilos de trabajo. Ajustamos el número de hilos de trabajo según cuántos hilos de CPU puede soportar la misma. Mi chip puede dar soporte a ocho hilos de hardware, así que el juego los divide como un hilo de juego, un hilo de renderizado y seis hilos de trabajo. Tened en cuenta que Guild Wars 2 tiene otros hilos que se están ejecutando también y que no os estoy mostrando aquí. Esos hilos no dan demasiado trabajo a la CPU, por lo que no son relevantes para esta publicación.
Los distintos bloques dentro de los canales de hilos representan funciones ejecutándose. Cuando el hilo se muestra como vacío, eso quiere decir que está desocupado y no realiza ninguna tarea del juego. En esos espacios, el hilo de hardware puede que esté tomando trabajo de otras aplicaciones del ordenador.
Consideramos que el bucle del juego se reinició en los fotogramas lógicos. Las líneas verticales indican dónde empiezan dichos fotogramas. Los dispositivos de entrada (como el teclado y el ratón) se consultan al principio del fotograma.
Aquí es donde tiene lugar el bucle de fotogramas gráficos. Dado que el comienzo del fotograma de juego no realiza ningún renderizado, dejamos que parte del trabajo del último fotograma se solape con el siguiente para poder hacer tanto trabajo en paralelo como sea posible. Pero en algún momento, no queda más remedio que esperar a que se retire el último fotograma para poder empezar a mandar trabajo para el siguiente. Puede que os hayáis fijado en un bloque rojo de trabajo en el hilo principal, el cual se alinea con parte del fin de trabajo del hilo de renderizado. Esto es lo que queremos eliminar. El hilo de juego no debería esperar nunca a que el trabajo de renderizado se complete.
Además, hay otros bloques rojos mucho más pequeños en el hilo principal. Eso es el hilo principal esperando a que el trabajo del hilo se complete.
Aquí preparamos listas detalladas de instrucciones para que las ejecute el hilo de renderizado. Cuando se genera un bloque de trabajo de renderizado, este se lleva hasta el hilo de renderizado.
El hilo de renderizado convierte el trabajo de renderizado siguiendo las especificaciones de backend para gráficos (OpenGL o DX9).
Fotograma de renderizador beta DX11
Así es cómo se ve el nuevo renderizador en Telemetry.
La disposición de los hilos es la misma.
El hilo principal ya no debe esperar a que el hilo de renderizado se complete. Esto se consigue gracias a la arquitectura de BGFX. Las llamadas de dibujado se acumulan en el hilo de juego (y también en los hilos de trabajo, de lo que ya hablaremos). Cuando el fotograma acaba los procesos de BGFX, estos llaman a su hilo de renderizado. Ahora tenemos un montón de espacio para dibujar.
La conversión de nuestros datos de renderizado en cola a llamadas de BGFX ocurren en paralelo por los hilos de trabajo.
¡Y eso es todo! Este proyecto ha sido muy interesante para mí. Tengo muchas ganas de ver el futuro tecnológico de Guild Wars 2.
Contadnos en los foros qué tal os funciona la beta de DirectX11.
¡Nos vemos en Tyria!
– James Fulop