1 async function helloTriangle() {
3 document.body.className = 'error';
7 const adapter = await navigator.gpu.requestAdapter();
8 const device = await adapter.requestDevice();
10 /*** Shader Setup ***/
13 const positionLocation = 0;
14 const colorLocation = 1;
16 const shaderSource = `
17 #include <metal_stdlib>
19 using namespace metal;
22 float4 position [[attribute(${positionLocation})]];
23 float4 color [[attribute(${colorLocation})]];
27 float4 position [[position]];
31 vertex FragmentData vertexMain(const Vertex in [[stage_in]])
33 return FragmentData { in.position, in.color };
36 fragment float4 fragmentMain(const FragmentData in [[stage_in]])
41 const shaderModule = device.createShaderModule({ code: shaderSource });
43 /* GPUPipelineStageDescriptors */
44 const vertexStageDescriptor = { module: shaderModule, entryPoint: "vertexMain" };
45 const fragmentStageDescriptor = { module: shaderModule, entryPoint: "fragmentMain" };
47 /*** Vertex Buffer Setup ***/
50 const colorOffset = 4 * 4; // 4 floats of 4 bytes each.
51 const vertexStride = 8 * 4;
52 const vertexDataSize = vertexStride * 3;
54 /* GPUBufferDescriptor */
55 const vertexBufferDescriptor = {
57 usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.VERTEX
60 const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
62 /*** Write Data To GPU ***/
64 const vertexArrayBuffer = await vertexBuffer.mapWriteAsync();
65 const vertexWriteArray = new Float32Array(vertexArrayBuffer);
66 vertexWriteArray.set([
67 // x, y, z, w, r, g, b, a
68 0, 0.8, 0, 1, 0, 1, 1, 1,
69 -0.8, -0.8, 0, 1, 1, 1, 0, 1,
70 0.8, -0.8, 0, 1, 1, 0, 1, 1
74 /*** Describe Vertex Data For Pipeline ***/
76 const vertexBufferSlot = 0;
78 /* GPUVertexAttributeDescriptors */
79 const positionAttribute = {
80 shaderLocation: positionLocation,
81 inputSlot: vertexBufferSlot,
85 const colorAttribute = {
86 shaderLocation: colorLocation,
87 inputSlot: vertexBufferSlot,
92 /* GPUVertexInputDescriptor */
93 const vertexInputDescriptor = {
94 inputSlot: vertexBufferSlot,
99 /* GPUInputStateDescriptor */
100 const inputStateDescriptor = {
101 attributes: [positionAttribute, colorAttribute],
102 inputs: [vertexInputDescriptor]
105 /*** Finish Pipeline State ***/
107 /* GPUBlendDescriptors */
108 const alphaBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
109 const colorBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
111 /* GPUColorStateDescriptor */
112 const colorStateDescriptor = {
113 format: "bgra8unorm",
114 alphaBlend: alphaBlendDescriptor,
115 colorBlend: colorBlendDescriptor,
116 writeMask: GPUColorWriteBits.ALL
119 /* GPURenderPipelineDescriptor */
120 const renderPipelineDescriptor = {
121 vertexStage: vertexStageDescriptor,
122 fragmentStage: fragmentStageDescriptor,
123 primitiveTopology: "triangle-list",
124 colorStates: [colorStateDescriptor],
125 inputState: inputStateDescriptor
127 /* GPURenderPipeline */
128 const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
130 /*** Swap Chain Setup ***/
132 const canvas = document.querySelector("canvas");
133 let canvasSize = canvas.getBoundingClientRect();
134 canvas.width = canvasSize.width;
135 canvas.height = canvasSize.height;
137 const gpuContext = canvas.getContext("gpu");
139 /* GPUSwapChainDescriptor */
140 const swapChainDescriptor = { device: device, format: "bgra8unorm" };
142 const swapChain = gpuContext.configureSwapChain(swapChainDescriptor);
144 /*** Render Pass Setup ***/
146 /* Acquire Texture To Render To */
149 const swapChainTexture = swapChain.getCurrentTexture();
151 const renderAttachment = swapChainTexture.createDefaultView();
154 const darkBlue = { r: 0, g: 0, b: 0.5, a: 1 };
156 /* GPURenderPassColorATtachmentDescriptor */
157 const colorAttachmentDescriptor = {
158 attachment: renderAttachment,
164 /* GPURenderPassDescriptor */
165 const renderPassDescriptor = { colorAttachments: [colorAttachmentDescriptor] };
169 /* GPUCommandEncoder */
170 const commandEncoder = device.createCommandEncoder();
171 /* GPURenderPassEncoder */
172 const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
174 renderPassEncoder.setPipeline(renderPipeline);
175 renderPassEncoder.setVertexBuffers(vertexBufferSlot, [vertexBuffer], [0]);
176 renderPassEncoder.draw(3, 1, 0, 0); // 3 vertices, 1 instance, 0th vertex, 0th instance.
177 renderPassEncoder.endPass();
179 /* GPUComamndBuffer */
180 const commandBuffer = commandEncoder.finish();
183 const queue = device.getQueue();
184 queue.submit([commandBuffer]);
187 window.addEventListener("DOMContentLoaded", helloTriangle);