Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / dom / webgpu / mochitest / test_encoder_cycle_collection.html
blob8b962fc10478ba05ff772f7330fcb46c3d345841
1 <!doctype html>
2 <html>
3 <head>
4 <meta charset="utf-8" />
5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel="stylesheet" href="/tests/SimpleTest/test.css" />
7 </head>
8 <body>
9 <script>
10 ok(
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.
32 let results = [];
34 // Here's our WebGPU test function, which we'll call with permuted
35 // parameters:
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
44 // dropped.
45 let test_func = async (
46 label,
47 encoderType,
48 resourceExtraParam,
49 resourceCycle,
50 endOrFinish
51 ) => {
52 const adapter = await navigator.gpu.requestAdapter();
53 const device = await adapter.requestDevice();
55 let encoder;
56 let pass;
57 let resource;
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 },
63 format: "rgba8unorm",
64 usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
65 });
66 const view = texture.createView();
67 pass = encoder.beginRenderPass({
68 colorAttachments: [
70 view,
71 loadOp: "load",
72 storeOp: "store",
75 });
76 resource = view;
77 } else if (encoderType == "compute") {
78 // Create some resources, and setup the pass.
79 encoder = device.createCommandEncoder();
80 const pipeline = device.createComputePipeline({
81 layout: "auto",
82 compute: {
83 module: device.createShaderModule({
84 code: `
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;
92 }),
93 entryPoint: "main",
95 });
96 pass = encoder.beginComputePass();
97 pass.setPipeline(pipeline);
98 resource = pipeline;
99 } else if (encoderType == "bundle") {
100 // Create some resources and setup the encoder.
101 const pipeline = device.createRenderPipeline({
102 layout: "auto",
103 vertex: {
104 module: device.createShaderModule({
105 code: `
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",
113 fragment: {
114 module: device.createShaderModule({
115 code: `
116 struct Data {
117 a : u32
120 @group(0) @binding(0) var<storage, read_write> data : Data;
121 @fragment fn frag_main() -> @location(0) vec4<f32> {
122 data.a = 0u;
123 return 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);
136 resource = pipeline;
139 if (resourceExtraParam) {
140 resource.extra = true;
143 if (resourceCycle) {
144 resource.encoder = encoder;
147 if (endOrFinish) {
148 if (encoderType == "render" || encoderType == "compute") {
149 pass.end();
150 } else if (encoderType == "bundle") {
151 encoder.finish();
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.`);
160 results.push({
161 label,
162 encoderWeakRef,
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}]`;
174 await test_func(
175 label,
176 encoderType,
177 resourceExtraParam,
178 resourceCycle,
179 endOrFinish
187 // Phase 1: Start the promise chain and call test_func repeated to fill
188 // our results struct.
189 call_test_func()
190 // Phase 2: Do our garbage collection.
191 .then(gc_promise)
192 .then(gc_promise)
193 .then(gc_promise)
194 // Phase 3: Iterate over results and check that all of the encoders
195 // were garbage collected.
196 .then(() => {
197 for (result of results) {
199 !result.encoderWeakRef.get(),
200 `${result.label} cycle collected encoder.`
204 .catch(e => {
205 ok(false, `unhandled exception ${e}`);
207 .finally(() => {
208 SimpleTest.finish();
210 </script>
211 </body>
212 </html>