Sta-stattering, o de dónde vienen los microcongelamientos en el juego y cómo lidiar con ellos

Imagina: aquí estás esperando una nueva parte de tu juego favorito, y finalmente sale. Especialmente para este negocio, actualizó su PC: instaló la última CPU y GPU, aumentó la cantidad de RAM e incluso reemplazó el disco duro con un SSD. Su juego ahora debería correr tan suave como la seda desde la primera pantalla de carga hasta el final.



Aquí te descargas un pedido anticipado previamente pagado. Finaliza la instalación, comienzas el juego. Todo va bien: el juego vuela con una velocidad de cuadro de 60 FPS. O al menos eso es lo que te dice el contador de fotogramas en la superposición de tu GPU. Pero algo va mal. Mueves el mouse hacia adelante y hacia atrás y notas que el juego se está ... congelando.



¿Cómo es esto posible? ¿Qué otros congela a 60 FPS?



Puede parecer ridículo hasta que te lo encuentres tú mismo. Si te has encontrado con tales frisos, probablemente ya hayas logrado odiarlos.



Estos no son retrasos. No es una velocidad de fotogramas baja. Esto es asombroso. Con FPS alto y configuración ultrarrápida ideal.



¿Qué es, de dónde vino y hay alguna manera de deshacerse de él? Vamos a averiguarlo ahora.



imagen



Desde la introducción de las primeras máquinas recreativas en los años 70, los videojuegos han estado funcionando a 60 FPS. Por lo general, se asume que el juego debe ejecutarse a la misma velocidad que la pantalla. Fue solo después de la popularización de los juegos en 3D que tuvimos que enfrentarnos y adoptar una velocidad de cuadro más baja. En los años 90, cuando las "tarjetas 3D" (ahora llamadas "GPU") comenzaron a reemplazar el renderizado por software, la gente jugaba a 20 cuadros por segundo y 35 FPS ya se consideraba la frecuencia para una competencia de red seria.



Ahora tenemos autos súper rápidos que, por supuesto, pueden volar a 60 FPS. Sin embargo ... parece que hay más rendimiento insatisfecho que nunca. ¿Cómo es esto posible?



No es que los juegos no sean lo suficientemente rápidos. Y el hecho de que se congelan incluso con un alto rendimiento.



Si navega por los foros de juegos, probablemente verá algo como esto en los titulares: los



imagen

jugadores de PC a menudo se quejan de que los juegos sufren de stattering incluso si no hay problemas de velocidad de fotogramas.



Se puede suponer que se trata de casos aislados, pero las estadísticas de búsqueda de Google disipan tales suposiciones:



imagen

durante los últimos 5 años, la clasificación se ha convertido (relativamente) en un problema más que en el rendimiento.



(Tenga en cuenta que estos son valores relativos. No es que las personas busquen información sobre stattering con más frecuencia que sobre las velocidades de fotogramas en general. Si bien el número de búsquedas de frecuencia de fotogramas sigue siendo el mismo, las búsquedas de indicando son cada vez más comunes, especialmente últimamente. )





Década de búsqueda de las razones del tartamudeo



imagen

El paciente definitivamente está vivo. Simplemente se preocupa a menudo.



El autor encontró este problema por primera vez en 2003 mientras trabajaba en Serious Sam 2. La gente comenzó a informar casos en los que los movimientos de la pantalla y el mouse no eran suaves durante las pruebas en un nivel vacío. Esto fue acompañado por un patrón muy específico en el gráfico de velocidad de fotogramas, que el equipo de desarrollo llamó "latido".



El primer pensamiento fue que en algún lugar del código se había introducido un error, pero nadie pudo encontrarlo. Parecía que el problema aparecía y desaparecía aleatoriamente - al reiniciar el juego, reiniciar la computadora ... pero valía la pena cambiar cualquier parámetro de rendimiento y desapareció. Luego, pudo volver a cambiar el parámetro y todo siguió funcionando perfectamente. Problema de fantasmas.



Obviamente, Sam no fue el único problema. Al lanzar otros juegos, apareció de la misma manera, sugiriendo que había algo mal con los controladores. Pero el stattering no dependía del fabricante de su GPU. Se llevó a cabo incluso con diferentes API (OpenGL, DirectX 9, DirectX 11 ...). Lo único que quedó en común fue que aparecían stattering aquí y allá en algunas máquinas y escenas de juegos.



Con el lanzamiento de nuevos juegos, este problema siguió apareciendo y desapareciendo. Anteriormente, esto solo afectaba a algunos usuarios, y todo se limitaba a solicitudes del soporte técnico para cambiar algunos parámetros de rendimiento, lo que a veces ayudaba, y otras no, nunca se sabe.



