4 <meta charset=
"utf-8" />
5 <script src=
"/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel=
"stylesheet" href=
"/tests/SimpleTest/test.css" />
11 SpecialPowers
.getBoolPref("dom.webgpu.enabled"),
12 "Pref should be enabled."
15 SimpleTest
.waitForExplicitFinish();
17 // This test has 3 phases:
18 // 1) Repeatedly call a function that creates some WebGPU objects with
19 // some variations. One of the objects is always an encoder. Act on
20 // those objects in ways that might confuse the cycle detector. All
21 // of the objects *should* be garbage collectable, including the
22 // encoders. Store a weak link to each of the encoders.
23 // 2) Invoke garbage collection.
24 // 3) Confirm all the encoders were garbage collected.
26 // Define some stuff we'll use in the various phases.
27 const gc_promise
= () =>
28 new Promise(resolve
=> SpecialPowers
.exactGC(resolve
));
30 // Define an array of structs containing a label and a weak reference
31 // to an encoder, then fill it by executing a bunch of WebGPU commands.
34 // Here's our WebGPU test function, which we'll call with permuted
36 // label: string label to use in error messages
37 // encoderType: string in ["render", "compute", "bundle"].
38 // resourceExtraParam: boolean should one of the resources get an
39 // added property with a scalar value. This can change the order that
40 // things are processed by the cycle collector.
41 // resourceCycle: boolean should one of the resources get an added
42 // property that is set to the encoder.
43 // endOrFinish: boolean should the encoder be ended. If not, it's just
45 let test_func
= async (
52 const adapter
= await navigator
.gpu
.requestAdapter();
53 const device
= await adapter
.requestDevice();
58 if (encoderType
== "render") {
59 // Create some resources, and setup the pass.
60 encoder
= device
.createCommandEncoder();
61 const texture
= device
.createTexture({
62 size
: { width
: 1, height
: 1, depthOrArrayLayers
: 1 },
64 usage
: GPUTextureUsage
.COPY_SRC
| GPUTextureUsage
.RENDER_ATTACHMENT
,
66 const view
= texture
.createView();
67 pass
= encoder
.beginRenderPass({
77 } else if (encoderType
== "compute") {
78 // Create some resources, and setup the pass.
79 encoder
= device
.createCommandEncoder();
80 const pipeline
= device
.createComputePipeline({
83 module
: device
.createShaderModule({
85 struct Buffer { data: array<u32>, };
86 @group(0) @binding(0) var<storage, read_write> buffer: Buffer;
87 @compute @workgroup_size(1) fn main(
88 @builtin(global_invocation_id) id: vec3<u32>) {
89 buffer.data[id.x] = buffer.data[id.x] + 1u;
96 pass
= encoder
.beginComputePass();
97 pass
.setPipeline(pipeline
);
99 } else if (encoderType
== "bundle") {
100 // Create some resources and setup the encoder.
101 const pipeline
= device
.createRenderPipeline({
104 module
: device
.createShaderModule({
106 @vertex fn vert_main() -> @builtin(position) vec4<f32> {
107 return vec4<f32>(0.5, 0.5, 0.0, 1.0);
111 entryPoint
: "vert_main",
114 module
: device
.createShaderModule({
120 @group(0) @binding(0) var<storage, read_write> data : Data;
121 @fragment fn frag_main() -> @location(0) vec4<f32> {
127 entryPoint
: "frag_main",
128 targets
: [{ format
: "rgba8unorm" }],
130 primitive
: { topology
: "point-list" },
132 encoder
= device
.createRenderBundleEncoder({
133 colorFormats
: ["rgba8unorm"],
135 encoder
.setPipeline(pipeline
);
139 if (resourceExtraParam
) {
140 resource
.extra
= true;
144 resource
.encoder
= encoder
;
148 if (encoderType
== "render" || encoderType
== "compute") {
150 } else if (encoderType
== "bundle") {
155 // Get a weak ref to the encoder, which we'll check after GC to ensure
156 // that it got collected.
157 encoderWeakRef
= SpecialPowers
.Cu
.getWeakReference(encoder
);
158 ok(encoderWeakRef
.get(), `${label} got encoder weak ref.`);
166 // The rest of the test will run in a promise chain. Define an async
167 // function to fill our results.
168 let call_test_func
= async () => {
169 for (const encoderType
of ["render", "compute", "bundle"]) {
170 for (const resourceExtraParam
of [true, false]) {
171 for (const resourceCycle
of [true, false]) {
172 for (const endOrFinish
of [true, false]) {
173 const label
= `[${encoderType}, ${resourceExtraParam}, ${resourceCycle}, ${endOrFinish}]`;
187 // Phase 1: Start the promise chain and call test_func repeated to fill
188 // our results struct.
190 // Phase 2: Do our garbage collection.
194 // Phase 3: Iterate over results and check that all of the encoders
195 // were garbage collected.
197 for (result
of results
) {
199 !result
.encoderWeakRef
.get(),
200 `${result.label} cycle collected encoder.`
205 ok(false, `unhandled exception ${e}`);