Renderización de latencia baja con la sugerencia desincronizada

Joe Medley
Joe Medley

Diferencias en la renderización de la pluma stylus

Las aplicaciones de dibujo basadas en la pluma stylus creadas para la Web han sufrido durante mucho tiempo problemas de latencia debido a que una página web tiene que sincronizar las actualizaciones de gráficos con el DOM. En cualquier aplicación de dibujo, las latencias de más de 50 milisegundos pueden interferir en la coordinación mano-ojo de un usuario, lo que dificulta el uso de las aplicaciones.

La sugerencia desynchronized para canvas.getContext() invoca una ruta de código diferente que omite el mecanismo habitual de actualización del DOM. En cambio, la sugerencia le indica al sistema subyacente que omita toda la composición que pueda y, en algunos casos, el búfer subyacente del lienzo se envía directamente al controlador de pantalla de la pantalla. Esto elimina la latencia que se produciría con la cola del compositor del procesador.

¿Qué te parece?

Renderización simultánea de Sintel

Para obtener el código, desplázate hacia delante. Para ver cómo funciona, necesitas un dispositivo con pantalla táctil y, preferentemente, una pluma stylus. (los dedos también funcionan). Si tienes uno, prueba las muestras de 2d o webgl. Para el resto, consulta esta demostración de Miguel Casas, uno de los ingenieros que implementó esta función. Abre la demostración, presiona reproducir y mueve el control deslizante hacia adelante y atrás al azar y con rapidez.

En este ejemplo, se usa un clip de un minuto y veintiún segundos del cortometraje Sintel de Durian, el proyecto de película abierta de Blender. En este ejemplo, la película se reproduce en un elemento <video> cuyo contenido se renderiza simultáneamente en un elemento <canvas>. Muchos dispositivos pueden hacerlo sin seccionar, aunque los dispositivos con renderización en búfer frontal, como ChromeOS, pueden tener seccionamientos. (La película es genial, pero desconcertante. Una hora después de verla, no me sirvió para nada. Considérate una advertencia).

Cómo usar la sugerencia

Usar la latencia baja es más que agregar desynchronized a canvas.getContext(). Analizaré los problemas uno por uno.

Crea el lienzo

En otra API, primero hablaría de la detección de funciones. Para la sugerencia desynchronized, primero debes crear el lienzo. Llama a canvas.getContext() y pásale la nueva sugerencia desynchronized con un valor de true.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
  desynchronized: true,
  // Other options. See below.
});

Detección de funciones

Luego, llama a getContextAttributes(). Si el objeto de atributos que se muestra tiene una propiedad desynchronized, pruébalo.

if (ctx.getContextAttributes().desynchronized) {
  console.log('Low latency canvas supported. Yay!');
} else {
  console.log('Low latency canvas not supported. Boo!');
}

Se evita el parpadeo

Existen dos instancias en las que pueden parpadear si no escribes el código correctamente.

Algunos navegadores, incluido Chrome, borran los lienzos de WebGL entre marcos. Es posible que el controlador de pantalla lea el búfer mientras está vacío, lo que hace que la imagen se dibuje parpadee. Para evitar que esto suceda, establece preserveDrawingBuffer en true.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
  desynchronized: true,
  preserveDrawingBuffer: true
});

También puede parpadear cuando borras el contexto de la pantalla en tu propio código de dibujo. Si debes borrar los datos, dibuja en un búfer de fotogramas fuera de pantalla y, luego, cópialo en la pantalla.

Canales alfa

Un elemento de lienzo translúcido, en el que alfa se establece como verdadero, aún se puede desincronizar, pero no debe tener ningún otro elemento del DOM encima.

Puede haber solo una

No puedes cambiar los atributos de contexto después de la primera llamada a canvas.getContext(). Esto siempre ha sido cierto, pero repetirlo puede ahorrarte algo de frustración si lo olvidas o desconoces .

Por ejemplo, supongamos que obtengo un contexto y especifico alpha como falso, luego, en algún lugar más adelante en mi código, llamo a canvas.getContext() por segunda vez con alfa configurado como verdadero, como se muestra a continuación.

const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
  alpha: false,
  desynchronized: true,
});

//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
  alpha: true,
  desynchronized: true,
});

No es evidente que ctx1 y ctx2 son el mismo objeto. El valor alfa sigue siendo falso y nunca se crea un contexto con alfa igual a verdadero.

Tipos de lienzos compatibles

El primer parámetro que se pasa a getContext() es contextType. Si ya estás familiarizado con getContext(), no dudes en preguntarte si se admite algo distinto de los tipos de contexto "2d". En la siguiente tabla, se muestran los tipos de contexto que admiten desynchronized.

contextType Objeto de tipo de contexto

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

Conclusión

Si quieres ver más de esto, consulta las muestras. Además del ejemplo de video que ya se describió, hay ejemplos que muestran los contextos '2d' y 'webgl'.