summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/mochitest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /dom/webgpu/mochitest
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/webgpu/mochitest')
-rw-r--r--dom/webgpu/mochitest/mochitest-no-pref.ini4
-rw-r--r--dom/webgpu/mochitest/mochitest.ini32
-rw-r--r--dom/webgpu/mochitest/test_basic_canvas.worker.html20
-rw-r--r--dom/webgpu/mochitest/test_basic_canvas.worker.js32
-rw-r--r--dom/webgpu/mochitest/test_buffer_mapping.html59
-rw-r--r--dom/webgpu/mochitest/test_command_buffer_creation.html28
-rw-r--r--dom/webgpu/mochitest/test_device_creation.html28
-rw-r--r--dom/webgpu/mochitest/test_disabled.html16
-rw-r--r--dom/webgpu/mochitest/test_enabled.html16
-rw-r--r--dom/webgpu/mochitest/test_error_scope.html38
-rw-r--r--dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html181
-rw-r--r--dom/webgpu/mochitest/test_queue_write.html33
-rw-r--r--dom/webgpu/mochitest/test_submit_compute_empty.html31
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.html53
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.worker.html16
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.worker.js48
-rw-r--r--dom/webgpu/mochitest/worker_wrapper.js33
17 files changed, 668 insertions, 0 deletions
diff --git a/dom/webgpu/mochitest/mochitest-no-pref.ini b/dom/webgpu/mochitest/mochitest-no-pref.ini
new file mode 100644
index 0000000000..c1e2681367
--- /dev/null
+++ b/dom/webgpu/mochitest/mochitest-no-pref.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+subsuite = webgpu
+
+[test_disabled.html]
diff --git a/dom/webgpu/mochitest/mochitest.ini b/dom/webgpu/mochitest/mochitest.ini
new file mode 100644
index 0000000000..3bd5124a21
--- /dev/null
+++ b/dom/webgpu/mochitest/mochitest.ini
@@ -0,0 +1,32 @@
+[DEFAULT]
+subsuite = webgpu
+run-if = !release_or_beta
+prefs =
+ dom.webgpu.enabled=true
+ gfx.offscreencanvas.enabled=true
+support-files =
+ worker_wrapper.js
+ test_basic_canvas.worker.js
+ test_submit_render_empty.worker.js
+
+[test_enabled.html]
+[test_basic_canvas.worker.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_device_creation.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_buffer_mapping.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_command_buffer_creation.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_submit_compute_empty.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_submit_render_empty.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_submit_render_empty.worker.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_queue_copyExternalImageToTexture.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_queue_write.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
+[test_error_scope.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1')
diff --git a/dom/webgpu/mochitest/test_basic_canvas.worker.html b/dom/webgpu/mochitest/test_basic_canvas.worker.html
new file mode 100644
index 0000000000..f34ef8af24
--- /dev/null
+++ b/dom/webgpu/mochitest/test_basic_canvas.worker.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="worker_wrapper.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<canvas id="canvas"></canvas>
+<script>
+
+const canvas = document.getElementById("canvas");
+const offscreen = canvas.transferControlToOffscreen();
+
+runWorkerTest('test_basic_canvas.worker.js', {offscreen}, [offscreen]);
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_basic_canvas.worker.js b/dom/webgpu/mochitest/test_basic_canvas.worker.js
new file mode 100644
index 0000000000..ddbc15c512
--- /dev/null
+++ b/dom/webgpu/mochitest/test_basic_canvas.worker.js
@@ -0,0 +1,32 @@
+self.addEventListener("message", async function(event) {
+ try {
+ const offscreen = event.data.offscreen;
+ const context = offscreen.getContext("webgpu");
+
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ const swapChainFormat = context.getPreferredFormat(adapter);
+
+ context.configure({
+ device,
+ format: swapChainFormat,
+ size: { width: 100, height: 100, depth: 1 },
+ });
+
+ const texture = context.getCurrentTexture();
+
+ self.postMessage([
+ {
+ value: texture !== undefined,
+ message: "texture !== undefined",
+ },
+ ]);
+ } catch (e) {
+ self.postMessage([
+ {
+ value: false,
+ message: "Unhandled exception " + e,
+ },
+ ]);
+ }
+});
diff --git a/dom/webgpu/mochitest/test_buffer_mapping.html b/dom/webgpu/mochitest/test_buffer_mapping.html
new file mode 100644
index 0000000000..a3f59d0caf
--- /dev/null
+++ b/dom/webgpu/mochitest/test_buffer_mapping.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+async function testBody() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const bufferRead = device.createBuffer({ size:4, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST });
+ const bufferWrite = device.createBuffer({ size:4, usage: GPUBufferUsage.COPY_SRC, mappedAtCreation: true });
+ (new Float32Array(bufferWrite.getMappedRange())).set([1.0]);
+ bufferWrite.unmap();
+
+ const encoder = device.createCommandEncoder();
+ encoder.copyBufferToBuffer(bufferWrite, 0, bufferRead, 0, 4);
+ device.queue.submit([encoder.finish()]);
+
+ await bufferRead.mapAsync(GPUMapMode.READ);
+
+ try {
+ bufferRead.getMappedRange(0, 5);
+ ok(false, 'mapped with size outside buffer should throw');
+ } catch(e) {
+ ok(true, 'mapped with size outside buffer should throw OperationError');
+ }
+
+ try {
+ bufferRead.getMappedRange(4, 1);
+ ok(false, 'mapped with offset outside buffer should throw');
+ } catch(e) {
+ ok(true, 'mapped with offset outside buffer should throw OperationError');
+ }
+
+ const data = bufferRead.getMappedRange();
+ is(data.byteLength, 4, 'array should be 4 bytes long');
+
+ const value = (new Float32Array(data))[0];
+ ok(value == 1.0, 'value == 1.0');
+
+ bufferRead.unmap();
+ is(data.byteLength, 0, 'array should be detached after explicit unmap');
+};
+
+SimpleTest.waitForExplicitFinish();
+testBody()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_command_buffer_creation.html b/dom/webgpu/mochitest/test_command_buffer_creation.html
new file mode 100644
index 0000000000..e4f7356e0a
--- /dev/null
+++ b/dom/webgpu/mochitest/test_command_buffer_creation.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ const encoder = device.createCommandEncoder();
+ const command_buffer = encoder.finish();
+ ok(command_buffer !== undefined, 'command_buffer !== undefined');
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_device_creation.html b/dom/webgpu/mochitest/test_device_creation.html
new file mode 100644
index 0000000000..8e14ac2760
--- /dev/null
+++ b/dom/webgpu/mochitest/test_device_creation.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const limits = adapter.limits;
+ const features = adapter.features;
+ const device = await adapter.requestDevice();
+ ok(device !== undefined, 'device !== undefined');
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_disabled.html b/dom/webgpu/mochitest/test_disabled.html
new file mode 100644
index 0000000000..e96b8d7ecf
--- /dev/null
+++ b/dom/webgpu/mochitest/test_disabled.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(!SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be disabled.');
+ok(navigator.gpu === undefined, 'navigator.gpu === undefined');
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_enabled.html b/dom/webgpu/mochitest/test_enabled.html
new file mode 100644
index 0000000000..3f4af2177b
--- /dev/null
+++ b/dom/webgpu/mochitest/test_enabled.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+ok(navigator.gpu !== undefined, 'navigator.gpu !== undefined');
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_error_scope.html b/dom/webgpu/mochitest/test_error_scope.html
new file mode 100644
index 0000000000..c59996d39e
--- /dev/null
+++ b/dom/webgpu/mochitest/test_error_scope.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ device.pushErrorScope("validation");
+ const buffer = device.createBuffer({ size:0, usage: 0 });
+ const error = await device.popErrorScope();
+
+ isnot(error, null)
+
+ try {
+ await device.popErrorScope();
+ ok(false, "Should have thrown")
+ } catch (ex) {
+ ok(ex.name == 'OperationError', "Should throw an OperationError")
+ }
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html b/dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html
new file mode 100644
index 0000000000..0224620e85
--- /dev/null
+++ b/dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset='utf-8'>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+
+<body>
+ <script type='text/javascript'>
+'use strict';
+
+ok(
+ SpecialPowers.getBoolPref("dom.webgpu.enabled"),
+ "WebGPU pref should be enabled."
+);
+ok(
+ SpecialPowers.getBoolPref("gfx.offscreencanvas.enabled"),
+ "OffscreenCanvas pref should be enabled."
+);
+
+SimpleTest.waitForExplicitFinish();
+
+function requestAnimationFramePromise() {
+ return new Promise(requestAnimationFrame);
+}
+
+function createSourceCanvasWebgl() {
+ const offscreenCanvas = new OffscreenCanvas(200, 200);
+ const gl = offscreenCanvas.getContext("webgl");
+
+ const COLOR_VALUE = 127.0 / 255.0;
+ const ALPHA_VALUE = 127.0 / 255.0;
+
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 100, 100);
+ gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 0, 100, 100);
+ gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ return {
+ source: offscreenCanvas,
+ origin: { x: 0, y: 0 },
+ flipY: true,
+ };
+}
+
+function createSourceCanvas2d() {
+ const offscreenCanvas = new OffscreenCanvas(200, 200);
+ const context = offscreenCanvas.getContext("2d");
+
+ context.fillStyle = "rgba(255,0,0,0.498)";
+ context.fillRect(0, 0, 100, 100);
+
+ context.fillStyle = "rgba(0,255,0,0.498)";
+ context.fillRect(100, 0, 100, 100);
+
+ context.fillStyle = "rgba(0,0,255,0.498)";
+ context.fillRect(0, 100, 100, 100);
+
+ context.fillStyle = "rgba(0,0,0,0.498)";
+ context.fillRect(100, 100, 100, 100);
+
+ return {
+ source: offscreenCanvas,
+ origin: { x: 0, y: 0 },
+ flipY: false,
+ };
+}
+
+function createSourceImageBitmap() {
+ const sourceCanvas = createSourceCanvas2d();
+ return {
+ source: sourceCanvas.source.transferToImageBitmap(),
+ origin: { x: 0, y: 0 },
+ flipY: false,
+ };
+}
+
+async function mapDestTexture(device, source, destFormat, premultiply, copySize) {
+ const bytesPerRow = 256 * 4; // 256 aligned for 200 pixels
+ const texture = device.createTexture({
+ format: destFormat,
+ size: copySize,
+ usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
+ });
+
+ device.queue.copyExternalImageToTexture(
+ source,
+ { texture, premultipliedAlpha: premultiply },
+ copySize,
+ );
+
+ const buffer = device.createBuffer({
+ size: 1024 * 200,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+
+ const encoder = device.createCommandEncoder();
+ encoder.copyTextureToBuffer(
+ { texture },
+ { buffer, bytesPerRow },
+ copySize,
+ );
+ device.queue.submit([encoder.finish()]);
+
+ await buffer.mapAsync(GPUMapMode.READ);
+ return buffer;
+}
+
+async function verifyBuffer(test, device, source, format, premultiply, copyDim, topLeftPixelData) {
+ try {
+ const buffer = await mapDestTexture(device, source, format, premultiply, copyDim);
+ const arrayBuffer = buffer.getMappedRange();
+ const view = new Uint8Array(arrayBuffer);
+ for (let i = 0; i < topLeftPixelData.length; ++i) {
+ is(view[i], topLeftPixelData[i], test + " " + format + " (" + source.origin.x + "," + source.origin.y + ") channel " + i);
+ }
+ } catch(e) {
+ ok(false, "WebGPU exception: " + e);
+ }
+}
+
+async function verifySourceCanvas(test, device, source) {
+ await verifyBuffer(test, device, source, "rgba8unorm", /* premultiply */ true, { width: 200, height: 200 }, [127, 0, 0, 127]);
+ await verifyBuffer(test, device, source, "bgra8unorm", /* premultiply */ true, { width: 200, height: 200 }, [0, 0, 127, 127]);
+ await verifyBuffer(test, device, source, "rgba8unorm", /* premultiply */ false, { width: 200, height: 200 }, [255, 0, 0, 127]);
+ await verifyBuffer(test, device, source, "bgra8unorm", /* premultiply */ false, { width: 200, height: 200 }, [0, 0, 255, 127]);
+
+ // The copy is flipped but the origin is relative to the original source data,
+ // so we need to invert for WebGL.
+ const topRightPixelData = test === "webgl" ? [0, 0, 0, 127] : [0, 127, 0, 127];
+ const topRightOrigin = { origin: { x: 100, y: 0 } };
+ await verifyBuffer(test, device, { ...source, ...topRightOrigin }, "bgra8unorm", /* premultiply */ true, { width: 100, height: 100 }, topRightPixelData);
+
+ const bottomLeftPixelData = test === "webgl" ? [0, 0, 127, 127] : [127, 0, 0, 127];
+ const bottomLeftOrigin = { origin: { x: 0, y: 100 } };
+ await verifyBuffer(test, device, { ...source, ...bottomLeftOrigin }, "bgra8unorm", /* premultiply */ true, { width: 100, height: 100 }, bottomLeftPixelData);
+}
+
+async function writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap) {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ await verifySourceCanvas("2d", device, source2d);
+ await verifySourceCanvas("imageBitmap", device, sourceImageBitmap);
+ await verifySourceCanvas("webgl", device, sourceWebgl);
+}
+
+async function runTest() {
+ try {
+ const source2d = createSourceCanvas2d();
+ const sourceWebgl = createSourceCanvasWebgl();
+ const sourceImageBitmap = createSourceImageBitmap();
+ await requestAnimationFramePromise();
+ await requestAnimationFramePromise();
+ await writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap);
+ } catch(e) {
+ ok(false, "Uncaught exception: " + e);
+ } finally {
+ SimpleTest.finish();
+ }
+}
+
+runTest();
+ </script>
+</body>
+
+</html>
diff --git a/dom/webgpu/mochitest/test_queue_write.html b/dom/webgpu/mochitest/test_queue_write.html
new file mode 100644
index 0000000000..bcc8a104df
--- /dev/null
+++ b/dom/webgpu/mochitest/test_queue_write.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ const buffer = device.createBuffer({size:16, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.VERTEX});
+ const arrayBuf = new ArrayBuffer(16);
+ (new Int32Array(arrayBuf)).fill(5)
+ device.queue.writeBuffer(buffer, 0, arrayBuf, 0);
+ const texture = device.createTexture({size: [2,2,1], dimension: "2d", format: "rgba8unorm", usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC });
+ device.queue.writeTexture({ texture }, arrayBuf, { bytesPerRow:8 }, [2,2,1]);
+ // this isn't a process check, we need to read back the contents and verify the writes happened
+ ok(device !== undefined, '');
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_submit_compute_empty.html b/dom/webgpu/mochitest/test_submit_compute_empty.html
new file mode 100644
index 0000000000..e5a9eabfc1
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_compute_empty.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+ const encoder = device.createCommandEncoder();
+ const pass = encoder.beginComputePass();
+ pass.endPass();
+ const command_buffer = encoder.finish();
+ device.queue.submit([command_buffer]);
+ ok(command_buffer !== undefined, 'command_buffer !== undefined');
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_submit_render_empty.html b/dom/webgpu/mochitest/test_submit_render_empty.html
new file mode 100644
index 0000000000..aec2a606ef
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_render_empty.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+ok(SpecialPowers.getBoolPref('dom.webgpu.enabled'), 'Pref should be enabled.');
+
+const func = async function() {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const swapChainFormat = "rgba8unorm";
+ const bundleEncoder = device.createRenderBundleEncoder({
+ colorFormats: [swapChainFormat],
+ });
+ const bundle = bundleEncoder.finish({});
+
+ const texture = device.createTexture({
+ size: { width: 100, height: 100, depth: 1 },
+ format: swapChainFormat,
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
+ });
+ const view = texture.createView();
+
+ const encoder = device.createCommandEncoder();
+ const pass = encoder.beginRenderPass({
+ colorAttachments: [{
+ view,
+ loadValue: { r: 0, g: 0, b: 0, a: 0 },
+ storeOp: "store",
+ }],
+ });
+ pass.executeBundles([bundle]);
+ pass.endPass();
+ const command_buffer = encoder.finish();
+
+ device.queue.submit([command_buffer]);
+ ok(command_buffer !== undefined, 'command_buffer !== undefined');
+};
+
+SimpleTest.waitForExplicitFinish();
+func()
+ .catch((e) => ok(false, "Unhandled exception " + e))
+ .finally(() => SimpleTest.finish());
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_submit_render_empty.worker.html b/dom/webgpu/mochitest/test_submit_render_empty.worker.html
new file mode 100644
index 0000000000..100f866ecc
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_render_empty.worker.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="worker_wrapper.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+
+runWorkerTest('test_submit_render_empty.worker.js', {}, []);
+
+</script>
+</body>
+</html>
diff --git a/dom/webgpu/mochitest/test_submit_render_empty.worker.js b/dom/webgpu/mochitest/test_submit_render_empty.worker.js
new file mode 100644
index 0000000000..1d922d38d5
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_render_empty.worker.js
@@ -0,0 +1,48 @@
+self.addEventListener("message", async function(event) {
+ try {
+ const adapter = await navigator.gpu.requestAdapter();
+ const device = await adapter.requestDevice();
+
+ const swapChainFormat = "rgba8unorm";
+ const bundleEncoder = device.createRenderBundleEncoder({
+ colorFormats: [swapChainFormat],
+ });
+ const bundle = bundleEncoder.finish({});
+
+ const texture = device.createTexture({
+ size: { width: 100, height: 100, depth: 1 },
+ format: swapChainFormat,
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
+ });
+ const view = texture.createView();
+
+ const encoder = device.createCommandEncoder();
+ const pass = encoder.beginRenderPass({
+ colorAttachments: [
+ {
+ view,
+ loadValue: { r: 0, g: 0, b: 0, a: 0 },
+ storeOp: "store",
+ },
+ ],
+ });
+ pass.executeBundles([bundle]);
+ pass.endPass();
+ const command_buffer = encoder.finish();
+
+ device.queue.submit([command_buffer]);
+ self.postMessage([
+ {
+ value: command_buffer !== undefined,
+ message: "command_buffer !== undefined",
+ },
+ ]);
+ } catch (e) {
+ self.postMessage([
+ {
+ value: false,
+ message: "Unhandled exception " + e,
+ },
+ ]);
+ }
+});
diff --git a/dom/webgpu/mochitest/worker_wrapper.js b/dom/webgpu/mochitest/worker_wrapper.js
new file mode 100644
index 0000000000..19ce6dd21e
--- /dev/null
+++ b/dom/webgpu/mochitest/worker_wrapper.js
@@ -0,0 +1,33 @@
+ok(
+ SpecialPowers.getBoolPref("dom.webgpu.enabled"),
+ "WebGPU pref should be enabled."
+);
+ok(
+ SpecialPowers.getBoolPref("gfx.offscreencanvas.enabled"),
+ "OffscreenCanvas pref should be enabled."
+);
+SimpleTest.waitForExplicitFinish();
+
+const workerWrapperFunc = async function(worker_path, data, transfer) {
+ const worker = new Worker(worker_path);
+
+ const results = new Promise((resolve, reject) => {
+ worker.addEventListener("message", event => {
+ resolve(event.data);
+ });
+ });
+
+ worker.postMessage(data, transfer);
+ for (const result of await results) {
+ ok(result.value, result.message);
+ }
+};
+
+async function runWorkerTest(worker_path, data, transfer) {
+ try {
+ await workerWrapperFunc(worker_path, data, transfer);
+ } catch (e) {
+ ok(false, "Unhandled exception " + e);
+ }
+ SimpleTest.finish();
+}