[WebGPU] Fix up demos on and add compute demo to webkit.org/demos
[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 whlslSource = `
17     struct FragmentData {
18         float4 position : SV_Position;
19         float4 color : attribute(${colorLocation});
20     }
21
22     vertex FragmentData vertexMain(float4 position : attribute(${positionLocation}), float4 color : attribute(${colorLocation}))
23     {
24         FragmentData out;
25
26         out.position = position;
27         out.color = color;
28
29         return out;
30     }
31
32     fragment float4 fragmentMain(float4 color : attribute(${colorLocation})) : SV_Target 0
33     {
34         return color;
35     }
36     `;
37     const shaderModule = device.createShaderModule({ code: whlslSource, isWHLSL: true });
38     
39     /* GPUPipelineStageDescriptors */
40     const vertexStageDescriptor = { module: shaderModule, entryPoint: "vertexMain" };
41     const fragmentStageDescriptor = { module: shaderModule, entryPoint: "fragmentMain" };
42     
43     /*** Vertex Buffer Setup ***/
44     
45     /* Vertex Data */
46     const colorOffset = 4 * 4; // 4 floats of 4 bytes each.
47     const vertexStride = 8 * 4;
48     const vertexDataSize = vertexStride * 3;
49     
50     /* GPUBufferDescriptor */
51     const vertexDataBufferDescriptor = { 
52         size: vertexDataSize,
53         usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.VERTEX
54     };
55     /* GPUBuffer */
56     const vertexBuffer = device.createBuffer(vertexDataBufferDescriptor);
57     
58     /*** Write Data To GPU ***/
59     
60     const vertexArrayBuffer = await vertexBuffer.mapWriteAsync();
61     const vertexWriteArray = new Float32Array(vertexArrayBuffer);
62     vertexWriteArray.set([
63         // x, y, z, w, r, g, b, a
64         0, 0.8, 0, 1, 0, 1, 1, 1,
65         -0.8, -0.8, 0, 1, 1, 1, 0, 1,
66         0.8, -0.8, 0, 1, 1, 0, 1, 1
67     ]);
68     vertexBuffer.unmap();
69     
70     /*** Describe Vertex Data For Pipeline ***/
71     
72     const vertexBufferSlot = 0;
73     
74     /* GPUVertexAttributeDescriptors */
75     const positionAttribute = {
76         shaderLocation: positionLocation,
77         offset: 0,
78         format: "float4"
79     };
80     const colorAttribute = {
81         shaderLocation: colorLocation,
82         offset: colorOffset,
83         format: "float4"
84     };
85
86     /* GPUVertexBufferDescriptor */
87     const vertexBufferDescriptor = {
88         stride: vertexStride,
89         attributeSet: [positionAttribute, colorAttribute]
90     };
91
92     /* GPUVertexInputDescriptor */
93     const vertexInputDescriptor = {
94         vertexBuffers: [vertexBufferDescriptor]
95     };
96     
97     /*** Finish Pipeline State ***/
98     
99     /* GPUBlendDescriptors */
100     const alphaBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
101     const colorBlendDescriptor = { srcFactor: "one", dstFactor: "zero", operation: "add" };
102     
103     /* GPUColorStateDescriptor */
104     const colorStateDescriptor = {
105         format: "bgra8unorm",
106         alphaBlend: alphaBlendDescriptor,
107         colorBlend: colorBlendDescriptor,
108         writeMask: GPUColorWriteBits.ALL
109     };
110     
111     /* GPURenderPipelineDescriptor */
112     const renderPipelineDescriptor = {
113         vertexStage: vertexStageDescriptor,
114         fragmentStage: fragmentStageDescriptor,
115         primitiveTopology: "triangle-list",
116         colorStates: [colorStateDescriptor],
117         vertexInput: vertexInputDescriptor
118     };
119     /* GPURenderPipeline */
120     const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);
121     
122     /*** Swap Chain Setup ***/
123     
124     const canvas = document.querySelector("canvas");
125     canvas.width = 600;
126     canvas.height = 600;
127
128     const gpuContext = canvas.getContext("gpu");
129     
130     /* GPUSwapChainDescriptor */
131     const swapChainDescriptor = { device: device, format: "bgra8unorm" };
132     /* GPUSwapChain */
133     const swapChain = gpuContext.configureSwapChain(swapChainDescriptor);
134     
135     /*** Render Pass Setup ***/
136     
137     /* Acquire Texture To Render To */
138     
139     /* GPUTexture */
140     const swapChainTexture = swapChain.getCurrentTexture();
141     /* GPUTextureView */
142     const renderAttachment = swapChainTexture.createDefaultView();
143     
144     /* GPUColor */
145     const darkBlue = { r: 0.15, g: 0.15, b: 0.5, a: 1 };
146     
147     /* GPURenderPassColorATtachmentDescriptor */
148     const colorAttachmentDescriptor = {
149         attachment: renderAttachment,
150         loadOp: "clear",
151         storeOp: "store",
152         clearColor: darkBlue
153     };
154     
155     /* GPURenderPassDescriptor */
156     const renderPassDescriptor = { colorAttachments: [colorAttachmentDescriptor] };
157     
158     /*** Rendering ***/
159     
160     /* GPUCommandEncoder */
161     const commandEncoder = device.createCommandEncoder();
162     /* GPURenderPassEncoder */
163     const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
164     
165     renderPassEncoder.setPipeline(renderPipeline);
166     renderPassEncoder.setVertexBuffers(vertexBufferSlot, [vertexBuffer], [0]);
167     renderPassEncoder.draw(3, 1, 0, 0); // 3 vertices, 1 instance, 0th vertex, 0th instance.
168     renderPassEncoder.endPass();
169     
170     /* GPUComamndBuffer */
171     const commandBuffer = commandEncoder.finish();
172     
173     /* GPUQueue */
174     const queue = device.getQueue();
175     queue.submit([commandBuffer]);
176 }
177
178 window.addEventListener("DOMContentLoaded", helloTriangle);