a56d337c78b5588b46589d80a7b640b2a3efb332
[WebKit-https.git] / Websites / webkit.org / demos / webgpu / scripts / hello-triangle.js
1 async function helloTriangle() {
2     if (!navigator.gpu) {
3         document.body.className = 'error';
4         return;
5     }
6
7     const adapter = await navigator.gpu.requestAdapter();
8     const device = await adapter.requestDevice();
9     
10     /*** Shader Setup ***/
11     
12     /* GPUShaderModule */
13     const positionLocation = 0;
14     const colorLocation = 1;
15     
16     const shaderSource = `
17     #include <metal_stdlib>
18   
19     using namespace metal;
20   
21     struct Vertex {
22         float4 position [[attribute(${positionLocation})]];
23         float4 color [[attribute(${colorLocation})]];
24     };
25   
26     struct FragmentData {
27         float4 position [[position]];
28         float4 color;
29     };
30   
31     vertex FragmentData vertexMain(const Vertex in [[stage_in]]) 
32     {
33         return FragmentData { in.position, in.color };
34     }
35   
36     fragment float4 fragmentMain(const FragmentData in [[stage_in]])
37     {
38         return in.color;
39     }
40     `;
41     const shaderModule = device.createShaderModule({ code: shaderSource });
42     
43     /* GPUPipelineStageDescriptors */
44     const vertexStageDescriptor = { module: shaderModule, entryPoint: "vertexMain" };
45     const fragmentStageDescriptor = { module: shaderModule, entryPoint: "fragmentMain" };
46     
47     /*** Vertex Buffer Setup ***/
48     
49     /* Vertex Data */
50     const colorOffset = 4 * 4; // 4 floats of 4 bytes each.
51     const vertexStride = 8 * 4;
52     const vertexDataSize = vertexStride * 3;
53     
54     /* GPUBufferDescriptor */
55     const vertexBufferDescriptor = { 
56         size: vertexDataSize,
57         usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.VERTEX
58     };
59     /* GPUBuffer */
60     const vertexBuffer = device.createBuffer(vertexBufferDescriptor);
61     
62     /*** Write Data To GPU ***/
63     
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
71     ]);
72     vertexBuffer.unmap();
73     
74     /*** Describe Vertex Data For Pipeline ***/
75     
76     const vertexBufferSlot = 0;
77     
78     /* GPUVertexAttributeDescriptors */
79     const positionAttribute = {
80         shaderLocation: positionLocation,
81         inputSlot: vertexBufferSlot,
82         offset: 0,
83         format: "float4"
84     };
85     const colorAttribute = {
86         shaderLocation: colorLocation,
87         inputSlot: vertexBufferSlot,
88         offset: colorOffset,
89         format: "float4"
90     };
91     
92     /* GPUVertexInputDescriptor */
93     const vertexInputDescriptor = {
94         inputSlot: vertexBufferSlot,
95         stride: vertexStride,
96         stepMode: "vertex"
97     };
98     
99     /* GPUInputStateDescriptor */
100     const inputStateDescriptor = {
101         attributes: [positionAttribute, colorAttribute],
102         inputs: [vertexInputDescriptor]
103     };
104     
105     /*** Finish Pipeline State ***/
106     
107     /* GPUBlendDescriptors */
108     const alphaBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
109     const colorBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
110     
111     /* GPUColorStateDescriptor */
112     const colorStateDescriptor = {
113         format: "bgra8unorm",
114         alphaBlend: alphaBlendDescriptor,
115         colorBlend: colorBlendDescriptor,
116         writeMask: GPUColorWriteBits.ALL
117     };
118     
119     /* GPURenderPipelineDescriptor */
120     const renderPipelineDescriptor = {
121         vertexStage: vertexStageDescriptor,
122         fragmentStage: fragmentStageDescriptor,
123         primitiveTopology: "triangle-list",
124         colorStates: [colorStateDescriptor],
125         inputState: inputStateDescriptor
126     };
127     /* GPURenderPipeline */
128     const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
129     
130     /*** Swap Chain Setup ***/
131     
132     const canvas = document.querySelector("canvas");
133     let canvasSize = canvas.getBoundingClientRect();
134     canvas.width = canvasSize.width;
135     canvas.height = canvasSize.height;
136
137     const gpuContext = canvas.getContext("gpu");
138     
139     /* GPUSwapChainDescriptor */
140     const swapChainDescriptor = { device: device, format: "bgra8unorm" };
141     /* GPUSwapChain */
142     const swapChain = gpuContext.configureSwapChain(swapChainDescriptor);
143     
144     /*** Render Pass Setup ***/
145     
146     /* Acquire Texture To Render To */
147     
148     /* GPUTexture */
149     const swapChainTexture = swapChain.getCurrentTexture();
150     /* GPUTextureView */
151     const renderAttachment = swapChainTexture.createDefaultView();
152     
153     /* GPUColor */
154     const darkBlue = { r: 0, g: 0, b: 0.5, a: 1 };
155     
156     /* GPURenderPassColorATtachmentDescriptor */
157     const colorAttachmentDescriptor = {
158         attachment: renderAttachment,
159         loadOp: "clear",
160         storeOp: "store",
161         clearColor: darkBlue
162     };
163     
164     /* GPURenderPassDescriptor */
165     const renderPassDescriptor = { colorAttachments: [colorAttachmentDescriptor] };
166     
167     /*** Rendering ***/
168     
169     /* GPUCommandEncoder */
170     const commandEncoder = device.createCommandEncoder();
171     /* GPURenderPassEncoder */
172     const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
173     
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();
178     
179     /* GPUComamndBuffer */
180     const commandBuffer = commandEncoder.finish();
181     
182     /* GPUQueue */
183     const queue = device.getQueue();
184     queue.submit([commandBuffer]);
185 }
186
187 window.addEventListener("DOMContentLoaded", helloTriangle);