summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/mochitest
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/mochitest')
-rw-r--r--dom/webgpu/mochitest/mochitest-no-pref.ini10
-rw-r--r--dom/webgpu/mochitest/mochitest.ini42
-rw-r--r--dom/webgpu/mochitest/test_basic_canvas.worker.html18
-rw-r--r--dom/webgpu/mochitest/test_basic_canvas.worker.js32
-rw-r--r--dom/webgpu/mochitest/test_buffer_mapping.html73
-rw-r--r--dom/webgpu/mochitest/test_command_buffer_creation.html29
-rw-r--r--dom/webgpu/mochitest/test_device_creation.html29
-rw-r--r--dom/webgpu/mochitest/test_disabled.html17
-rw-r--r--dom/webgpu/mochitest/test_enabled.html17
-rw-r--r--dom/webgpu/mochitest/test_error_scope.html39
-rw-r--r--dom/webgpu/mochitest/test_insecure_context.html22
-rw-r--r--dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html261
-rw-r--r--dom/webgpu/mochitest/test_queue_write.html50
-rw-r--r--dom/webgpu/mochitest/test_submit_compute_empty.html32
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.html57
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.worker.html14
-rw-r--r--dom/webgpu/mochitest/test_submit_render_empty.worker.js48
-rw-r--r--dom/webgpu/mochitest/worker_wrapper.js33
18 files changed, 823 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..d4d111e6ee
--- /dev/null
+++ b/dom/webgpu/mochitest/mochitest-no-pref.ini
@@ -0,0 +1,10 @@
+[DEFAULT]
+subsuite = webgpu
+run-if = release_or_beta
+
+# Even if the pref were enabled, WebGPU is only available in secure contexts.
+#
+# See spec WebIDL, like this: https://www.w3.org/TR/webgpu/#navigatorgpu
+scheme = https
+
+[test_disabled.html]
diff --git a/dom/webgpu/mochitest/mochitest.ini b/dom/webgpu/mochitest/mochitest.ini
new file mode 100644
index 0000000000..96b2c55ee8
--- /dev/null
+++ b/dom/webgpu/mochitest/mochitest.ini
@@ -0,0 +1,42 @@
+[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
+
+# WebGPU is only available in secure contexts.
+#
+# See spec WebIDL, like this: https://www.w3.org/TR/webgpu/#navigatorgpu
+scheme = https
+
+[test_basic_canvas.worker.html]
+skip-if = true # Bug 1818379 - no webgpu in worker scopes, see bug 1808820
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_buffer_mapping.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_command_buffer_creation.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_device_creation.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_enabled.html]
+[test_error_scope.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_insecure_context.html]
+# This test checks that WebGPU is not available in insecure contexts.
+scheme = http
+[test_queue_copyExternalImageToTexture.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_queue_write.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_submit_compute_empty.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_submit_render_empty.html]
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
+[test_submit_render_empty.worker.html]
+skip-if = true # Bug 1818379 - no webgpu in worker scopes, see bug 1808820
+fail-if = (os == 'linux' && os_version == '18.04') || (os == 'win' && os_version == '6.1') || (os == 'mac')
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..a23ee9fc70
--- /dev/null
+++ b/dom/webgpu/mochitest/test_basic_canvas.worker.html
@@ -0,0 +1,18 @@
+<!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..5bd0434602
--- /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..01dfbf893e
--- /dev/null
+++ b/dom/webgpu/mochitest/test_buffer_mapping.html
@@ -0,0 +1,73 @@
+<!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..a92c038afd
--- /dev/null
+++ b/dom/webgpu/mochitest/test_command_buffer_creation.html
@@ -0,0 +1,29 @@
+<!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..678359c323
--- /dev/null
+++ b/dom/webgpu/mochitest/test_device_creation.html
@@ -0,0 +1,29 @@
+<!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..12eb01e465
--- /dev/null
+++ b/dom/webgpu/mochitest/test_disabled.html
@@ -0,0 +1,17 @@
+<!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..318788bf1e
--- /dev/null
+++ b/dom/webgpu/mochitest/test_enabled.html
@@ -0,0 +1,17 @@
+<!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..2bed5b937b
--- /dev/null
+++ b/dom/webgpu/mochitest/test_error_scope.html
@@ -0,0 +1,39 @@
+<!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_insecure_context.html b/dom/webgpu/mochitest/test_insecure_context.html
new file mode 100644
index 0000000000..dcc4a313b9
--- /dev/null
+++ b/dom/webgpu/mochitest/test_insecure_context.html
@@ -0,0 +1,22 @@
+<!-- This is somewhat redundant with
+ dom/tests/mochitest/general/test_interfaces.js, but I think it's good to
+ have something here as well. -->
+
+<!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(!isSecureContext, "test should not run in a secure context");
+ ok(navigator.gpu === undefined, "navigator.gpu === undefined");
+ </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..279b4a52b4
--- /dev/null
+++ b/dom/webgpu/mochitest/test_queue_copyExternalImageToTexture.html
@@ -0,0 +1,261 @@
+<!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..585c1617cd
--- /dev/null
+++ b/dom/webgpu/mochitest/test_queue_write.html
@@ -0,0 +1,50 @@
+<!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..82cb9473c5
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_compute_empty.html
@@ -0,0 +1,32 @@
+<!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.end();
+ 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..bac0d1ede7
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_render_empty.html
@@ -0,0 +1,57 @@
+<!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,
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
+ loadOp: "clear",
+ storeOp: "store",
+ },
+ ],
+ });
+ pass.executeBundles([bundle]);
+ pass.end();
+ 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..8db3168be0
--- /dev/null
+++ b/dom/webgpu/mochitest/test_submit_render_empty.worker.html
@@ -0,0 +1,14 @@
+<!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..6183983ff4
--- /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.end();
+ 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..6f6de9002d
--- /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();
+}