Entonces, de repente, un hermoso día de invierno a principios de 2013, los chicos de Croteam descubrieron otro ejemplo de este problema que podría reproducirse de manera relativamente consistente en ese momento, esta vez en uno de los niveles de Serious Sam 3. Jugaron con esa escena durante mucho tiempo, hasta que de repente se dio cuenta. Era tan simple, no es de extrañar que se escapara del ojo público durante una década.



Al cambiar solo una opción simple en el motor del juego, pudieron resolver este problema. Sin embargo, inmediatamente quedó claro que la solución en realidad requeriría mucho más tiempo y esfuerzo. Y no solo de un equipo específico, sino de todo el ecosistema de juegos: desarrolladores de controladores de GPU, especialistas en mantenimiento de API, proveedores de sistemas operativos, todos.





Que ha estado pasando todo este tiempo



Así es como se ve cuando el juego se ralentiza incluso a 60 FPS. Podrías haber experimentado algo similar jugando a cualquier juego moderno, y probablemente lo primero que pensarías es que el juego no está optimizado. Bueno, revisemos esta teoría.



Si el juego es "demasiado lento", significa que en algunos puntos no podrá renderizar un cuadro lo suficientemente rápido y el monitor tendrá que mostrar el cuadro anterior nuevamente. Por lo tanto, cuando grabamos videos a 60 cuadros por segundo, debería mostrar "cuadros descartados", cuando el siguiente cuadro no se mostró a tiempo, por lo que el mismo se mostró dos veces.



Sin embargo, esto solo sucede cuando reproduce toda la animación. Si lo revisara cuadro por cuadro, no encontraría ningún espacio.





¿Cómo es esto posible?



Echemos un vistazo más de cerca a esto. A continuación se muestra una comparación en paralelo entre el video fluido ideal y el video en escena:



imagen

Seis cuadros consecutivos con sincronización precisa. Sobre - marcos correctamente colocados, debajo - marcos con stattering.



Puede ver dos cosas aquí: en primer lugar, realmente funcionan a la misma velocidad: cada vez que aparece un nuevo cuadro en la parte superior (correcto), luego aparece un nuevo cuadro debajo (stattering). En segundo lugar, por alguna razón, parece que se mueven un poco diferente: hay un "espacio" notable en el medio de la imagen que fluctúa entre una división de tiempo mayor y menor.



Los más atentos pueden notar otro detalle curioso: la imagen de abajo es supuestamente "más lenta" ... de hecho está "por delante" de la correcta. Extraño, ¿no?



Si observamos varios fotogramas consecutivos y su sincronización, podemos ver algo más interesante: los dos primeros fotogramas están perfectamente sincronizados, pero en el tercer fotograma el árbol en el video "más lento" está significativamente por delante de su contraparte en el "correcto". video (encerrado en un círculo rojo) ... También puede notar que este marco claramente tomó más tiempo (encerrado en un círculo amarillo).



Espera, espera ... pero si el video es "más lento" y el cuadro "tomó más tiempo", ¿cómo puede continuar?



Para comprender más explicaciones, primero debe comprender cómo los juegos modernos y otras aplicaciones 3D generalmente realizan la animación y el renderizado.





Una breve historia de la sincronización de cuadros



Hace mucho tiempo, en una galaxia muy, muy lejana ... cuando los desarrolladores crearon los primeros videojuegos, por lo general lo hacían basándose en la velocidad de fotogramas exacta a la que se ejecutaba la pantalla. En las regiones NTSC, donde los televisores funcionan a 60 Hz, esto significa 60 fotogramas por segundo, y en las regiones PAL / SECAM, donde los televisores funcionan a 50 Hz, 50 fotogramas por segundo.



La mayoría de los juegos eran conceptos muy simples que se ejecutaban en hardware fijo, generalmente una consola de juegos o un "microordenador doméstico" conocido como ZX Spectrum, C64, Atari ST, Amstrad CPC 464, Amiga, etc. Por lo tanto, creando y probando juegos para una máquina específica y una velocidad de fotogramas específica, el desarrollador siempre puede estar 100% seguro de que la velocidad de fotogramas nunca caerá en ninguna parte.



Las velocidades de los objetos también se almacenaron en unidades de "personal". Por lo tanto, necesitaba saber no cuántos píxeles por segundo se movería el personaje, sino cuántos píxeles en el marco. Por ejemplo, en Sonic The Hedgehog para Sega Genesis, esta velocidad es de 16 píxeles por cuadro. Muchos juegos incluso tenían versiones separadas para las regiones PAL y NTSC, donde las animaciones fueron dibujadas a mano específicamente para 50 y 60 FPS, respectivamente. De hecho, trabajar a cualquier otra velocidad de fotogramas era simplemente imposible.



