blob: 77c86d846775c41b61f014f5bc14a774b76bc2eb [file] [log] [blame]
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07001export const description = `
2Examples of writing CTS tests with various features.
Kai Ninomiyacb13fba2019-10-24 16:59:36 -07003
4Start here when looking for examples of basic framework usage.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07005`;
6
Kai Ninomiya9cbb8002020-05-18 15:33:41 -07007import { makeTestGroup } from '../common/framework/test_group.js';
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07008
9import { GPUTest } from './gpu_test.js';
10
Kai Ninomiyae7561052021-04-29 15:37:09 -070011// To run these tests in the standalone runner, run `npm start` then open:
Kai Ninomiya119b9532021-06-03 19:55:56 -070012// - http://localhost:XXXX/standalone/?runnow=1&q=webgpu:examples:*
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070013// To run in WPT, copy/symlink the out-wpt/ directory as the webgpu/ directory in WPT, then open:
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070014// - (wpt server url)/webgpu/cts.html?q=webgpu:examples:
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070015//
16// Tests here can be run individually or in groups:
Kai Ninomiyae7561052021-04-29 15:37:09 -070017// - ?q=webgpu:examples:basic,async:
18// - ?q=webgpu:examples:basic,async:*
19// - ?q=webgpu:examples:basic,*
20// - ?q=webgpu:examples:*
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070021
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070022export const g = makeTestGroup(GPUTest);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070023
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070024// Note: spaces in test names are replaced with underscores: webgpu:examples:test_name=
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070025g.test('test_name').fn(t => {});
Kai Ninomiya04ec6b62019-10-25 00:35:32 -070026
Kai Ninomiyafba26302020-11-04 13:38:05 -080027g.test('not_implemented_yet,without_plan').unimplemented();
28g.test('not_implemented_yet,with_plan')
29 .desc(
30 `
31Plan for this test. What it tests. Summary of how it tests that functionality.
32- Description of cases, by describing parameters {a, b, c}
33- x= more parameters {x, y, z}
34`
35 )
36 .unimplemented();
37
Kai Ninomiyafb584a52020-04-16 16:43:24 -070038g.test('basic').fn(t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070039 t.expect(true);
40 t.expect(true, 'true should be true');
41
42 t.shouldThrow(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070043 // The expected '.name' of the thrown error.
44 'TypeError',
45 // This function is run inline inside shouldThrow, and is expected to throw.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070046 () => {
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070047 throw new TypeError();
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070048 },
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070049 // Log message.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070050 'function should throw Error'
51 );
52});
53
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070054g.test('basic,async').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070055 // shouldReject must be awaited to ensure it can wait for the promise before the test ends.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070056 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070057 // The expected '.name' of the thrown error.
58 'TypeError',
59 // Promise expected to reject.
60 Promise.reject(new TypeError()),
61 // Log message.
62 'Promise.reject should reject'
63 );
64
65 // Promise can also be an IIFE.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070066 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070067 'TypeError',
68 (async () => {
69 throw new TypeError();
70 })(),
71 'Promise.reject should reject'
72 );
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070073});
74
Kai Ninomiya119b9532021-06-03 19:55:56 -070075g.test('basic,plain_cases')
76 .desc(
77 `
78A test can be parameterized with a simple array of objects using .paramsSimple([ ... ]).
79Each such instance of the test is a "case".
Enrico Galli9bec7342021-01-27 15:58:01 -080080
Kai Ninomiya119b9532021-06-03 19:55:56 -070081In this example, the following cases are generated (identified by their "query string"),
82each with just one subcase:
83 - webgpu:examples:basic,cases:x=2;y=2 runs 1 subcase, with t.params set to:
84 - { x: 2, y: 2 }
85 - webgpu:examples:basic,cases:x=-10;y=-10 runs 1 subcase, with t.params set to:
86 - { x: -10, y: -10 }
87 `
88 )
89 .paramsSimple([
90 { x: 2, y: 2 }, //
91 { x: -10, y: -10 },
92 ])
93 .fn(t => {
94 t.expect(t.params.x === t.params.y);
95 });
96
97g.test('basic,plain_cases_private')
98 .desc(
99 `
100Parameters can be public ("x", "y") which means they're part of the case name.
101They can also be private by starting with an underscore ("_result"), which passes
102them into the test but does not make them part of the case name:
103
104In this example, the following cases are generated, each with just one subcase:
105 - webgpu:examples:basic,cases:x=2;y=4 runs 1 subcase, with t.params set to:
106 - { x: 2, y: 4, _result: 6 }
107 - webgpu:examples:basic,cases:x=-10;y=18 runs 1 subcase, with t.params set to:
108 - { x: -10, y: 18, _result: 8 }
109 `
110 )
111 .paramsSimple([
Kai Ninomiyafb584a52020-04-16 16:43:24 -0700112 { x: 2, y: 4, _result: 6 }, //
113 { x: -10, y: 18, _result: 8 },
114 ])
115 .fn(t => {
116 t.expect(t.params.x + t.params.y === t.params._result);
117 });
Kai Ninomiya13820262019-10-17 15:30:56 -0700118// (note the blank comment above to enforce newlines on autoformat)
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700119
Kai Ninomiya119b9532021-06-03 19:55:56 -0700120g.test('basic,builder_cases')
121 .desc(
122 `
123A "CaseParamsBuilder" or "SubcaseParamsBuilder" can be passed to .params() instead.
124The params builder provides facilities for generating tests combinatorially (by cartesian
125product). For convenience, the "unit" CaseParamsBuilder is passed as an argument ("u" below).
Enrico Galli9bec7342021-01-27 15:58:01 -0800126
Kai Ninomiya119b9532021-06-03 19:55:56 -0700127In this example, the following cases are generated, each with just one subcase:
128 - webgpu:examples:basic,cases:x=1,y=1 runs 1 subcase, with t.params set to:
129 - { x: 1, y: 1 }
130 - webgpu:examples:basic,cases:x=1,y=2 runs 1 subcase, with t.params set to:
131 - { x: 1, y: 2 }
132 - webgpu:examples:basic,cases:x=2,y=1 runs 1 subcase, with t.params set to:
133 - { x: 2, y: 1 }
134 - webgpu:examples:basic,cases:x=2,y=2 runs 1 subcase, with t.params set to:
135 - { x: 2, y: 2 }
136 `
137 )
138 .params(u =>
139 u //
140 .combineWithParams([{ x: 1 }, { x: 2 }])
141 .combineWithParams([{ y: 1 }, { y: 2 }])
142 )
143 .fn(() => {});
Enrico Galli9bec7342021-01-27 15:58:01 -0800144
Kai Ninomiya119b9532021-06-03 19:55:56 -0700145g.test('basic,builder_cases_subcases')
146 .desc(
147 `
148Each case sub-parameterized using .beginSubcases().
149Each such instance of the test is a "subcase", which cannot be run independently of other
150subcases. It is somewhat like wrapping the entire fn body in a for-loop.
151
152In this example, the following cases are generated:
153 - webgpu:examples:basic,cases:x=1 runs 2 subcases, with t.params set to:
154 - { x: 1, y: 1 }
155 - { x: 1, y: 2 }
156 - webgpu:examples:basic,cases:x=2 runs 2 subcases, with t.params set to:
157 - { x: 2, y: 1 }
158 - { x: 2, y: 2 }
159 `
160 )
161 .params(u =>
162 u //
163 .combineWithParams([{ x: 1 }, { x: 2 }])
164 .beginSubcases()
165 .combineWithParams([{ y: 1 }, { y: 2 }])
166 )
167 .fn(() => {});
168
169g.test('basic,builder_subcases')
170 .desc(
171 `
172In this example, the following single case is generated:
173 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
174 - { x: 1, y: 1 }
175 - { x: 1, y: 2 }
176 - { x: 2, y: 1 }
177 - { x: 2, y: 2 }
178 `
179 )
180 .params(u =>
181 u //
182 .beginSubcases()
183 .combineWithParams([{ x: 1 }, { x: 2 }])
184 .combineWithParams([{ y: 1 }, { y: 2 }])
185 )
186 .fn(() => {});
187
188g.test('basic,builder_subcases_short')
189 .desc(
190 `
191As a shorthand, .paramsSubcasesOnly() can be used.
192
193In this example, the following single case is generated:
194 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
195 - { x: 1, y: 1 }
196 - { x: 1, y: 2 }
197 - { x: 2, y: 1 }
198 - { x: 2, y: 2 }
199 `
200 )
201 .paramsSubcasesOnly(u =>
202 u //
203 .combineWithParams([{ x: 1 }, { x: 2 }])
204 .combineWithParams([{ y: 1 }, { y: 2 }])
Kai Ninomiyad4c4dde2020-12-08 10:54:28 -0800205 )
206 .fn(() => {});
207
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700208g.test('gpu,async').fn(async t => {
Kai Ninomiya2f242cf2021-04-14 14:12:03 -0700209 const x = await t.queue.onSubmittedWorkDone();
210 t.expect(x === undefined);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700211});
212
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700213g.test('gpu,buffers').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700214 const data = new Uint32Array([0, 1234, 0]);
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700215 const src = t.device.createBuffer({
216 mappedAtCreation: true,
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700217 size: 12,
218 usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
219 });
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700220 new Uint32Array(src.getMappedRange()).set(data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700221 src.unmap();
222
223 // Use the expectContents helper to check the actual contents of a GPUBuffer.
224 // Like shouldReject, it must be awaited.
Kai Ninomiya8de9aa52021-06-23 18:25:51 -0700225 t.expectGPUBufferValuesEqual(src, data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700226});
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700227
228// One of the following two tests should be skipped on most platforms.
229
230g.test('gpu,with_texture_compression,bc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800231 .desc(
232 `Example of a test using a device descriptor.
233Tests that a BC format passes validation iff the feature is enabled.`
234 )
Kai Ninomiya119b9532021-06-03 19:55:56 -0700235 .params(u => u.combine('textureCompressionBC', [false, true]))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700236 .fn(async t => {
237 const { textureCompressionBC } = t.params;
238
239 if (textureCompressionBC) {
Kai Ninomiya0d21f752021-04-14 14:41:48 -0700240 await t.selectDeviceOrSkipTestCase('texture-compression-bc');
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700241 }
242
243 const shouldError = !textureCompressionBC;
244 t.expectGPUError(
245 'validation',
246 () => {
247 t.device.createTexture({
248 format: 'bc1-rgba-unorm',
249 size: [4, 4, 1],
250 usage: GPUTextureUsage.SAMPLED,
251 });
252 },
253 shouldError
254 );
255 });
256
257g.test('gpu,with_texture_compression,etc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800258 .desc(
259 `Example of a test using a device descriptor.
260
261TODO: Test that an ETC format passes validation iff the feature is enabled.`
262 )
Kai Ninomiya119b9532021-06-03 19:55:56 -0700263 .params(u => u.combine('textureCompressionETC', [false, true]))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700264 .fn(async t => {
265 const { textureCompressionETC } = t.params;
266
267 if (textureCompressionETC) {
Kai Ninomiya2f242cf2021-04-14 14:12:03 -0700268 await t.selectDeviceOrSkipTestCase('texture-compression-etc' as GPUFeatureName);
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700269 }
270
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700271 // TODO: Should actually test createTexture with an ETC format here.
272 });