wandres.dev
ONTOLOGÍA · El mapa de WebGPU

El mapa del territorio: las cuatro regiones de WebGPU

Cómo se divide el conocimiento de WebGPU en cuatro regiones, en qué orden conviene recorrerlas y qué problema real resuelve cada una.

⏱ 16 min

El material de aprendizaje de WebGPU tiende a ser lineal: primero el triángulo, luego el cubo, luego texturas, luego cómputo. Funciona para llegar a la primera demo y falla en cuanto quieres construir algo, porque no dice dónde estás ni qué te falta. La API se organiza mejor como cuatro regiones con dependencias claras entre ellas, y saber en cuál vive tu problema actual es lo que convierte «no sé por qué esto no funciona» en una pregunta contestable.

🎯 Al terminar esta lección sabrás
  • Nombrar las cuatro regiones de la API y el problema que resuelve cada una.
  • Identificar en qué región vive un síntoma concreto para acotar la depuración.
  • Explicar por qué render y cómputo comparten tres de las cuatro regiones.
  • Ordenar el aprendizaje según dependencias reales y no según la demo más vistosa.

Las cuatro regiones

Región uno: la iniciación

Es todo lo que ocurre entre que la página carga y que tienes un GPUDevice utilizable y un canvas configurado. Ocupa unas veinte líneas, se escribe una vez por proyecto y concentra una cantidad desproporcionada de los problemas de producción.

Lo que se decide aquí: si hay WebGPU en este navegador y qué haces si no; qué adaptador pides y con qué preferencia de potencia; qué capacidades opcionales necesitas y qué haces si faltan; qué límites necesitas por encima del mínimo garantizado; qué formato de color usa el canvas y cómo se compone con el resto de la página; y qué pasa cuando el sistema operativo decide reiniciar el controlador gráfico a mitad de sesión.

Ninguna de esas preguntas aparece en un tutorial de triángulo, y todas aparecen cuando publicas. Es la región con la peor relación entre lo poco que se enseña y lo mucho que cuesta ignorarla.

Región dos: los datos

Memoria de la GPU y cómo llenarla. GPUBuffer y GPUTexture son los dos únicos tipos de almacenamiento que existen, y todo lo demás son formas de mirarlos: una vista de textura, un sampler que describe cómo interpolar, un bind group que agrupa referencias.

La dificultad de esta región no es la API, que es pequeña, sino el modelo de memoria. Hay tres preguntas que hay que saber contestar sin dudar: dónde vive un dato en cada momento, quién puede leerlo y quién puede escribirlo, y qué cuesta moverlo de un sitio a otro. WebGPU no expone la memoria directamente, pero sí expone las consecuencias: los flags de usage declaran de antemano para qué vas a usar un búfer y limitan lo que puedes hacer con él, la escritura desde JavaScript pasa por caminos distintos según el caso, y la lectura de vuelta desde la GPU tiene una latencia que no se puede esconder.

Aquí viven también las reglas de alineación, que son el generador número uno de bugs silenciosos en WebGPU: un struct de WGSL con un vec3 en medio no ocupa lo que parece, y si tu código de JavaScript escribe los bytes con el desplazamiento equivocado no hay ningún error, solo valores absurdos.

Región tres: los programas

WGSL y las tuberías. Un shader es un programa que se compila a un GPUShaderModule, y un pipeline es la configuración completa de una ejecución: qué shaders, con qué entradas, con qué estado fijo alrededor.

WGSL es un lenguaje con tipado estricto y sintaxis inspirada en Rust: declaraciones con var y let, tipos a la derecha, atributos con arroba como @group, @binding, @location y @builtin, y funciones de entrada marcadas con @vertex, @fragment o @compute. La curva de aprendizaje no está en la sintaxis, que se aprende en una tarde, sino en los espacios de dirección: una variable en WGSL vive en function, private, workgroup, uniform, storage o handle, y el espacio determina quién la ve, cuánto dura y cuánto cuesta leerla.

Los pipelines son donde el estado gráfico se hace explícito. Un GPURenderPipeline fija de una vez la topología de las primitivas, el sentido de las caras frontales, el descarte de caras, el formato de profundidad, la comparación de profundidad, el número de muestras, los formatos de salida y la ecuación de mezcla de cada una. Todo eso se valida al crearlo. La consecuencia práctica es que cada combinación distinta de estado es un pipeline distinto, y una aplicación real tiene decenas.

Región cuatro: los comandos