Y dado que los juegos comenzaron a ejecutarse en dispositivos más variados con el tiempo, incluidas PC con hardware en constante expansión y actualización, era imposible saber exactamente a qué velocidad de fotogramas se ejecutaría el juego. Este hecho se vio agravado por el hecho de que los juegos en sí se han vuelto más complejos e impredecibles; esto es especialmente notable en los juegos en 3D, donde puede haber grandes diferencias en la complejidad de la escena, a veces incluso determinadas por los propios jugadores. Por ejemplo, a todo el mundo le encanta disparar a pilas de barriles de combustible, provocando una colorida serie de explosiones ... y una caída inevitable en la velocidad de fotogramas. Pero como es divertido, a nadie le importa.



Por lo tanto, es difícil predecir cuánto tiempo llevará modelar y renderizar un fotograma. (Tenga en cuenta que en las consolas modernas podemos suponer que el hardware es fijo, pero los juegos en sí son bastante impredecibles y complejos).



Si no puede estar seguro de a qué velocidad de cuadros funcionará el juego, debe medir los cuadros de frecuencia actuales y adaptar constantemente la física del juego y la velocidad de la animación para ello. Si un fotograma tarda 1/60 de segundo (16,67 ms) y tu personaje corre a 10 m / s, entonces se mueve 1/6 de metro en cada fotograma. Pero si el cuadro de repente comienza a tomar 1/30 de segundo (33.33 ms), entonces tienes que mover el personaje ya 1/3 de metro por cuadro (dos veces "más rápido") para que continúe moviéndose al mismo aparente velocidad.



¿Cómo arreglarlo? Como regla general, el juego mide el tiempo al comienzo de los fotogramas adyacentes y calcula la diferencia. Este es un método bastante simple, pero funciona muy bien.



Más bien, funcionó muy bien antes. En los años 90, cuando se consideraba 35 FPS qué velocidad, la gente estaba más que feliz con eso. Pero en ese momento, las tarjetas de video no eran una parte tan importante de la PC, y el procesador central tenía control sobre todo lo que sucedía en la pantalla. Si no tenía un acelerador 3D, incluso dibujaba objetos por sí mismo. Por lo tanto, sabía exactamente cuándo aparecerían en la pantalla.





La situación hoy



Con el tiempo, comenzaron a aparecer GPU cada vez más sofisticadas, e inevitablemente se volvieron cada vez más "asincrónicas". Esto significa que cuando la CPU le dice a la GPU que dibuje algo en la pantalla, la GPU simplemente almacena ese comando en un búfer para que la CPU pueda continuar mientras la GPU está procesando. En última instancia, esto conduce a una situación en la que la CPU le dice a la GPU cuándo se acerca el final del marco, y la GPU, mientras almacena esto entre sus datos, realmente no lo considera una prioridad; después de todo, todavía lo es. procesando algunos de los comandos emitidos anteriormente ... Mostrará el marco en la pantalla solo cuando haya hecho todo lo que se cargó antes.



Entonces, cuando el juego intenta calcular el tiempo restando las marcas de tiempo al comienzo de dos cuadros consecutivos, la relevancia de esto, francamente ... es muy cuestionable. Así que volvamos a nuestro ejemplo. Allí teníamos los siguientes fotogramas:



imagen

Seis fotogramas consecutivos con una sincronización precisa. La fila superior es correcta, la fila inferior tiene un efecto estabilizador.



En los dos primeros fotogramas, el tiempo de fotograma es de 16,67 ms (o 1/60 de segundo) y la cámara se mueve en la misma cantidad en las mayúsculas y minúsculas, por lo que los árboles están sincronizados. En el tercer fotograma (abajo, con stattering), el juego vio que el tiempo de fotograma es de 24,8 ms (es decir, más de 1/60 de segundo) y, por lo tanto, cree que la velocidad de fotogramas ha disminuido y se apresura a ponerse al día con el falta ... solo para encontrar que en el siguiente cuadro el tiempo es de solo 10.7 ms, lo que hace que la cámara se ralentice, y ahora los árboles están más o menos sincronizados nuevamente.



¿Qué está pasando? Los tiempos de fotogramas medidos por un juego fluctúan debido a varios factores, especialmente en un sistema multitarea ocupado como una PC. Por lo tanto, en algunos momentos, el juego asume que la frecuencia ha caído de 60 FPS y genera cuadros de animación diseñados para una velocidad de cuadros más baja. Pero debido a la naturaleza asincrónica de la GPU, siempre regresa de alguna manera a los mismos 60 cuadros por segundo.



Esto es gracioso: una animación generada para una frecuencia de fotogramas variable (frecuencia cardíaca) que se muestra a la frecuencia de fotogramas fija correcta real.



Entonces, en esencia, podemos asumir que no hay problema: todo va bien, el juego simplemente no lo sabe.



