<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>WebGPU Life</title>
</head>
<body>
<canvas width="512" height="512"></canvas>
<script type="module">
const canvas = document.querySelector("canvas");
if (!navigator.gpu) {
throw new Error("WebGPU not supported on this browser.");
}
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
throw new Error("No appropriate GPUAdapter found.");
}
const device = await adapter.requestDevice();
const context = canvas.getContext("webgpu");
const devicePixelRatio = window.devicePixelRatio || 1;
const presentationSize = [
canvas.Width * devicePixelRatio,
canvas.Height * devicePixelRatio,
];
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device: device,
format: presentationFormat,
size: [canvas.Width,canvas.Height],
});
const vertices = new Float32Array([
// X, Y,
-0.8, 0, // Triangle 1 (Blue)
0.8, 0,
0, 0.8,
]);
const vertexBuffer = device.createBuffer({
label: "Cell vertices",
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, /*bufferOffset=*/0, vertices);
const vertexBufferLayout = {
arrayStride: 2*4,
attributes: [{
format: "float32x2",
offset: 0,
shaderLocation: 0, // Position, see vertex shader
}],
};
const cellShaderModule = device.createShaderModule({
label: 'Cell shader',
code: `
@vertex
fn vertexMain(@location(0) pos: vec2f) ->@builtin(position) vec4f {
return vec4f(pos, 0, 1);
}
@fragment
fn fragmentMain() -> @location(0) vec4f {
return vec4f(1, 0, 0, 1);
}
`
});
const sampleCount = 4;
/* 共4步,第一步
multisample:{
count:sampleCount
}
*/
const cellPipeline = device.createRenderPipeline({
label: "Cell pipeline",
layout: "auto",
vertex: {
module: cellShaderModule,
entryPoint: "vertexMain",
buffers: [vertexBufferLayout]
},
fragment: {
module: cellShaderModule,
entryPoint: "fragmentMain",
targets: [{
format: presentationFormat
}]
},
primitive:{
topology:'triangle-list'
},
multisample:{
count:sampleCount
}
});
/* 共4步,第2步
const texture = device.createTexture({
*/
const texture = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount,
format: presentationFormat,
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
const view = texture.createView();
/*共4步,第3步
view:view,
共4步,第4步
resolveTarget: context.getCurrentTexture().createView(),
*/
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [
{
view:view,
resolveTarget: context.getCurrentTexture().createView(),
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'discard',
},
],
});
pass.setPipeline(cellPipeline);
pass.setVertexBuffer(0, vertexBuffer);
pass.draw(3);
pass.end();
const commandBuffer = encoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>