Cómo se le dice a la GPU que trabaje. Un GPUCommandEncoder graba una secuencia de comandos, los pases delimitan ámbitos dentro de esa secuencia, finish() produce un GPUCommandBuffer inmutable y queue.submit() lo entrega.

Es la región más pequeña y la que más cambia la forma de pensar, porque introduce una separación temporal que WebGL no tenía: grabar no es ejecutar. Cuando submit() retorna, no ha pasado nada todavía. La GPU ejecutará ese trabajo cuando le toque, y tu código sigue corriendo mientras tanto. De ahí salen las dos consecuencias que definen la arquitectura de cualquier aplicación seria: que el coste de CPU de preparar un fotograma se puede solapar con el trabajo de GPU del fotograma anterior, y que leer un resultado de vuelta obliga a esperar de verdad, con todo lo que eso implica.

flowchart LR
R1[Region 1 iniciacion] --> R2[Region 2 datos]
R2 --> R3[Region 3 programas]
R3 --> R4[Region 4 comandos]
R2 --> R4
R4 --> render[Camino de render]
R4 --> compute[Camino de computo]
style R1 fill:#cba6f7,color:#11111b
style R2 fill:#94e2d5,color:#11111b
style R3 fill:#89b4fa,color:#11111b
style R4 fill:#f9e2af,color:#11111b
style render fill:#a6e3a1,color:#11111b
style compute fill:#fab387,color:#11111b

Las dos cajas de la derecha son la razón de que este mapa sea útil. Render y cómputo se bifurcan solo en la región cuatro y en una parte de la tres. Comparten la iniciación entera, los recursos enteros, el lenguaje entero y el modelo de comandos entero. Lo único que les distingue es el tipo de pipeline y el tipo de pase. Quien aprende bien las regiones uno y dos aprende cómputo en una tarde.

💡
Dónde vive tu síntoma

La utilidad diaria del mapa es acotar. Pantalla negra sin errores en consola: región uno o cuatro, casi siempre el formato del canvas o un loadOp mal puesto. Geometría deformada o colores absurdos: región dos, alineación. Error de validación al crear algo: región tres, un descriptor incoherente. Todo correcto pero lento: región cuatro para el coste de CPU, región dos para el ancho de banda.

El orden que funciona

El orden natural del mapa es también el orden de aprendizaje correcto, con una excepción deliberada.

Primero iniciación, porque sin dispositivo no hay nada y porque hacerlo bien desde el principio evita reescribirlo cuando descubres la pérdida de dispositivo. Luego datos, porque los búferes son el objeto más simple de la API y el modelo de memoria es el conocimiento que más se transfiere al resto. Luego comandos con un pipeline mínimo, que es la excepción: conviene ver un triángulo en pantalla antes de estudiar WGSL a fondo, porque un ciclo de retroalimentación visual acelera todo lo que viene después. Y solo entonces programas en serio.

Lo que se aprende después de eso es una ampliación de las mismas cuatro regiones, no una quinta: las texturas amplían los datos, los bind groups amplían la organización de los datos, el cómputo amplía los comandos, y la depuración y el rendimiento son transversales.

El error de aprendizaje más caro es empezar por el render

Casi todo el mundo llega a WebGPU queriendo dibujar algo, y por eso casi todo el mundo empieza por la ruta de render: vértices, rasterizador, fragmentos, canvas. Es la ruta con más piezas móviles simultáneas y con la peor observabilidad de toda la API, porque el resultado es una imagen: si sale negra, el fallo puede estar en cualquiera de doce sitios y la imagen no te dice en cuál.

La ruta de cómputo tiene exactamente el mismo esqueleto —dispositivo, búferes, módulo, pipeline, encoder, pase, submit— con tres piezas menos y una propiedad decisiva: el resultado es un array de números que puedes imprimir. Un console.log de treinta y dos floats te dice si el problema es el índice de invocación, la alineación del búfer, el binding o el algoritmo, y te lo dice en el primer intento.

De modo que el consejo que casi nadie da: si te atascas en el triángulo, escribe primero un compute shader que sume dos arrays. Son cincuenta líneas, ejercita el 80% del modelo mental que necesita el render, y cuando vuelvas al triángulo lo único nuevo que quedará por entender será el rasterizador. La observabilidad no es un lujo de depuración; es una estrategia de aprendizaje.

Queda una pregunta antes de tocar código: dónde encaja WebGPU dentro de la plataforma web y con qué convive. Eso está en dónde encaja WebGPU, y el origen de la forma de la API en las tres APIs nativas.