Planteamiento y caso de uso
Una aplicación gráfica de navegador muestra un lienzo negro tras reanudarse en segundo plano, una actualización de controladores o presión de recursos. Diseña el manejo de la pérdida del dispositivo WebGPU: cómo observar GPUDevice.lost, distinguir la destrucción intencional de la pérdida transitoria, reconstruir el dispositivo y cada recurso de GPU, y evitar que los flujos de recuperación concurrentes se sobreescriban entre sí. Cubre también navegadores no compatibles, adaptadores no disponibles de forma permanente y la degradación elegante (fallback) del renderizado.
Qué está evaluando el entrevistador
- Comprender
lostcomo una Promise del ciclo de vida del dispositivo en lugar de un error de renderizado ordinario. - Distinguir
destroyedde la pérdida causada por el navegador, el controlador o la gestión de recursos. - Reconstruir adaptadores, dispositivos, pipelines, buffers, texturas y grupos de enlaces (bind groups).
- Diseñar la recuperación de vuelo único (single-flight), la cancelación de fotogramas obsoletos y la inicialización idempotente.
- Manejar contextos seguros, Workers, compatibilidad y observabilidad.
Preguntas para aclarar primero
- ¿La aplicación es un lienzo en tiempo real, un editor o un trabajo de cómputo fuera de línea, y qué tiempo de recuperación es aceptable?
- ¿Deben sobrevivir las escenas del lado de la CPU, la entrada del usuario y las ediciones no confirmadas?
- ¿Qué navegadores, Workers, estados de energía y presupuestos de memoria están dentro del alcance?
- ¿Debería la falla cambiar a WebGL, a una vista previa estática o a un aviso de recarga?
Respuesta en treinta segundos
Trato al dispositivo GPU como una sesión reemplazable: las descripciones de recursos y escenas del lado de la CPU son autoritativas, mientras que los objetos de GPU son cachés. Tras observar device.lost, una máquina de estados de vuelo único pausa los envíos y lee GPUDeviceLostInfo.reason; un destroyed intencional finaliza la sesión, mientras que otros motivos desencadenan un nuevo adaptador y dispositivo, la reconstrucción de recursos y la recuperación del bucle de renderizado. Las fallas repetidas o un adaptador que devuelve dispositivos ya perdidos entra en una ruta de fallback, registrando el motivo, el tiempo de recuperación y el recurso fallido.
Respuesta a fondo, paso a paso
1. Separar el estado del dispositivo y el de la aplicación
Mantén el grafo de escena, los parámetros de materiales, los datos de geometría y las fuentes de texturas en el lado de la CPU. El dispositivo, la cola, los buffers, las texturas, los pipelines y los grupos de enlaces son objetos desechables de la sesión de GPU, no la verdad del negocio.
2. Observar la Promise del ciclo de vida
GPUDevice.lost permanece pendiente durante la vida útil del dispositivo y se resuelve con GPUDeviceLostInfo tras la pérdida. Registra un único listener tras la inicialización y envía la devolución de llamada (callback) a una única máquina de estados de recuperación.
3. Explicar los motivos de pérdida
Un GPUDevice.destroy() explícito normalmente corresponde a reason destroyed, por lo que no debería desencadenar un reinicio incondicional. La gestión de recursos del navegador, las actualizaciones de controladores y los fallos transitorios del dispositivo pueden recuperarse; un adaptador desconectado o deshabilitado por energía puede seguir devolviendo dispositivos ya perdidos.
4. Usar una compuerta de recuperación de vuelo único
Devuelve la misma Promise desde el punto de entrada de recuperación en lugar de permitir que cada fotograma de animación realice la inicialización. Pausa los envíos, descarta los codificadores de comandos antiguos y utiliza un token de generación para rechazar devoluciones de llamada asíncronas del dispositivo antiguo.
5. Reconstruir recursos a partir de descripciones
Persiste el uso de buffers, el tamaño y formato de texturas, los samplers, los diseños de grupos de enlaces, el código fuente de los shaders y la configuración del pipeline. Tras crear el nuevo dispositivo, reconstruye en orden de dependencia: shaders y diseños, pipelines, buffers y texturas, vistas, grupos de enlaces, y luego el contexto del lienzo y el bucle de renderizado.
6. Gestionar los datos de CPU y los presupuestos
Las texturas grandes y la geometría pueden provenir de URLs re-legibles, IndexedDB o cachés comprimidos. Sube en lotes conscientes de la visibilidad y prioridad con un presupuesto de memoria y una señal de cancelación, para que la recuperación no recree inmediatamente la presión de recursos.
7. Manejar la concurrencia y la visibilidad
La ocultación de página, los mensajes de Workers y los reintentos del usuario pueden solicitar la recuperación. Restringe la máquina de estados a ready, lost, recovering y degraded; solo la generación actual puede enviar fotogramas. Retrasa la reconstrucción costosa mientras la página esté oculta.
8. Diseñar fallback y observabilidad
Comprueba el contexto seguro y navigator.gpu antes de solicitar un adaptador y dispositivo. Tras fallas repetidas, pérdida permanente del dispositivo o navegadores no compatibles, cambia a WebGL, a una vista previa estática o a un aviso de recarga claro. Registra el motivo, la información del adaptador, los intentos, la duración, los recursos fallidos y la proporción de fallback sin exponer errores internos a los usuarios.
Compensaciones y límites
Solicitar un nuevo dispositivo no restaura buffers, texturas ni pipelines antiguos; deben reconstruirse a partir de descripciones del lado de la CPU. La recuperación no puede asumir que cada pérdida sea transitoria y debe usar retroceso exponencial (backoff) en lugar de reintentos infinitos. WebGPU requiere un contexto seguro y sigue teniendo disponibilidad limitada; los Workers pueden usar la API, pero las diferencias entre navegadores y controladores pertenecen a la matriz de lanzamientos.
Plan de despliegue y evidencia
- Construye un manifiesto de recursos de CPU y una fábrica de recursos de GPU cuyos pasos de creación sean repetibles.
- Agrega una generación y un estado de recuperación de vuelo único al dispositivo, adaptador, contexto del lienzo y bucle de renderizado.
- Inyecta casos de destrucción intencional, reanudación en segundo plano, reinicio de controladores, presión de memoria y adaptadores ya perdidos.
- Verifica el orden de los recursos, la preservación de las ediciones del usuario, la pausa de fotogramas y la interfaz de fallback, incluyendo Workers.
- Utiliza las notas de MDN sobre la Promise
lost,GPUDeviceLostInfo, contexto seguro y disponibilidad limitada como evidencia de compatibilidad.
Errores comunes y seguimiento
Error 1: Llamar solo a requestDevice de nuevo
El nuevo dispositivo no tiene recursos antiguos. Reconstruye pipelines, buffers, texturas, vistas y grupos de enlaces a partir de descripciones de CPU.
Error 2: Reintentar cada motivo automáticamente
La destrucción intencional puede ser un apagado normal; reintentar con un adaptador no disponible de forma permanente crea un bucle. Ramifica según el motivo aplicando backoff.
Error 3: Iniciar la recuperación en cada fotograma de animación
Los flujos concurrentes compiten por el estado compartido. Una Promise de vuelo único y una compuerta de generación garantizan una sola sesión actual.
Error 4: Tratar los objetos de GPU como estado de negocio
La pérdida del dispositivo borra la sesión de GPU. Mantén las escenas, la entrada del usuario y las fuentes de recursos independientes del dispositivo.
Error 5: Ignorar las rutas no compatibles y de fallback
WebGPU no es Baseline y solo está disponible en contextos seguros. Detéctalo temprano y proporciona WebGL, una vista previa estática o un plan de recarga.