Rendimiento de WebGL
WebGL tiene mala fama: muchos desarrolladores asumen que WebGL es lento e incapaz de renderizar gráficos 3D complejos. Aunque numerosos ejemplos demuestran lo contrario, la experiencia de los desarrolladores a menudo refuerza esta creencia una y otra vez.
Pero el hardware que ejecuta el código de WebGL no está limitado para los navegadores. Entonces, ¿por qué muchos desarrolladores piensan que es imposible renderizar gráficos 3D rápidamente en la web?
Este artículo te guiará a través de las mejores prácticas de rendimiento de WebGL y cómo tú también puedes lograr un renderizado 3D rápido en la web.
CPU vs GPU
En una aplicación 3D, parte del código se ejecuta en la CPU y otra parte en hardware acelerado, como el GPU.
WebGL está diseñado para permitir el uso del GPU y así acelerar aplicaciones gráficas en la web. Por lo tanto, WebGL puede entenderse como funciones que envían trabajo al hardware gráfico y recuperan el resultado.
El código que genera el trabajo para el GPU se ejecuta en la CPU y, en el caso de WebGL, lo controlamos a través de JavaScript.
Sobrecarga del Navegador
Uno de los objetivos del navegador es proteger a los usuarios de posibles sitios web maliciosos. Por eso, verificará la seguridad de cada llamada a WebGL que haga el sitio web mediante JavaScript. Además, debe aislar el proceso que ejecuta el código del sitio, convirtiendo cualquier llamada hacia y desde este proceso en un formato que se pueda enviar, proceso conocido como “marshalling”.
Tanto el marshalling como la verificación de las llamadas a WebGL del sitio web implican un trabajo que añade un coste de rendimiento, comparado con la misma llamada en un entorno nativo.
Evitar Llamadas a WebGL
Para mejorar el rendimiento de WebGL, debemos evitar usar llamadas que tengan un alto sobrecoste. Te darás cuenta de qué llamadas son especialmente costosas al perfilar tu aplicación de WebGL.
Algunas de las llamadas que son inesperadamente caras son:
Una excelente forma de evitar estas llamadas es realizar un seguimiento del estado de WebGL y reducir las comprobaciones de errores en las compilaciones de producción de tu aplicación WebGL.
Evitar Llamadas de Dibujo
El secreto para un rendimiento excepcional de WebGL es tener la menor cantidad de llamadas de dibujo posibles. Una llamada de dibujo es cualquier función que utiliza una de las siguientes funciones de WebGL:
- drawArrays()
- drawElements()
- drawArraysInstanced()
- drawElementsInstanced()
- drawBuffers()
- drawRangeElements()
Hay muchas formas de lograrlo. Por ejemplo, usando una sola llamada que dibuje muchos objetos, en lugar de llamar repetidamente a una función para dibujar los mismos objetos. Puedes usar instancing para renderizar una gran cantidad del mismo mesh, o el WEBGL_multi_draw para renderizar muchos objetos diferentes con el mismo shader.
Los motores 3D suelen disponer de una función llamada “batching”, que fusiona muchas llamadas en una sola llamada de WebGL. Wonderland Engine lleva esto a un nivel extremo, donde escenas con decenas de miles de objetos dinámicos se renderizan en menos de diez llamadas de dibujo automáticamente.
El rendimiento de WebGL en dispositivos móviles es especialmente sensible a las llamadas de dibujo.
Evitar Llamadas de Dibujo (Móviles)
Reiteramos la importancia de este punto: en móviles, las llamadas de dibujo son cruciales incluso sin la sobrecarga del navegador. Incluso cuando se construye de forma nativa con Unity o directamente con GLES, debes mantener baja tu cantidad de llamadas de dibujo.
Si tu objetivo es obtener un rendimiento excelente de WebGL en móviles, deberás prestar especial atención a las llamadas de dibujo.
WebGL en Safari
En Safari (tanto en iOS como en MacOS), hay algunas llamadas de WebGL que tienen sorprendentemente mucha sobrecarga, como:
Presta especial atención al uso de Uniform Buffers al optimizar para Safari.
JavaScript
El lenguaje que se utiliza para interactuar con las APIs del navegador, como WebGL, es JavaScript. El principal problema de rendimiento con JavaScript es la recogida de basura (Garbage Collection), que automáticamente encuentra y elimina la memoria que ya no es necesaria.
El proceso de Garbage Collection puede hacer que el rendimiento de la aplicación WebGL sea impredecible y poco fiable, ya que no tienes control sobre cuándo ocurrirá. Como resultado, a menudo sucede en momentos en que puede causar parpadeos en el renderizado, dando la apariencia de un mal rendimiento, incluso aunque el código esté bien optimizado.
Para conseguir tasas de fotogramas estables, adopta un enfoque estricto para escribir JavaScript sin basura.
Safari de iOS y Memoria
Las aplicaciones WebGL que funcionan bien en Safari son raras. El rendimiento de WebGL en Safari presenta algunos desafíos adicionales. Escribimos un blog entero sobre cómo optimizar para Safari.
Límites de Memoria
En iOS tienes otro reto: las pestañas del navegador tienen memoria muy limitada, especialmente en hardware de iPhone más antiguo. Si superas los límites de memoria, la pestaña podría recargarse o congelarse. Dado que los iPhones usan memoria unificada, la RAM para CPU y GPU se comparte, y tanto los datos de texturas y buffers, como la memoria de JavaScript o WebAssembly, contarán hacia el límite.