wandres.dev
ONTOLOGÍA · El mapa de WebGPU

Dónde encaja WebGPU en la plataforma web

Con qué convive WebGPU dentro del navegador, cómo se relaciona con canvas, workers, WebAssembly y las bibliotecas de alto nivel, y cuándo la decisión correcta es no usarla directamente.

⏱ 17 min

WebGPU no llega a una plataforma vacía. Llega a un navegador que ya tiene canvas 2D, WebGL2, WebAssembly, workers, OffscreenCanvas y un ecosistema de bibliotecas de render con diez años de recorrido. Saber qué relación tiene con cada una de esas piezas es lo que determina si tu proyecto va a usar WebGPU directamente, a través de una biblioteca, o no va a usarla en absoluto y va a estar bien así.

🎯 Al terminar esta lección sabrás
  • Situar WebGPU entre las demás APIs de dibujo y cómputo del navegador.
  • Explicar cómo se combina con workers, OffscreenCanvas y WebAssembly.
  • Decidir con criterio entre WebGPU directo y una biblioteca de alto nivel.
  • Aplicar mejora progresiva sobre WebGL2 con una detección que no rompe la página.

El vecindario

Cuatro APIs del navegador dibujan píxeles y dos calculan. Conviene tenerlas ordenadas por lo que cuestan y por lo que permiten.

Canvas 2D es la más alta y la más cómoda: rutas, texto, imágenes, transformaciones. Está acelerada por GPU en todos los navegadores modernos, pero no expone nada del hardware. Para interfaces, gráficas y visualización 2D sigue siendo la respuesta correcta y nadie debería sustituirla por WebGPU sin un motivo medido.

WebGL2 es la API gráfica de cobertura. Rasterización programable con GLSL ES 3.0, sin cómputo, con máquina de estados global. Funciona en prácticamente cualquier dispositivo con capacidad gráfica de la última década.

WebGPU es la API de cómputo y render de esta generación. Más capacidades, menos coste de CPU, más verbosidad, menos cobertura.

WebXR no dibuja: define sesiones inmersivas, seguimiento de pose y capas de presentación, y delega el dibujado en WebGL o WebGPU. La integración de WebXR con WebGPU es más reciente que la de WebGL y su disponibilidad varía por plataforma.

Del lado del cómputo, WebAssembly ejecuta en la CPU y WebNN expone aceleradores de inferencia. WebNN y WebGPU no compiten: WebNN busca usar la NPU cuando existe y WebGPU es el camino cuando no. Las bibliotecas de aprendizaje automático en el navegador suelen tener rutas para ambas y elegir en tiempo de ejecución.

📝
Contexto por canvas, uno y solo uno

Un elemento canvas tiene un único contexto durante toda su vida. Si pides getContext("2d") y luego getContext("webgpu") sobre el mismo elemento, la segunda llamada devuelve null. Para superponer una capa 2D sobre una escena de WebGPU se usan dos elementos canvas apilados con CSS, no un canvas con dos contextos.

Fuera del hilo principal y fuera del navegador

Workers y OffscreenCanvas

WebGPU está disponible en workers, y esa disponibilidad es más importante de lo que parece. WorkerNavigator.gpu existe, lo que significa que se puede pedir un adaptador y un dispositivo desde un worker dedicado y grabar y enviar todos los comandos desde ahí.

La pieza que lo hace útil es OffscreenCanvas. Un canvas del documento se transfiere a un worker con transferControlToOffscreen(), y a partir de ese momento el worker es el dueño del contexto y puede configurarlo y dibujar sin tocar el hilo principal:

// hilo principal
const canvas = document.querySelector('#lienzo');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('./render.js', { type: 'module' });
worker.postMessage({ canvas: offscreen }, [offscreen]);
// render.js, dentro del worker
self.onmessage = async (e) => {
  const canvas = e.data.canvas;
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();
  const ctx = canvas.getContext('webgpu');
  ctx.configure({ device, format: navigator.gpu.getPreferredCanvasFormat() });
  // A partir de aqui el bucle de render vive fuera del hilo principal.
};

El beneficio no es que la GPU vaya más rápido: es que el trabajo de CPU de preparar los comandos deja de competir con el layout, el estilo y los manejadores de eventos de la página. En una aplicación donde la escena convive con una interfaz de verdad, eso es la diferencia entre un desplazamiento fluido y uno que se atasca.

Un matiz de disponibilidad que conviene comprobar antes de apoyarse en ello: el soporte de WebGPU en service workers no está garantizado en todas las implementaciones, y la ruta fiable es un worker dedicado.

WebAssembly y el código nativo

Las dos implementaciones de referencia de WebGPU, Dawn y wgpu, son bibliotecas nativas que además compilan a WebAssembly. Eso produce una propiedad poco común en la plataforma web: el mismo código de gráficos puede ejecutarse como binario de escritorio y como página web.

