abaaa2ad2d7a455b642c7bd52ea1055bf3fb6fe0
[WebKit-https.git] / LayoutTests / webgpu / buffer-command-buffer-races.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-command-buffer-races-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 VertexIn
19 {
20     float2 xy [[attribute(0)]];
21     float3 rgb [[attribute(1)]];
22 };
23
24 struct VertexOut
25 {
26     float4 position [[position]];
27     float4 color;
28 };
29
30 vertex VertexOut vertex_main(VertexIn vertexIn [[stage_in]])
31 {
32     VertexOut vOut;
33     vOut.position = float4(vertexIn.xy, 0, 1);
34     vOut.color = float4(vertexIn.rgb, 1);
35
36     return vOut;
37 }
38
39 fragment float4 fragment_main(VertexOut v [[stage_in]])
40 {
41     return v.color;
42 }
43 `
44
45 function createVertexInputDescriptor() {
46     return {
47         indexFormat: "uint32",
48         vertexBuffers: [{
49             stride: 4 * 2,
50             attributeSet: [{
51                 format: "float2",
52                 shaderLocation: 0
53             }]
54         }, {
55             stride: 4 * 3,
56             stepMode: "instance",
57             attributeSet: [{
58                 format: "float3",
59                 shaderLocation: 1
60             }]
61         }]
62     }
63 }
64
65 function createAndSetVertexBuffer(device, vertices) {
66     const vertexArray = new Float32Array(vertices)
67     return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
68 }
69
70 function drawAndSubmitCommands(device, pipeline, attachment, vertexBuffer, colorBuffer) {
71     const commandEncoder = device.createCommandEncoder();
72     const encoder = commandEncoder.beginRenderPass({ colorAttachments: [attachment] });
73     encoder.setVertexBuffers(0, [vertexBuffer, colorBuffer], [0, 0]);
74     encoder.setPipeline(pipeline);
75     encoder.draw(3, 1, 0, 0);
76     encoder.endPass();
77     device.getQueue().submit([commandEncoder.finish()]);
78 }
79
80 async function test() {
81     const device = await getBasicDevice();
82     const canvas = document.querySelector("canvas");
83     const swapChain = createBasicSwapChain(canvas, device);
84     // FIXME: Replace with non-MSL shaders.
85     const shaderModule = device.createShaderModule({ code: shaderCode });
86     const vertexInputDescriptor = createVertexInputDescriptor();
87     const pipeline = createBasicPipeline(shaderModule, device, null, null, vertexInputDescriptor);
88
89     const upperLeftBuffer = createAndSetVertexBuffer(device, [-1, 1, -1, -1, 0, 1]);
90     const middleBuffer = createAndSetVertexBuffer(device, [0, 1, -1, -1, 1, -1]);
91     const upperRightBuffer = createAndSetVertexBuffer(device, [0, 1, 1, 1, 1, -1]);
92
93     const green = [0, 1, 0];
94     const blue = [0, 0, 1];
95     const greenArray = new Float32Array(green);
96     const blueArray = new Float32Array(blue);
97
98     const colorBuffer = createBufferWithData(device, { size: greenArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE }, greenArray.buffer);
99
100     const attachment = {
101         attachment: swapChain.getCurrentTexture().createDefaultView(),
102         loadOp: "load",
103         storeOp: "store",
104         clearColor: { r: 1, g: 0, b: 0, a: 1 }
105     };
106
107     /* mapWriteAsync should resolve after GPU commands are complete, so triangle should be green. */
108     drawAndSubmitCommands(device, pipeline, attachment, upperLeftBuffer, colorBuffer);
109     await colorBuffer.mapWriteAsync().then(ab => {
110         let array = new Float32Array(ab);
111         array.set(blue);
112         colorBuffer.unmap();
113     });
114
115     await colorBuffer.mapWriteAsync().then(ab => {
116         let array = new Float32Array(ab);
117         array.set(green);
118     });
119
120     /* colorBuffer that is still mapped should be not submitted to draw a blue triangle. */
121     drawAndSubmitCommands(device, pipeline, attachment, upperLeftBuffer, colorBuffer);
122
123     /* colorBuffer does not actually contain "green" again until this call. */
124     colorBuffer.unmap();
125
126     /* Writing data immediately after a submit should not affect the preceding draw call. */
127     drawAndSubmitCommands(device, pipeline, attachment, middleBuffer, colorBuffer);
128     await mapWriteDataToBuffer(colorBuffer, blueArray.buffer);
129
130     /* destroy right after a submit should not affect the draw call. */
131     await mapWriteDataToBuffer(colorBuffer, greenArray.buffer);
132     drawAndSubmitCommands(device, pipeline, attachment, upperRightBuffer, colorBuffer);
133     upperRightBuffer.destroy();
134
135     /* draw command with a destroyed buffer should fail */
136     colorBuffer.destroy();
137     drawAndSubmitCommands(device, pipeline, attachment, middleBuffer, colorBuffer);
138
139     upperLeftBuffer.destroy();
140     middleBuffer.destroy();
141     upperRightBuffer.destroy();
142 }
143
144 test().then(function() {
145     if (window.testRunner)
146         testRunner.notifyDone();
147 }, function() {
148     if (window.testRunner)
149         testRunner.notifyDone();
150 });
151 </script>