Add a runtime-disabled dialog element skeleton
[WebKit-https.git] / LayoutTests / webgpu / whlsl-test-harness-test.html
1 <!DOCTYPE html>
2 <html>
3 <meta charset=utf-8>
4 <meta name="timeout" content="long">
5 <title>Test the WHLSL test harness.</title>
6 <script src="js/whlsl-test-harness.js"></script>
7 <script src="../resources/testharness.js"></script>
8 <script src="../resources/testharnessreport.js"></script>
9 <script>
10 const epsilon = 0.0001;
11
12 // FIXME: Add "uchar" back in when operator+(uchar, uchar) is available.
13 const numericScalarTypes = ["int", "uint", "float"];
14
15 const numericScalarFuncs = {
16     "int": callIntFunction,
17     "uchar": callUcharFunction,
18     "uint": callUintFunction,
19     "float": callFloatFunction
20 };
21
22 const scalarArgMakers = {
23     "bool": makeBool,
24     "int": makeInt,
25     "uchar": makeUchar,
26     "uint": makeUint,
27     "float": makeFloat
28 };
29
30 const arrayTypeLengths = {
31     "float4": 4,
32     "float4x4": 16
33 };
34
35 const arrayFuncs = {
36     "float4": callFloat4Function,
37     "float4x4": callFloat4x4Function,
38 };
39
40 const arrayArgMakers = {
41     "float4": makeFloat4,
42     "float4x4": makeFloat4x4
43 };
44
45 const float4x4expected = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
46 const float4x4ColumnExpected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
47 const float4expected = [0, 1, 2, 3];
48
49 let whlslTests = {};
50
51 whlslTests.literals = () => {
52     checkBools("Return a literal of type bool.", "return true;");
53     checkArrays("float4", "return float4(0, 1, 2, 3);", [], float4expected);
54     checkNumericScalars("return 42;", [], 42);
55 };
56
57 whlslTests.singleArgument = () => {
58     checkBools("Upload and return a bool value.", "return in0;", [true]);
59     checkArrays("float4", "return in0;", [float4expected], float4expected);
60     checkNumericScalars("return in0;", [42], 42);
61 };
62
63 whlslTests.manyArguments = () => {
64     checkBools("Upload many bool values and return a calculated result.",
65         "return in0 & in1 & in2 & in3 & in4 & in5 & in6 & in7;",
66         [true, true, true, true, true, true, true, true]);
67
68     let body = "return float4(in0.x, in1.y, in2.z, in3.w);"
69     let args = [];
70     for (let i = 0; i < 4; ++i)
71         args.push(float4expected);
72     checkArrays("float4", body, args, float4expected);
73
74     body = `return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7;`;
75     checkNumericScalars(body, [0, 1, 2, 3, 4, 5, 6, 7], 28);
76 };
77
78 whlslTests.buffersWithOneValue = () => {
79     const body = `return in0[0];`
80     checkArrays("float4", body, [[float4expected]], float4expected);
81     checkNumericScalars(body, [[42]], 42);
82 };
83
84 whlslTests.multipleBufferArguments = () => {
85     let body = `
86     float x = in0[0].x + in0[1].x + in0[2].x + in1.x + in2[0].x;
87     float y = in0[0].y + in0[1].y + in0[2].y + in1.y + in2[0].y;
88     float z = in0[0].z + in0[1].z + in0[2].z + in1.z + in2[0].z;
89     float w = in0[0].w + in0[1].w + in0[2].w + in1.w + in2[0].w;
90
91     return float4(x, y, z, w);`;
92     checkArrays("float4", body, [[float4expected, float4expected, float4expected], float4expected, [float4expected]], [0, 5, 10, 15]);
93
94     body = `return in0[0] + in0[1] + in0[2] + in1 + in2[0];`;
95     checkNumericScalars(body, [[0, 1, 2], 3, [4]], 10);
96 };
97
98 whlslTests.multipleArgumentTypes = () => {
99     const src = `float test(int i, uchar c, float4 f4, device uint[] u, device float[] fs)
100     {
101         return float(i) + float(c) + f4.x + f4.y + f4.z + f4.w + float(u[0]) + fs[0] + fs[1];
102     }`;
103     const i = makeInt(1);
104     const c = makeUchar(2);
105     const f4 = makeFloat4([4, 5, 6, 7]);
106     const u = makeUint([3]);
107     const fs = makeFloat([8, 9]);
108     webGPUPromiseTest(() => {
109         return callFloatFunction(src, "test", [i, c, f4, u, fs]).then(result => {
110             assert_approx_equals(result, 45, epsilon, "Test returned expected value.");
111         });
112     }, "Upload and calculate a result from varied argument types.");
113 };
114
115 whlslTests.bufferStores = () => {
116     let src = `void test(device float4[] out) {
117         out[0] = float4(0, 1, 2, 3);
118     }`;
119     const float4Out = makeFloat4([[0, 0, 0, 0]]);
120     callVoidFunction(src, "test", float4Out);
121
122     webGPUPromiseTest(() => {
123         return float4Out.getArrayBuffer().then(arrayBuffer => {
124             const result = new Float32Array(arrayBuffer);
125             for (let i; i < 4; ++i) {
126                 assert_approx_equals(result[i], i, "Test stored expected values.");
127             }
128         });
129     }, "Store into a float4[].");
130
131     src = `void test(device int[] in, device int[] out) {
132         for (uint i = 0; i < 5; i = i + 1)
133             out[i] = in[i];
134     }`;
135     const array = [0, 1, 2, 3, 4];
136     const input = makeInt(array);
137     const output = makeInt([0, 0, 0, 0, 0]);
138     callVoidFunction(src, "test", [input, output]);
139
140     webGPUPromiseTest(() => {
141         return output.getArrayBuffer().then(arrayBuffer => {
142             const result = new Uint32Array(arrayBuffer);
143             assert_array_equals(array, result, "Test stored expected values.");
144         });
145     }, "Upload a int[] and store into a int[].");
146 };
147
148 whlslTests.float4x4tests = () => {
149     const src = `void test(device float4x4[] in, device float4x4[] out) {
150         for (uint i = 0; i < 4; i = i + 1)
151             out[i] = in[i];
152     }`;
153     const input = makeFloat4x4([float4x4expected, float4x4expected, float4x4expected, float4x4expected]);
154     const output = makeFloat4x4(new Array(64).fill(0));
155     callVoidFunction(src, "test", [input, output]);
156
157     webGPUPromiseTest(() => {
158         return output.getArrayBuffer().then(arrayBuffer => {
159             const result = new Float32Array(arrayBuffer);
160             for (let i = 0; i < 4; ++i) {
161                 for (let j = 0; j < 16; ++j)
162                     assert_approx_equals(result[i * 16 + j], float4x4expected[j], epsilon, "Test stored expected values.");
163             }
164         });
165     }, "Upload a float4x4[] and store into a float4x4[].");
166
167     checkArrays("float4x4", "return float4x4(float4(0, 1, 2, 3), float4(4, 5, 6, 7), float4(8, 9, 10, 11), float4(12, 13, 14, 15));", [], float4x4expected);
168     checkArrays("float4x4", "return in0;", [float4x4expected], float4x4expected);
169     let multiple4x4args = [];
170     for (let i = 0; i < 16; ++i) {
171         const arg = new Array(16);
172         arg.fill(0);
173         arg[i] = i;
174         multiple4x4args.push(arg);
175     }
176     checkArrays("float4x4", "return in0 + in1 + in2 + in3 + in4 + in5 + in6 + in7 + in8 + in9 + in10 + in11 + in12 + in13 + in14 + in15;", multiple4x4args, float4x4ColumnExpected);
177     checkArrays("float4x4", "return in0[0];", [[float4x4expected]], float4x4expected);
178 };
179
180 whlslTests.checkFailTests = () => {
181     webGPUPromiseTest(() => {
182         return checkFail(`Doors and corners, kid. That's where they getcha.`);
183     }, "Code should not compile, and no error is reported.");
184
185     webGPUPromiseTest(() => {
186         return checkFail("").catch(e => {
187             assert_true(e instanceof Error, "An expected Error was caught.");
188         });
189     }, "Successfully compiling code in checkFail is an error.")
190 };
191
192 window.addEventListener("load", () => {
193     try {
194         for (const name in whlslTests) {
195             if (!name.startsWith("_"))
196                 whlslTests[name]();
197         }
198     } catch (e) {
199         if (window.testRunner)
200             testRunner.notifyDone();
201         
202         throw e;
203     }
204 });
205
206 /* Helper functions */
207
208 const checkNumericScalars = (body, argValues, expected) => {
209     let functions = [];
210     let src = "";
211     for (let type of numericScalarTypes) {
212         let name, values;
213         [src, name, values] = appendScalarFunctionToSource(src, type, body, argValues);
214         functions.push({ type: type, name: name, args: values, expected: expected });
215     }
216
217     for (const f of functions) {
218         const callFunc = numericScalarFuncs[f.type];
219         webGPUPromiseTest(async () => {
220             return callFunc(src, f.name, f.args).then(result => {
221                 assert_approx_equals(result, f.expected, epsilon, "Test returned expected value.");
222             });
223         }, `Return an expected ${f.type} value.`);
224     }
225 };
226
227 const checkBools = (msg = "Return an expected bool value.", body, argValues = [], expected = true) => {
228     const [src, name, values] = appendScalarFunctionToSource("", "bool", body, argValues); 
229
230     webGPUPromiseTest(async () => {
231         return callBoolFunction(src, name, values).then(result => {
232             assert_equals(result, expected, "Test returned expected value.");
233         }, e => {
234             if (!(e instanceof WebGPUUnsupportedError))
235                 throw e;
236         });
237     }, msg);
238 };
239
240 const checkArrays = (type, body, argValues = [], expected) => {
241     let inputArgs = [];
242     let values = [];
243     for (let i = 0; i < argValues.length; ++i) {
244         // Support arrays of float4, including one with a single float4.
245         const totalLength = argValues[i].flat().length;
246         const isBuffer = argValues[i].length === 1 || totalLength > arrayTypeLengths[type];
247         inputArgs.push(`${isBuffer ? "device " : ""}${type}${isBuffer ? "[]" : ""} in${i}`);
248         values.push(arrayArgMakers[type](argValues[i]));
249     }
250
251     const src = `${type} ${type}Test(${inputArgs.join(", ")}) { ${body} }
252     `;
253
254     webGPUPromiseTest(async () => {
255         return arrayFuncs[type](src, `${type}Test`, values).then(result => {
256             for (let i = 0; i < arrayTypeLengths[type]; ++i)
257                 assert_approx_equals(result[i], expected[i], epsilon, "Test returned expected value.");
258         });
259     }, `Return an expected ${type} value.`);
260 }
261
262 const appendScalarFunctionToSource = (src, type, body, argValues) => {
263     const name = `${type}Test`;
264
265     let inputArgs = [];
266     let values = [];
267     for (let i = 0; i < argValues.length; ++i) {
268         const isBuffer = Array.isArray(argValues[i]);
269         inputArgs.push(`${isBuffer ? "device " : ""}${type}${isBuffer ? "[]" : ""} in${i}`);
270         values.push(scalarArgMakers[type](argValues[i]));
271     }
272
273     src += `${type} ${name}(${inputArgs.join(", ")}) { ${body} }
274     `;
275     
276     return [src, name, values];
277 };
278 </script>
279 </html>