En la práctica se ve en dos direcciones. Un proyecto en Rust que usa wgpu compila a nativo con Vulkan o Metal por debajo, y compila a wasm32-unknown-unknown con WebGPU por debajo, sin cambiar la lógica de render. Un proyecto en C o C++ que usa Dawn hace lo equivalente a través de Emscripten, que traduce las llamadas de la API C de WebGPU a llamadas de JavaScript.

Para quien escribe JavaScript esto importa por una razón indirecta: significa que buena parte de la documentación, los ejemplos y las técnicas de WebGPU que encontrarás están escritas en Rust o en C++, y son transferibles casi literalmente porque el modelo de objetos es idéntico.

Directo o a través de una biblioteca

Es la decisión que más tiempo ahorra o cuesta, y tiene una respuesta razonablemente clara según el caso.

Usa una biblioteca de alto nivel si tu problema es una escena: modelos cargados de un archivo, materiales físicamente correctos, luces, sombras, cámara orbital, post-proceso. Todo eso son meses de trabajo que ya están hechos, y hacerlos peor por tu cuenta no es una victoria técnica. Three.js con WebGPURenderer y Babylon.js cubren ese terreno, y ambos caen a WebGL cuando WebGPU no está disponible, lo que resuelve el problema de cobertura de paso.

Usa WebGPU directamente si tu problema no es una escena: simulación, cómputo general, visualización de datos con millones de puntos, procesado de imagen, un renderizador con una arquitectura que no encaja en el modelo de una biblioteca general. En esos casos la biblioteca no te ahorra nada y sí te estorba, porque su abstracción está pensada para otro problema.

Usa las dos es una opción legítima y poco explorada: una escena en una biblioteca y un pase de cómputo propio que comparte búferes con ella. Requiere entender WebGPU a fondo de todos modos.

Mejora progresiva, no sustitución

La detección de soporte es tres líneas y hay dos formas de escribirla mal. La primera es comprobar solo navigator.gpu, que existe en navegadores donde requestAdapter() devuelve null porque el hardware o el controlador están en la lista de bloqueo. La segunda es no envolver nada en try, lo que convierte una falta de soporte en una excepción sin capturar que se lleva por delante el resto de la página.

export async function detectarWebGPU() {
  if (!navigator.gpu) return { soportado: false, motivo: 'sin-api' };
  try {
    const adapter = await navigator.gpu.requestAdapter();
    if (!adapter) return { soportado: false, motivo: 'sin-adaptador' };
    const device = await adapter.requestDevice();
    return { soportado: true, adapter, device };
  } catch (err) {
    return { soportado: false, motivo: 'fallo', error: err };
  }
}

Los tres motivos son distintos y merecen respuestas distintas. sin-api es un navegador antiguo o un contexto no seguro: WebGPU solo está disponible en contextos seguros, así que una página servida por HTTP plano no lo tiene aunque el navegador lo soporte. sin-adaptador es un navegador con la API pero sin hardware utilizable, típicamente por lista de bloqueo de controladores. fallo es cualquier otra cosa.

En 2026 la posición defendible es la que ya funcionaba en 2024: WebGL2 sigue siendo la base más segura por cobertura de dispositivos antiguos, y el enfoque correcto es la mejora progresiva. Diseña la experiencia para que funcione sin WebGPU y usa WebGPU para lo que no se puede hacer sin ella. Si tu producto necesita cómputo en GPU de forma esencial, entonces WebGPU es un requisito y lo que tienes que diseñar es qué ve quien no lo tiene.

El fallback que nadie prueba es el fallback que no existe

Todo el mundo escribe la rama del else. Casi nadie la ejecuta más de una vez. Y como la rama de WebGPU es la que se desarrolla a diario en la máquina del equipo, que tiene WebGPU, el camino degradado se pudre en silencio durante meses hasta que llega a un usuario real.

Hay dos disciplinas que lo arreglan y las dos son de proceso, no de código. La primera: un interruptor por parámetro de URL que fuerce el camino sin WebGPU, comprobado en cada revisión igual que se comprueba el camino bueno. Simular la ausencia es trivial —basta con leer un flag antes de tocar navigator.gpu— y sin ese interruptor nadie va a desinstalar su GPU para probar. La segunda: decidir de antemano qué se degrada y escribirlo. «Sin WebGPU no hay simulación de fluidos, hay una textura animada precalculada» es una decisión de producto que hay que tomar con la cabeza fría al principio, no con prisa el día del lanzamiento.

Y un detalle que muerde tarde: la pérdida de dispositivo puede ocurrir a mitad de sesión, no solo al arrancar. Un portátil que cambia de GPU integrada a discreta, una actualización de controlador, una pestaña que el sistema decide sacrificar por memoria. Si tu camino degradado solo se puede tomar en el arranque, esa sesión se acabó.

Con el territorio delimitado, lo que queda es entender qué motivó exactamente el rediseño. Eso empieza por la máquina de estados de WebGL, y el mapa completo está en las cuatro regiones.