2.5 Tu primer programa WebGPU (Hello Graphics)
Solo para completar, puedes ver un ejemplo “mínimo” de un programa WebGPU que muestra algo gráficamente (triángulo) en la pantalla. Si bien la lista solo muestra un simple triángulo verde (Figura 2.5), el código de configuración es bastante largo. La API WebGPU no tiene “valores predeterminados” (no se ocultan), la configuración debe ser definida por ti. Por lo tanto, debes incluir un “shader” simple. Aprenderás más sobre el lenguaje de sombreado WGSL en detalle más adelante, pero por ahora, para poner en funcionamiento un programa gráfico básico, se incluye aquí. El programa simplemente pasa los valores a la salida (sin transformaciones complejas ni búferes).
let canvas = document.createElement('canvas');
document.body.appendChild( canvas );
console.log( canvas );
canvas.width = canvas.height = 512;
console.log( 'w:', canvas.width, 'h:', canvas.height );
let wgsltxt = `
[[stage(vertex)]]
fn main_vs([[builtin(vertex_index)]] VertexIndex : u32)
-> [[builtin(position)]] vec4<f32>
{
var pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
vec2<f32>(0.0, 0.5),
vec2<f32>(-0.5, -0.5),
vec2<f32>(0.5, -0.5));
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
}
[[stage(fragment)]]
fn main_fs() ->[[location(0)]] vec4<f32>
{
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
}
`;
const gpu = navigator.gpu;
const adapter = await gpu.requestAdapter();
const device = await adapter.requestDevice();
// context type 'gpupresent' is deprecated. Use 'webgpu' instead.
// const ctx = canvas.getContext("gpupresent");
const ctx = canvas.getContext("webgpu");
let configuration = {
device: device,
format: ctx.getPreferredFormat(adapter),
size: { // the size of the canvas element in pixels
width: canvas.width,
height: canvas.height }
};
const res = ctx.configure( configuration );
console.log( 'getCurrentTexture():', ctx.getCurrentTexture() );
const wgsl = device.createShaderModule({
code: wgsltxt
});
const pipeline = device.createRenderPipeline({
vertex: { module: wgsl, entryPoint: "main_vs" },
fragment: { module: wgsl, entryPoint: "main_fs",
targets: [{ format: "bgra8unorm" }] },
primitive: { topology: "triangle-list" }
});
let render = function () {
const commandEncoder = device.createCommandEncoder();
const textureView = ctx.getCurrentTexture().createView();
const renderPassDescriptor = {
colorAttachment: [ { view: textureView,
loadValue: { r: 1, g: 1, b: 1, a: 1 },
storeOp: 'store' }
]
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.draw(3, 1, 0, 0);
passEncoder.endPass();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(render);
};
requestAnimationFrame(render);Para ver lo que estás dibujando, crearás un HTMLCanvasElement y configurarás un Canvas Context a partir de ese lienzo. Un Canvas Context administra una serie de texturas que usarás para presentar la salida de renderizado final en tu elemento <canvas>.
Sombreador de vértices (escrito en el lenguaje de sombreado WGSL)
El sombreador de fragmentos (o píxeles) (escrito en el lenguaje de sombreado WGSL) realiza cálculos en cada “píxel”. El ejemplo es muy minimalista y simplemente devuelve un color fijo para cada píxel (verde).