summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/webgpu/01_webgpu.js40
-rw-r--r--tests/unit/webgpu_test.ts262
2 files changed, 301 insertions, 1 deletions
diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js
index 5ca8c0fdb..be0b87cdf 100644
--- a/ext/webgpu/01_webgpu.js
+++ b/ext/webgpu/01_webgpu.js
@@ -1136,10 +1136,11 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
+ // assign normalized size to descriptor due to createGPUTexture needs it
+ descriptor.size = normalizeGPUExtent3D(descriptor.size);
const { rid, err } = op_webgpu_create_texture({
deviceRid: device.rid,
...descriptor,
- size: normalizeGPUExtent3D(descriptor.size),
});
device.pushError(err);
@@ -5501,6 +5502,16 @@ webidl.converters["GPUExtent3D"] = (V, opts) => {
if (typeof V === "object") {
const method = V[SymbolIterator];
if (method !== undefined) {
+ // validate length of GPUExtent3D
+ const min = 1;
+ const max = 3;
+ if (V.length < min || V.length > max) {
+ throw webidl.makeException(
+ TypeError,
+ `A sequence of number used as a GPUExtent3D must have between ${min} and ${max} elements.`,
+ opts,
+ );
+ }
return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
return webidl.converters["GPUExtent3DDict"](V, opts);
@@ -6836,6 +6847,15 @@ webidl.converters["GPUOrigin3D"] = (V, opts) => {
if (typeof V === "object") {
const method = V[SymbolIterator];
if (method !== undefined) {
+ // validate length of GPUOrigin3D
+ const length = 3;
+ if (V.length > length) {
+ throw webidl.makeException(
+ TypeError,
+ `A sequence of number used as a GPUOrigin3D must have at most ${length} elements.`,
+ opts,
+ );
+ }
return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
return webidl.converters["GPUOrigin3DDict"](V, opts);
@@ -6904,6 +6924,15 @@ webidl.converters["GPUOrigin2D"] = (V, opts) => {
if (typeof V === "object") {
const method = V[SymbolIterator];
if (method !== undefined) {
+ // validate length of GPUOrigin2D
+ const length = 2;
+ if (V.length > length) {
+ throw webidl.makeException(
+ TypeError,
+ `A sequence of number used as a GPUOrigin2D must have at most ${length} elements.`,
+ opts,
+ );
+ }
return webidl.converters["sequence<GPUIntegerCoordinate>"](V, opts);
}
return webidl.converters["GPUOrigin2DDict"](V, opts);
@@ -6989,6 +7018,15 @@ webidl.converters["GPUColor"] = (V, opts) => {
if (typeof V === "object") {
const method = V[SymbolIterator];
if (method !== undefined) {
+ // validate length of GPUColor
+ const length = 4;
+ if (V.length !== length) {
+ throw webidl.makeException(
+ TypeError,
+ `A sequence of number used as a GPUColor must have exactly ${length} elements.`,
+ opts,
+ );
+ }
return webidl.converters["sequence<double>"](V, opts);
}
return webidl.converters["GPUColorDict"](V, opts);
diff --git a/tests/unit/webgpu_test.ts b/tests/unit/webgpu_test.ts
index 517c75f9e..4b65e0033 100644
--- a/tests/unit/webgpu_test.ts
+++ b/tests/unit/webgpu_test.ts
@@ -252,6 +252,268 @@ Deno.test(function getPreferredCanvasFormat() {
assert(preferredFormat === "bgra8unorm" || preferredFormat === "rgba8unorm");
});
+Deno.test({
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function validateGPUColor() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+ const device = await adapter.requestDevice();
+ assert(device);
+
+ const format = "rgba8unorm-srgb";
+ const encoder = device.createCommandEncoder();
+ const texture = device.createTexture({
+ size: [256, 256],
+ format,
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
+ });
+ const view = texture.createView();
+ const storeOp = "store";
+ const loadOp = "clear";
+
+ // values for validating GPUColor
+ const invalidSize = [0, 0, 0];
+
+ const msgIncludes =
+ "A sequence of number used as a GPUColor must have exactly 4 elements.";
+
+ // validate the argument of descriptor.colorAttachments[@@iterator].clearValue property's length of GPUCommandEncoder.beginRenderPass when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-beginrenderpass
+ assertThrows(
+ () =>
+ encoder.beginRenderPass({
+ colorAttachments: [
+ {
+ view,
+ storeOp,
+ loadOp,
+ clearValue: invalidSize,
+ },
+ ],
+ }),
+ TypeError,
+ msgIncludes,
+ );
+ const renderPass = encoder.beginRenderPass({
+ colorAttachments: [
+ {
+ view,
+ storeOp,
+ loadOp,
+ clearValue: [0, 0, 0, 1],
+ },
+ ],
+ });
+ // validate the argument of color length of GPURenderPassEncoder.setBlendConstant when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpurenderpassencoder-setblendconstant
+ assertThrows(
+ () => renderPass.setBlendConstant(invalidSize),
+ TypeError,
+ msgIncludes,
+ );
+
+ device.destroy();
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
+Deno.test({
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function validateGPUExtent3D() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+ const device = await adapter.requestDevice();
+ assert(device);
+
+ const format = "rgba8unorm-srgb";
+ const encoder = device.createCommandEncoder();
+ const buffer = device.createBuffer({
+ size: new Uint32Array([1, 4, 3, 295]).byteLength,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+ const usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC;
+ const texture = device.createTexture({
+ size: [256, 256],
+ format,
+ usage,
+ });
+
+ // values for validating GPUExtent3D
+ const belowSize: Array<number> = [];
+ const overSize = [256, 256, 1, 1];
+
+ const msgIncludes =
+ "A sequence of number used as a GPUExtent3D must have between 1 and 3 elements.";
+
+ // validate the argument of descriptor.size property's length of GPUDevice.createTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpudevice-createtexture
+ assertThrows(
+ () => device.createTexture({ size: belowSize, format, usage }),
+ TypeError,
+ msgIncludes,
+ );
+ assertThrows(
+ () => device.createTexture({ size: overSize, format, usage }),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of copySize property's length of GPUCommandEncoder.copyBufferToTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copybuffertotexture
+ assertThrows(
+ () => encoder.copyBufferToTexture({ buffer }, { texture }, belowSize),
+ TypeError,
+ msgIncludes,
+ );
+ assertThrows(
+ () => encoder.copyBufferToTexture({ buffer }, { texture }, overSize),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of copySize property's length of GPUCommandEncoder.copyTextureToBuffer when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copytexturetobuffer
+ assertThrows(
+ () => encoder.copyTextureToBuffer({ texture }, { buffer }, belowSize),
+ TypeError,
+ msgIncludes,
+ );
+ assertThrows(
+ () => encoder.copyTextureToBuffer({ texture }, { buffer }, overSize),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of copySize property's length of GPUCommandEncoder.copyTextureToTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copytexturetotexture
+ assertThrows(
+ () => encoder.copyTextureToTexture({ texture }, { texture }, belowSize),
+ TypeError,
+ msgIncludes,
+ );
+ assertThrows(
+ () => encoder.copyTextureToTexture({ texture }, { texture }, overSize),
+ TypeError,
+ msgIncludes,
+ );
+ const data = new Uint8Array([1 * 255, 1 * 255, 1 * 255, 1 * 255]);
+ // validate the argument of size property's length of GPUQueue.writeTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpuqueue-writetexture
+ assertThrows(
+ () => device.queue.writeTexture({ texture }, data, {}, belowSize),
+ TypeError,
+ msgIncludes,
+ );
+ assertThrows(
+ () => device.queue.writeTexture({ texture }, data, {}, overSize),
+ TypeError,
+ msgIncludes,
+ );
+ // NOTE: GPUQueue.copyExternalImageToTexture needs to be validated the argument of copySize property's length when its a sequence, but it is not implemented yet
+
+ device.destroy();
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
+Deno.test({
+ ignore: true,
+}, async function validateGPUOrigin2D() {
+ // NOTE: GPUQueue.copyExternalImageToTexture needs to be validated the argument of source.origin property's length when its a sequence, but it is not implemented yet
+});
+
+Deno.test({
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function validateGPUOrigin3D() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+ const device = await adapter.requestDevice();
+ assert(device);
+
+ const format = "rgba8unorm-srgb";
+ const encoder = device.createCommandEncoder();
+ const buffer = device.createBuffer({
+ size: new Uint32Array([1, 4, 3, 295]).byteLength,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+ const usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC;
+ const size = [256, 256, 1];
+ const texture = device.createTexture({
+ size,
+ format,
+ usage,
+ });
+
+ // value for validating GPUOrigin3D
+ const overSize = [256, 256, 1, 1];
+
+ const msgIncludes =
+ "A sequence of number used as a GPUOrigin3D must have at most 3 elements.";
+
+ // validate the argument of destination.origin property's length of GPUCommandEncoder.copyBufferToTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copybuffertotexture
+ assertThrows(
+ () =>
+ encoder.copyBufferToTexture(
+ { buffer },
+ { texture, origin: overSize },
+ size,
+ ),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of source.origin property's length of GPUCommandEncoder.copyTextureToBuffer when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copytexturetobuffer
+ assertThrows(
+ () =>
+ encoder.copyTextureToBuffer(
+ { texture, origin: overSize },
+ { buffer },
+ size,
+ ),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of source.origin property's length of GPUCommandEncoder.copyTextureToTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpucommandencoder-copytexturetotexture
+ assertThrows(
+ () =>
+ encoder.copyTextureToTexture(
+ { texture, origin: overSize },
+ { texture },
+ size,
+ ),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of destination.origin property's length of GPUCommandEncoder.copyTextureToTexture when its a sequence
+ assertThrows(
+ () =>
+ encoder.copyTextureToTexture(
+ { texture },
+ { texture, origin: overSize },
+ size,
+ ),
+ TypeError,
+ msgIncludes,
+ );
+ // validate the argument of destination.origin property's length of GPUQueue.writeTexture when its a sequence
+ // https://www.w3.org/TR/2024/WD-webgpu-20240409/#dom-gpuqueue-writetexture
+ assertThrows(
+ () =>
+ device.queue.writeTexture(
+ { texture, origin: overSize },
+ new Uint8Array([1 * 255, 1 * 255, 1 * 255, 1 * 255]),
+ {},
+ size,
+ ),
+ TypeError,
+ msgIncludes,
+ );
+ // NOTE: GPUQueue.copyExternalImageToTexture needs to be validated the argument of destination.origin property's length when its a sequence, but it is not implemented yet
+
+ device.destroy();
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
async function checkIsWsl() {
return Deno.build.os === "linux" && await hasMicrosoftProcVersion();