wandres.dev
NIVEL DIOS · Síntesis de WebGPU

El mapa de decisiones técnicas

Las siete decisiones que determinan la forma de un proyecto WebGPU, en el orden en que hay que tomarlas, con el criterio de cada una y las que solo parecen decisiones.

⏱ 22 min

Un proyecto gráfico se decide en siete bifurcaciones, y casi todas se toman en la primera semana sin darse cuenta de que se están tomando. El resto del trabajo es consecuencia. Esta lección pone las siete por escrito, en el orden correcto, con el criterio que resuelve cada una y con la advertencia de cuáles no admiten marcha atrás.

🎯 Al terminar esta lección sabrás
  • Ordenar las decisiones de un proyecto WebGPU de la más estructural a la más reversible.
  • Aplicar un criterio explícito a cada bifurcación en vez de copiar una arquitectura.
  • Distinguir las decisiones que condicionan el resto de las que se pueden cambiar el martes.
  • Reconocer las falsas decisiones que consumen debate sin cambiar nada.

El mapa

flowchart TB
A[Proyecto grafico en la web] --> B{WebGPU obligatorio o mejora}
B -->|Mejora progresiva| C[Ruta principal en WebGL2 y capa extra en WebGPU]
B -->|Obligatorio| D{Rasterizas o trazas rayos}
D -->|Trazado| E[Compute con BVH y acumulacion progresiva]
D -->|Rasterizacion| F{Cuantas luces dinamicas}
F -->|Menos de 8| G[Forward con prepass de profundidad]
F -->|Decenas o mas| H{Presupuesto de ancho de banda}
H -->|Movil o integrada| I[Clustered forward]
H -->|Escritorio dedicada| J[Clustered deferred]
G --> K{Cuantos objetos por fotograma}
I --> K
J --> K
K -->|Menos de mil| L[Culling en CPU y draws directos]
K -->|Decenas de miles| M[Culling en compute y draw indirect]
L --> N{Escala del mundo}
M --> N
N -->|Menos de 8 km| O[Coordenadas de mundo en f32]
N -->|Mayor| P[Coordenadas relativas a camara]
O --> Q[Medir antes de optimizar]
P --> Q
E --> Q
C --> Q
Q --> R{El cuello esta en computo o en memoria}
R -->|Computo| S[Menos operaciones y aproximaciones]
R -->|Memoria| T[Menos bytes y mas reutilizacion]
style A fill:#cba6f7,color:#11111b
style B fill:#f9e2af,color:#11111b
style D fill:#f9e2af,color:#11111b
style F fill:#f9e2af,color:#11111b
style H fill:#f9e2af,color:#11111b
style K fill:#f9e2af,color:#11111b
style N fill:#f9e2af,color:#11111b
style R fill:#f9e2af,color:#11111b
style C fill:#89b4fa,color:#11111b
style E fill:#fab387,color:#11111b
style G fill:#a6e3a1,color:#11111b
style I fill:#a6e3a1,color:#11111b
style J fill:#a6e3a1,color:#11111b
style L fill:#89b4fa,color:#11111b
style M fill:#fab387,color:#11111b
style O fill:#94e2d5,color:#11111b
style P fill:#94e2d5,color:#11111b
style Q fill:#cba6f7,color:#11111b
style S fill:#a6e3a1,color:#11111b
style T fill:#a6e3a1,color:#11111b

El mapa tiene una propiedad que conviene señalar antes de recorrerlo: las bifurcaciones están ordenadas por coste de cambio, de mayor a menor. La primera es prácticamente irreversible; la última se cambia en una tarde. Tomar las decisiones en otro orden es el origen de la mayoría de las reescrituras.

Las siete, una a una

Primera: obligatorio o mejora. Es la única decisión de producto de la lista y la que condiciona todas las demás, porque si WebGPU es una mejora sobre una base de WebGL2, no puedes usarlo para nada estructural. Se resuelve con dos números, la fracción de tus usuarios reales sin adaptador y el valor de un usuario perdido, tal y como está desarrollado en qué puedes asumir y qué no. Todo lo que sigue supone que la respuesta fue “obligatorio”.

Segunda: rasterizar o trazar rayos. Son dos motores distintos, no dos opciones de configuración. La rasterización tiene un coste proporcional a los triángulos y a los píxeles cubiertos, y produce un fotograma completo cada dieciséis milisegundos. El trazado tiene un coste proporcional a los rayos y produce una imagen que converge con el tiempo. El criterio es el modo de interacción: si el usuario mueve la cámara continuamente, rasterizas; si contempla, configura y espera, el trazado progresivo es viable y da una calidad que la rasterización no alcanza. La respuesta intermedia existe y es la buena en muchos configuradores: rasteriza mientras se mueve y traza cuando se para.

Tercera: cuántas luces dinámicas. Con menos de ocho, forward con prepass de profundidad gana en todo y cualquier otra cosa es complejidad gratis. Con decenas o cientos, el coste cuadrático te obliga a acotar qué luces ve cada fragmento, y ahí entra el clustered lighting. La frontera no es exactamente ocho: es el punto en que el producto de fragmentos por luces empieza a dominar tu perfil, y eso lo dice el reloj y no la tabla.

Cuarta: cuánto ancho de banda te puedes gastar. Es la que decide entre clustered forward y clustered deferred, y la respuesta depende del dispositivo más modesto al que apuntes. En una GPU integrada o móvil, escribir y releer un G-buffer completo es tráfico que no te puedes permitir y los problemas del deferred pesan más que sus ventajas. En escritorio con memoria dedicada, el G-buffer se paga solo en cuanto hay geometría compleja. El árbol completo, con los seis ejes de la decisión, está en el árbol de decisión de arquitectura.