Esto nos lleva a lo que hablamos al principio del artículo. Cuando finalmente hayamos descubierto la causa del problema (aunque sabemos que esto es una ilusión de un problema, realmente no hay problema, ¿verdad?), Podemos aplicar la siguiente píldora mágica.



¿Qué es esta píldora? En Serious Engine, se indica como sim_fSyncRate = 60. En términos simples, esto significa esto: " ignora por completo todas estas travesuras y finge que siempre medimos 60 cuadros por segundo estables ". Y hace que todo funcione sin problemas, ¡solo porque todo funcionó sin problemas desde el principio! La única razón por la que se produjo la declaración fue porque el tiempo no era correcto para la animación.



¿Y eso es todo?





Entonces, ¿la solución es así de simple?



Lamentablemente no. Fue solo en las pruebas. Si dejamos de medir la velocidad de fotogramas en condiciones reales y simplemente asumimos que siempre es igual a 60 FPS, entonces cuando desciende por debajo de 60, y en una PC, tarde o temprano caerá por cualquier motivo: programas que se ejecutan en segundo plano, energía conservación o protección contra sobrecalentamiento, quién sabe, entonces todo se ralentizará.



Entonces, si medimos el tiempo de fotograma, se produce el stattering, y si no, en algún momento todo puede ralentizarse. ¿Y entonces que?



La solución real sería medir no el tiempo de inicio / finalización de la renderización de un fotograma, sino el tiempo en que se muestra la imagen en la pantalla.



Pero, ¿cómo puede saber el juego cuándo se muestra realmente un marco en la pantalla?



De ninguna manera: por el momento esto es imposible.



Extraño pero cierto. Uno esperaría que esta fuera una característica central de cada API de gráficos. Pero no: han sufrido cambios en todos los demás aspectos además de este. No hay forma de saber con certeza cuándo aparecerá el marco en la pantalla. Puede averiguar cuándo terminó el renderizado. Pero esto no es lo mismo que el tiempo de visualización.





¿Ahora que?



Bueno, no es tan malo. Muchas personas están trabajando activamente en la implementación de soporte para la sincronización de cuadros correcta para diferentes API. La API de Vulkan ya tiene una extensión llamada VK_GOOGLE_display_timing que tiene un historial comprobado de implementación de este concepto, pero solo está disponible para un número limitado de dispositivos.



Se está trabajando para proporcionar soluciones similares y mejores, me gustaría creer que ya en todas las principales API de gráficos. ¿Cuando? Es difícil de decir, porque el problema afecta profundamente a varios subsistemas del sistema operativo.



Sin embargo, esperamos que pronto esté disponible para el público en general.





Varias advertencias y otros detalles



Asumiremos que este es el final del texto principal. Las secciones siguientes son "características adicionales" que son en gran medida independientes entre sí y de las anteriores.



"Compositor"



imagen

¿Es un efecto de vidrio esmerilado? Sí, es por eso que tenemos que tener un compositor. Bastante importante, ¿no?



Un concepto llamado Compositing Window Manager , también conocido como compositor, está involucrado detrás de escena . Este es un sistema que ahora está presente en todos los sistemas operativos y permite que las ventanas sean transparentes, tengan un fondo borroso, sombras, etc. Los compositores pueden ir más allá y mostrar las ventanas de su programa en 3D. Para hacer esto, el compositor toma el control de la última parte del fotograma y decide qué hacer con él, justo antes de que llegue al monitor.



En algunos sistemas operativos, el compositor se puede desactivar en modo de pantalla completa. Pero esto no siempre es posible, e incluso en tales casos, ¿no podemos ejecutar el juego en modo ventana?





Gestión de energía y térmica frente a la complejidad del renderizado



También debemos tener en cuenta el hecho de que las CPU y GPU modernas no operan a una frecuencia fija, pero ambas tienen sistemas que ajustan su velocidad hacia arriba y hacia abajo en función de la carga y la temperatura actual. Por lo tanto, el juego no puede simplemente asumir que tendrán la misma velocidad de cuadro a cuadro. Por otro lado, el sistema operativo y los controladores no pueden esperar que el juego haga la misma cantidad de trabajo en cada fotograma. Los sistemas de comunicación complejos entre dos partes deben diseñarse de tal manera que se tenga en cuenta todo esto.





¿No podríamos simplemente ...



No pude. :) Por lo general, la medición del tiempo de la GPU se ofrece como una alternativa al tiempo de visualización. Pero esto no tiene en cuenta la presencia de un compositor y el hecho de que ninguno de los temporizadores de renderizado de la GPU se sincroniza directamente con la actualización de la pantalla. Para una animación perfecta, definitivamente necesitamos saber exactamente cuándo se mostró la imagen, no cuándo terminó de renderizarse.



All Articles