Incluso si aplicas todas las optimizaciones a nivel de React, aún necesitas optimizar tu render loop. Utilizamos el concepto de presupuesto de cuadros. Esto significa que si deseas alcanzar 60 cuadros por segundo, tienes 15 milisegundos para renderizar toda tu escena. Por lo tanto, es crucial utilizar el perfilador de Chrome y ver qué está ocupando mucho tiempo en tu loop de cuadros y optimizar esas cosas primero. A veces, el resultado de esos perfiles puede ser inesperado. Descubrir que has introducido una llamada de función con demasiada complejidad en tu camino crítico.
Otra cosa que hacemos es el perfilado de memoria ya que mantener una huella de memoria baja es crucial cuando manejas grandes cantidades de datos. Utilizando el perfilador de Chrome, puedes tomar una instantánea de la memoria y ver qué está ocupando demasiado espacio. Utilizando este método, por ejemplo, pudimos notar cómo estábamos utilizando cientos de megabytes solo para almacenar UIDs basados en cadenas. Esto nos sugirió usar números en su lugar lo cual nos permitió ahorrar mucho espacio y hacer posible la carga de ciertos documentos.
Otra cosa que necesitas son algoritmos eficientes y estructuras de datos. Esto realmente ayuda, por ejemplo, a optimizar el raycasting que es el proceso de determinar qué objetos están presentes en tu escena en una posición dada. Esto es crucial para las interacciones del mouse ya que necesitas saber qué hay debajo del puntero del cursor. El enfoque ingenuo para este problema como también se implementa en React 3 Fiber es realizar una búsqueda lineal lo cual desafortunadamente puede ser muy costoso cuando tienes miles de objetos. Dado que esto es algo que debe ejecutarse en tiempo real, tener estructuras de datos más rápidas como R3 y BinaryTree realmente puede acelerar mucho tu aplicación.
Otra cosa de la que debes tener en cuenta son las optimizaciones de la GPU. Las GPUs son procesadores paralelos realmente potentes pero debes tener en cuenta el cuello de botella de la CPU y la GPU. De hecho, la comunicación entre la CPU y la GPU no es gratuita. Cada vez que le pides a la GPU que haga algo, también llamado draw call, hay cierta sobrecarga. Por esta razón, quieres mantener tus draw calls lo más bajos posible, especialmente en dispositivos móviles de gama baja. Esto significa que si deseas dibujar, por ejemplo, 10,000 instancias del mismo objeto, una y otra vez, hacerlo de la manera ingenua, utilizando un bucle for, puede ser muy ineficiente. Puedes ver que si queremos renderizar 10,000 instancias del mismo objeto, obtendremos un rendimiento bastante pobre alrededor de 33 FPS. Afortunadamente, hay una forma de optimizar eso y se llama instanced rendering. Con esta técnica, puedes dibujar varias instancias del mismo objeto con una sola llamada a la GPU, reduciendo en gran medida el cuello de botella. Esto puede generar grandes mejoras de rendimiento en algunos casos, como aquí, por ejemplo, donde anteriormente estábamos limitados a un promedio de 33 FPS. Lo interesante del instanced rendering es que es muy personalizable. Incluso si estás limitado a tener la misma geometría y material para cada instancia, puedes programar cómo la GPU está procesando cada vértice y píxel e incluso pasar parámetros personalizados para cada uno. Por ejemplo, puedes darle a cada instancia una posición o tamaño diferente y programar en la GPU cómo interpretar esos parámetros. El instanced rendering fue crucial en Flux para optimizar nuestro renderizado de texto aunque requirió una configuración especial. Verás, el renderizado de texto desafortunadamente no está provisto por WebGL y es algo que debes manejar con tu propia solución personalizada.
Comments