Quinta: cuántos objetos por fotograma. Con menos de mil, el culling en CPU y los dibujados directos son más simples, más fáciles de depurar y perfectamente suficientes. Con decenas de miles, el coste de la CPU por objeto se convierte en el cuello y hay que mover el culling a compute y generar el buffer indirecto desde la GPU. El aviso importante: este cambio no es gratis en depurabilidad, porque a partir de él ya no puedes poner un punto de interrupción en el bucle que decide qué se dibuja.

Sexta: la escala del mundo. Es la decisión que más proyectos ha hundido por tomarse tarde. Si tu mundo cabe en unos pocos kilómetros con detalle de centímetro, las coordenadas de mundo en f32 funcionan. Si no, necesitas coordenadas relativas a la cámara desde el principio, porque introducirlas en un motor que ya funciona significa tocar todas las matrices, toda la física y todos los shaders. La cuenta que decide está en el problema de las escalas grandes y se hace en dos minutos.

Séptima: dónde está el cuello. Esta es la única que no se decide, se mide, y por eso está al final del mapa y por eso es la que se puede repetir cada semana. Los tres experimentos que la resuelven tardan media hora y descartan semanas de optimización mal dirigida. Si el cuello es de cómputo, reduces operaciones; si es de memoria, reduces bytes y aumentas la reutilización.

Las que no son decisiones

Hay un puñado de preguntas que consumen mucho debate y no cambian nada, y reconocerlas ahorra reuniones.

Qué tamaño de workgroup usar. No es una decisión de arquitectura, es un parámetro que se ajusta midiendo. Empieza en 64 para trabajo unidimensional y 8 por 8 para trabajo por píxel, hazlo un override de WGSL para poder cambiarlo sin tocar el fuente, y prueba tres valores cuando el kernel esté escrito. Lo que sí es una decisión, y de las duras, es si tu algoritmo cabe en la memoria compartida, porque eso cambia el algoritmo y no el número.

Si usar TypeScript. Con una API cuyos descriptores tienen quince campos anidados y cuyos errores son de validación en tiempo de ejecución, los tipos no son una preferencia estilística: son el mecanismo que convierte la mitad de esos errores en fallos de compilación.

Si etiquetar los objetos. No hay ninguna razón para no hacerlo. Cuesta cero en tiempo de ejecución y transforma los mensajes de error, según se ve en las etiquetas lo cambian todo.

Si medir con timestamp queries. Tampoco hay debate: se hace, y si la feature no está, el perfilador devuelve null en vez de ceros. El detalle está en las timestamp queries.

Si escribir la ruta de reserva. Esa sí es una decisión, pero no es técnica; es la primera bifurcación del mapa disfrazada de segunda pregunta. Si tu equipo la está debatiendo en términos de esfuerzo de implementación, es que la primera decisión no se tomó nunca.

Y una última que se confunde constantemente con una decisión de arquitectura: si escribir tu propio motor o usar uno existente. El criterio es honesto y sencillo. Un motor de escena resuelve la carga de recursos, el grafo, los materiales, las sombras y el post-proceso, que es entre el setenta y el noventa por ciento del trabajo de un proyecto normal. Escribes el tuyo cuando tu render no se parece a lo que ese motor hace bien: un trazador de rayos, una simulación de partículas de millones de elementos, una visualización con un pipeline muy específico. Escribir un motor propio para dibujar mallas con materiales estándar es una decisión de aprendizaje perfectamente legítima y una mala decisión de producto, y conviene saber cuál de las dos estás tomando.

El orden de las decisiones importa más que las decisiones, y el error caro siempre es el mismo

Si tuvieras que quedarte con una sola idea de este mapa, que sea esta: las decisiones baratas no deben tomarse antes que las caras, aunque sean más divertidas. El patrón de fracaso que se repite en todos los proyectos gráficos que se reescriben es sorprendentemente uniforme. Alguien empieza por la séptima decisión, la optimización, porque es la que tiene retroalimentación inmediata y se puede medir; luego escoge la arquitectura de iluminación porque es la que aparece en los artículos; y deja la escala del mundo y la portabilidad para el final, porque “eso se resuelve luego”. Y las dos que dejó para el final son precisamente las dos que no se pueden añadir: las coordenadas relativas a cámara y la ruta de reserva no son características, son propiedades del diseño, y una propiedad no se atornilla al terminar. El motor que sobrevive es el que resuelve las decisiones en orden inverso a lo apetecible: primero la de producto, después la de escala numérica, después la de arquitectura de render, y solo al final la optimización, que además es la única que se puede revisar cada semana sin coste. Hay una prueba de un minuto para saber si has hecho esto bien, y funciona en cualquier proyecto: pregúntate qué pasaría si mañana tuvieras que hacer que el mundo fuera cien veces más grande. Si la respuesta es “cambiar una función que construye la matriz de modelo y vista”, vas bien. Si la respuesta es “reescribir”, no tomaste la sexta decisión: la tomaste por omisión, y la omisión eligió por ti.

⚔️ Recorre tu propio mapa
  1. Recorre las siete bifurcaciones con tu proyecto actual y anota qué respuesta tienes en cada una. Marca cuáles decidiste conscientemente y cuáles decidió la inercia.
  2. Para las que decidió la inercia, calcula qué costaría cambiarlas hoy. Ese número es tu deuda de arquitectura.
  3. Haz la prueba del minuto: escribe qué habría que tocar si el mundo fuera cien veces más grande.
  4. Ejecuta los tres experimentos de la séptima decisión y comprueba si el cuello que tienes es el que creías.