blob: 25a2843fbfe02c8ee1f00ee95c37f8c721e89c8f [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 Ninomiyad4c4dde2020-12-08 10:54:28 -08007import { params, pbool, poptions } from '../common/framework/params_builder.js';
Kai Ninomiya9cbb8002020-05-18 15:33:41 -07008import { makeTestGroup } from '../common/framework/test_group.js';
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07009
10import { GPUTest } from './gpu_test.js';
11
12// To run these tests in the standalone runner, run `grunt build` or `grunt pre` then open:
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070013// - http://localhost:8080/?runnow=1&q=webgpu:examples:
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070014// 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 -070015// - (wpt server url)/webgpu/cts.html?q=webgpu:examples:
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070016//
17// Tests here can be run individually or in groups:
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070018// - ?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=
Austin Eng639527e2020-04-14 16:20:36 -070025/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070026g.test('test_name').fn(t => {});
Kai Ninomiya04ec6b62019-10-25 00:35:32 -070027
Kai Ninomiyafba26302020-11-04 13:38:05 -080028g.test('not_implemented_yet,without_plan').unimplemented();
29g.test('not_implemented_yet,with_plan')
30 .desc(
31 `
32Plan for this test. What it tests. Summary of how it tests that functionality.
33- Description of cases, by describing parameters {a, b, c}
34- x= more parameters {x, y, z}
35`
36 )
37 .unimplemented();
38
Kai Ninomiyafb584a52020-04-16 16:43:24 -070039g.test('basic').fn(t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070040 t.expect(true);
41 t.expect(true, 'true should be true');
42
43 t.shouldThrow(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070044 // The expected '.name' of the thrown error.
45 'TypeError',
46 // This function is run inline inside shouldThrow, and is expected to throw.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070047 () => {
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070048 throw new TypeError();
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070049 },
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070050 // Log message.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070051 'function should throw Error'
52 );
53});
54
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070055g.test('basic,async').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070056 // shouldReject must be awaited to ensure it can wait for the promise before the test ends.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070057 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070058 // The expected '.name' of the thrown error.
59 'TypeError',
60 // Promise expected to reject.
61 Promise.reject(new TypeError()),
62 // Log message.
63 'Promise.reject should reject'
64 );
65
66 // Promise can also be an IIFE.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070067 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070068 'TypeError',
69 (async () => {
70 throw new TypeError();
71 })(),
72 'Promise.reject should reject'
73 );
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070074});
75
Enrico Galli9bec7342021-01-27 15:58:01 -080076// A test can be parameterized with a simple array of objects using .cases().
77// Each such instance of the test is a "case".
Kai Ninomiya13820262019-10-17 15:30:56 -070078//
79// Parameters can be public (x, y) which means they're part of the case name.
80// They can also be private by starting with an underscore (_result), which passes
81// them into the test but does not make them part of the case name:
82//
Enrico Galli9bec7342021-01-27 15:58:01 -080083// In this example, the following cases are generated (identified by their "query string"):
84// - webgpu:examples:basic,cases:x=2;y=4 runs once, with t.params set to:
85// - { x: 2, y: 4, _result: 6 }
86// - webgpu:examples:basic,cases:x=-10;y=18 runs once, with t.params set to:
87// - { x: -10, y: 18, _result: 8 }
88
89g.test('basic,cases')
90 .cases([
Kai Ninomiyafb584a52020-04-16 16:43:24 -070091 { x: 2, y: 4, _result: 6 }, //
92 { x: -10, y: 18, _result: 8 },
93 ])
94 .fn(t => {
95 t.expect(t.params.x + t.params.y === t.params._result);
96 });
Kai Ninomiya13820262019-10-17 15:30:56 -070097// (note the blank comment above to enforce newlines on autoformat)
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070098
Enrico Galli9bec7342021-01-27 15:58:01 -080099// Each case can be further parameterized using .subcases().
100// Each such instance of the test is a "subcase", which cannot be run independently of other
101// subcases. It is analogous to wrapping the entire fn body in a for-loop.
102//
103// In this example, the following cases are generated (identified by their "query string"):
104// - webgpu:examples:basic,cases:x=1 runs twice, with t.params set to each of:
105// - { x: 1, a: 2 }
106// - { x: 1, b: 2 }
107// - webgpu:examples:basic,cases:x=2 runs twice, with t.params set to each of:
108// - { x: 2, a: 3 }
109// - { x: 2, b: 2 }
110
111g.test('basic,subcases')
112 .cases([{ x: 1 }, { x: 2 }])
113 .subcases(p => [{ a: p.x + 1 }, { b: 2 }])
114 .fn(t => {
115 t.expect(
116 ((t.params.a === 2 || t.params.a === 3) && t.params.b === undefined) ||
117 (t.params.a === undefined && t.params.b === 2)
118 );
119 });
120
Kai Ninomiyad4c4dde2020-12-08 10:54:28 -0800121// Runs the following cases:
122// { x: 2, y: 2 }
123// { x: 2, z: 3 }
124// { x: 3, y: 2 }
125// { x: 3, z: 3 }
126g.test('basic,params_builder')
Enrico Galli9bec7342021-01-27 15:58:01 -0800127 .cases(
Kai Ninomiyad4c4dde2020-12-08 10:54:28 -0800128 params()
129 .combine(poptions('x', [2, 3]))
130 .combine([{ y: 2 }, { z: 3 }])
131 )
132 .fn(() => {});
133
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700134g.test('gpu,async').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700135 const fence = t.queue.createFence();
136 t.queue.signal(fence, 2);
137 await fence.onCompletion(1);
138 t.expect(fence.getCompletedValue() === 2);
139});
140
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700141g.test('gpu,buffers').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700142 const data = new Uint32Array([0, 1234, 0]);
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700143 const src = t.device.createBuffer({
144 mappedAtCreation: true,
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700145 size: 12,
146 usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
147 });
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700148 new Uint32Array(src.getMappedRange()).set(data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700149 src.unmap();
150
151 // Use the expectContents helper to check the actual contents of a GPUBuffer.
152 // Like shouldReject, it must be awaited.
Kai Ninomiyac42e2982019-10-23 15:44:28 -0700153 t.expectContents(src, data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700154});
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700155
156// One of the following two tests should be skipped on most platforms.
157
158g.test('gpu,with_texture_compression,bc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800159 .desc(
160 `Example of a test using a device descriptor.
161Tests that a BC format passes validation iff the feature is enabled.`
162 )
Enrico Galli9bec7342021-01-27 15:58:01 -0800163 .cases(pbool('textureCompressionBC'))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700164 .fn(async t => {
165 const { textureCompressionBC } = t.params;
166
167 if (textureCompressionBC) {
Kai Ninomiya001316a2020-09-29 09:47:08 -0700168 await t.selectDeviceOrSkipTestCase({ extensions: ['texture-compression-bc'] });
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700169 }
170
171 const shouldError = !textureCompressionBC;
172 t.expectGPUError(
173 'validation',
174 () => {
175 t.device.createTexture({
176 format: 'bc1-rgba-unorm',
177 size: [4, 4, 1],
178 usage: GPUTextureUsage.SAMPLED,
179 });
180 },
181 shouldError
182 );
183 });
184
185g.test('gpu,with_texture_compression,etc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800186 .desc(
187 `Example of a test using a device descriptor.
188
189TODO: Test that an ETC format passes validation iff the feature is enabled.`
190 )
Enrico Galli9bec7342021-01-27 15:58:01 -0800191 .cases(pbool('textureCompressionETC'))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700192 .fn(async t => {
193 const { textureCompressionETC } = t.params;
194
195 if (textureCompressionETC) {
Kai Ninomiya001316a2020-09-29 09:47:08 -0700196 await t.selectDeviceOrSkipTestCase({
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700197 extensions: ['texture-compression-etc' as GPUExtensionName],
198 });
199 }
200
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700201 // TODO: Should actually test createTexture with an ETC format here.
202 });