media/W3C/video/events/event_progress_manual.html is a flaky failure
[WebKit-https.git] / LayoutTests / webgpu / buffer-resource-triangles.html
1 <!DOCTYPE html>
2 <meta charset="utf-8">
3 <title>WebGPU Hello Triangles</title>
4 <meta name="assert" content="WebGPU correctly renders a green canvas.">
5 <link rel="match" href="buffer-resource-triangles-expected.html">
6 <p>Pass if square canvas below is completely green.</p>
7 <canvas width="400" height="400"></canvas>
8 <script src="js/webgpu-functions.js"></script>
9 <script>
10 if (window.testRunner)
11     testRunner.waitUntilDone();
12
13 const shaderCode = `
14 #include <metal_stdlib>
15     
16 using namespace metal;
17
18 struct VertexInput {
19     float4 position [[attribute(0)]];
20 };
21
22 struct Vertex {
23     float4 position [[position]];
24 };
25
26 struct VertexArguments {
27     device Vertex* v0;
28     device Vertex* v1;
29     device Vertex* v2;
30 };
31
32 vertex Vertex vertex_main(
33     VertexInput input [[stage_in]],
34     const device VertexArguments& args0 [[buffer(0)]],
35     const device VertexArguments& args1 [[buffer(1)]],
36     uint vid [[vertex_id]])
37 {
38     switch (vid)
39     {
40         case 0:
41         case 1:
42         case 2: {
43             Vertex out;
44             out.position = input.position;
45             return out;
46         }
47         case 3: return *args0.v0;
48         case 4: return *args0.v1;
49         case 5: return *args0.v2;
50         case 6: return *args1.v0;
51         case 7: return *args1.v1;
52         default: return *args1.v2;
53     }
54 }
55
56 struct FragmentArguments {
57     device float4* color;
58 };
59
60 fragment float4 fragment_main(const device FragmentArguments& args [[buffer(0)]])
61 {
62     return args.color[0];
63 }
64 `
65
66 const bindingNums = {
67     UL: 0,
68     UM: 1,
69     UR: 2,
70     LL: 3,
71     LR: 4,
72     G: 5
73 };
74
75 function createUniformBufferBindGroupLayout(bindNum, stage = GPUShaderStageBit.VERTEX) {
76     return {
77         binding: bindNum,
78         visibility: stage,
79         type: "uniform-buffer"
80     };
81 }
82
83 const vertexSize = 4 * 4;
84 const verticesBufferSize = vertexSize * 3;
85 function createAndUploadVerticesBuffer(device) {
86     const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
87     const arrayBuffer = new Float32Array([
88         0, 1, 0, 1,
89         -1, -1, 0, 1,
90         1, -1, 0, 1
91     ]).buffer;
92
93     buffer.setSubData(0, arrayBuffer);
94     return buffer;
95 }
96
97 function createFloat4Buffer(device, a, b, promises) {
98     const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE });
99
100     const promise = buffer.mapWriteAsync().then(mapping => {
101         const mappedArray = new Float32Array(mapping);
102         mappedArray.set([a, b, 0, 1]);
103         buffer.unmap();
104     });
105
106     promises.push(promise);
107     return buffer;
108 }
109
110 function createBufferBinding(buffer) {
111     return {
112         buffer: buffer,
113         offset: 0,
114         size: vertexSize
115     };
116 }
117
118 async function test() {
119     const device = await getBasicDevice();
120     const canvas = document.querySelector("canvas");
121     const swapChain = createBasicSwapChain(canvas, device);
122     // FIXME: Replace with non-MSL shaders.
123     const shaderModule = device.createShaderModule({ code: shaderCode });
124
125     // Create vertex data WebGPUBuffers.
126     const verticesBuffer = createAndUploadVerticesBuffer(device);
127
128     let bufferPromises = [];
129     const upperLeft = createFloat4Buffer(device, -1, 1, bufferPromises);
130     const upperMiddle = createFloat4Buffer(device, 0, 1, bufferPromises);
131     const upperRight = createFloat4Buffer(device, 1, 1, bufferPromises);
132     const lowerLeft = createFloat4Buffer(device, -1, -1, bufferPromises);
133     const lowerRight = createFloat4Buffer(device, 1, -1, bufferPromises);
134
135     // Color data buffer.
136     const green = createFloat4Buffer(device, 0, 1, bufferPromises);
137
138     // Create vertex input state.
139     const inputState = {
140         indexFormat: "uint32",
141         attributes: [{
142             shaderLocation: 0,
143             inputSlot: 0,
144             offset: 0,
145             format: "float4"
146         }],
147         inputs: [{
148             inputSlot: 0,
149             stride: vertexSize,
150             stepMode: "vertex"
151         }]
152     };
153
154     // Create buffer WebGPUBindGroupLayoutBindings.
155     const layoutUL = createUniformBufferBindGroupLayout(bindingNums.UL);
156     const layoutUM = createUniformBufferBindGroupLayout(bindingNums.UM);
157     const layoutUR = createUniformBufferBindGroupLayout(bindingNums.UR);
158     const layoutLL = createUniformBufferBindGroupLayout(bindingNums.LL);
159     const layoutLR = createUniformBufferBindGroupLayout(bindingNums.LR);
160     const layoutG = createUniformBufferBindGroupLayout(bindingNums.G, GPUShaderStageBit.FRAGMENT);
161
162     // WebGPUBindGroupLayouts
163     const leftTriangleBGLayout = device.createBindGroupLayout({ bindings: [layoutUL, layoutUM, layoutLL, layoutG] });
164     const rightTriangleBGLayout = device.createBindGroupLayout({ bindings: [layoutUR, layoutUM, layoutLR] });
165
166     // WebGPUPipelineLayout and WebGPURenderPipeline
167     const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [leftTriangleBGLayout, rightTriangleBGLayout] });
168     const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, inputState, null, "triangle-list");
169
170     // WebGPUBufferBindings
171     const bindingUL = createBufferBinding(upperLeft);
172     const bindingUM = createBufferBinding(upperMiddle);
173     const bindingUR = createBufferBinding(upperRight);
174     const bindingLL = createBufferBinding(lowerLeft);
175     const bindingLR = createBufferBinding(lowerRight);
176     const bindingG = createBufferBinding(green);
177     
178     // WebGPUBindGroupBindings
179     const bgBindingUL = { binding: bindingNums.UL, resource: bindingUL };
180     const bgBindingUM = { binding: bindingNums.UM, resource: bindingUM };
181     const bgBindingUR = { binding: bindingNums.UR, resource: bindingUR };
182     const bgBindingLL = { binding: bindingNums.LL, resource: bindingLL };
183     const bgBindingLR = { binding: bindingNums.LR, resource: bindingLR };
184     const bgBindingG = { binding: bindingNums.G, resource: bindingG };
185
186     // WebGPUBindGroups
187     const leftTriangleBG = device.createBindGroup({ 
188         layout: leftTriangleBGLayout, 
189         bindings: [bgBindingUL, bgBindingUM, bgBindingLL, bgBindingG] 
190     });
191     const rightTriangleBG = device.createBindGroup({
192         layout: rightTriangleBGLayout,
193         bindings: [bgBindingUR, bgBindingUM, bgBindingLR]
194     });
195
196     Promise.all(bufferPromises).then(() => {
197         const commandEncoder = device.createCommandEncoder();
198         const passEncoder = beginBasicRenderPass(swapChain, commandEncoder);
199         passEncoder.setPipeline(pipeline);
200
201         // Vertex data for upper triangles.
202         passEncoder.setBindGroup(0, leftTriangleBG);
203         passEncoder.setBindGroup(1, rightTriangleBG);
204         // Lower triangle.
205         passEncoder.setVertexBuffers(0, [verticesBuffer], [0]);
206         passEncoder.draw(9, 1, 0, 0);
207
208         passEncoder.endPass();
209         const queue = device.getQueue();
210         queue.submit([commandEncoder.finish()]);
211
212         if (window.testRunner)
213             testRunner.notifyDone();
214     });
215 }
216
217 test();
218 </script>