diff --git a/Cargo.lock b/Cargo.lock
index eb2e05042..69b4d58d9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1077,7 +1077,7 @@ dependencies = [
[[package]]
name = "deno_webgpu"
-version = "0.85.0"
+version = "0.110.0"
dependencies = [
"deno_core",
"raw-window-handle 0.6.0",
diff --git a/Cargo.toml b/Cargo.toml
index 7cb26434b..52e8c5c17 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -170,7 +170,7 @@ deno_core = "0.272.0"
deno_url = "0.143.0"
deno_web = "0.174.0"
deno_webidl = "0.143.0"
-deno_webgpu = { version = "0.85.0", path = "./deno_webgpu" }
+deno_webgpu = { version = "0.110.0", path = "./deno_webgpu" }
tokio = "1.36.0"
termcolor = "1.4.1"
diff --git a/cts_runner/src/bootstrap.js b/cts_runner/src/bootstrap.js
index b16884393..5d9c6f65d 100644
--- a/cts_runner/src/bootstrap.js
+++ b/cts_runner/src/bootstrap.js
@@ -26,8 +26,9 @@ import { Console } from "ext:deno_console/01_console.js";
import * as url from "ext:deno_url/00_url.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";
import * as performance from "ext:deno_web/15_performance.js";
-import * as webgpu from "ext:deno_webgpu/01_webgpu.js";
+import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
import * as imageData from "ext:deno_web/16_image_data.js";
+const webgpu = loadWebGPU();
// imports needed to pass module evaluation
import "ext:deno_url/01_urlpattern.js";
@@ -39,6 +40,7 @@ import "ext:deno_web/10_filereader.js";
import "ext:deno_web/12_location.js";
import "ext:deno_web/13_message_port.js";
import "ext:deno_web/14_compression.js";
+import "ext:deno_webgpu/02_surface.js";
let globalThis_;
diff --git a/cts_runner/src/main.rs b/cts_runner/src/main.rs
index 201fda80d..fe8c1cf81 100644
--- a/cts_runner/src/main.rs
+++ b/cts_runner/src/main.rs
@@ -29,6 +29,9 @@ mod native {
.ok_or_else(|| anyhow!("missing specifier in first command line argument"))?;
let specifier = resolve_url_or_path(&url, &env::current_dir()?)?;
+ let mut feature_checker = deno_core::FeatureChecker::default();
+ feature_checker.enable_feature(deno_webgpu::UNSTABLE_FEATURE_NAME);
+
let options = RuntimeOptions {
module_loader: Some(Rc::new(deno_core::FsModuleLoader)),
get_error_class_fn: Some(&get_error_class_name),
@@ -40,9 +43,10 @@ mod native {
Arc::new(BlobStore::default()),
None,
),
- deno_webgpu::deno_webgpu::init_ops_and_esm(true),
+ deno_webgpu::deno_webgpu::init_ops_and_esm(),
cts_runner::init_ops_and_esm(),
],
+ feature_checker: Some(Arc::new(feature_checker)),
..Default::default()
};
let mut js_runtime = JsRuntime::new(options);
diff --git a/deno_webgpu/00_init.js b/deno_webgpu/00_init.js
new file mode 100644
index 000000000..0f10847ce
--- /dev/null
+++ b/deno_webgpu/00_init.js
@@ -0,0 +1,7 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+import { core } from "ext:core/mod.js";
+
+const loadWebGPU = core.createLazyLoader("ext:deno_webgpu/01_webgpu.js");
+
+export { loadWebGPU };
diff --git a/deno_webgpu/01_webgpu.js b/deno_webgpu/01_webgpu.js
index 6aecb0323..11d7a5a44 100644
--- a/deno_webgpu/01_webgpu.js
+++ b/deno_webgpu/01_webgpu.js
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// @ts-check
///
@@ -7,22 +7,100 @@
///
import { core, primordials } from "ext:core/mod.js";
-import * as ops from "ext:core/ops";
-import * as webidl from "ext:deno_webidl/00_webidl.js";
-import { EventTarget } from "ext:deno_web/02_event.js";
-import { DOMException } from "ext:deno_web/01_dom_exception.js";
-import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
+const {
+ isDataView,
+ isTypedArray,
+} = core;
+import {
+ op_webgpu_buffer_get_map_async,
+ op_webgpu_buffer_get_mapped_range,
+ op_webgpu_buffer_unmap,
+ op_webgpu_command_encoder_begin_compute_pass,
+ op_webgpu_command_encoder_begin_render_pass,
+ op_webgpu_command_encoder_clear_buffer,
+ op_webgpu_command_encoder_copy_buffer_to_buffer,
+ op_webgpu_command_encoder_copy_buffer_to_texture,
+ op_webgpu_command_encoder_copy_texture_to_buffer,
+ op_webgpu_command_encoder_copy_texture_to_texture,
+ op_webgpu_command_encoder_finish,
+ op_webgpu_command_encoder_insert_debug_marker,
+ op_webgpu_command_encoder_pop_debug_group,
+ op_webgpu_command_encoder_push_debug_group,
+ op_webgpu_command_encoder_resolve_query_set,
+ op_webgpu_command_encoder_write_timestamp,
+ op_webgpu_compute_pass_dispatch_workgroups,
+ op_webgpu_compute_pass_dispatch_workgroups_indirect,
+ op_webgpu_compute_pass_end,
+ op_webgpu_compute_pass_insert_debug_marker,
+ op_webgpu_compute_pass_pop_debug_group,
+ op_webgpu_compute_pass_push_debug_group,
+ op_webgpu_compute_pass_set_bind_group,
+ op_webgpu_compute_pass_set_pipeline,
+ op_webgpu_compute_pipeline_get_bind_group_layout,
+ op_webgpu_create_bind_group,
+ op_webgpu_create_bind_group_layout,
+ op_webgpu_create_buffer,
+ op_webgpu_create_command_encoder,
+ op_webgpu_create_compute_pipeline,
+ op_webgpu_create_pipeline_layout,
+ op_webgpu_create_query_set,
+ op_webgpu_create_render_bundle_encoder,
+ op_webgpu_create_render_pipeline,
+ op_webgpu_create_sampler,
+ op_webgpu_create_shader_module,
+ op_webgpu_create_texture,
+ op_webgpu_create_texture_view,
+ op_webgpu_queue_submit,
+ op_webgpu_render_bundle_encoder_draw,
+ op_webgpu_render_bundle_encoder_draw_indexed,
+ op_webgpu_render_bundle_encoder_draw_indirect,
+ op_webgpu_render_bundle_encoder_finish,
+ op_webgpu_render_bundle_encoder_insert_debug_marker,
+ op_webgpu_render_bundle_encoder_pop_debug_group,
+ op_webgpu_render_bundle_encoder_push_debug_group,
+ op_webgpu_render_bundle_encoder_set_bind_group,
+ op_webgpu_render_bundle_encoder_set_index_buffer,
+ op_webgpu_render_bundle_encoder_set_pipeline,
+ op_webgpu_render_bundle_encoder_set_vertex_buffer,
+ op_webgpu_render_pass_begin_occlusion_query,
+ op_webgpu_render_pass_draw,
+ op_webgpu_render_pass_draw_indexed,
+ op_webgpu_render_pass_draw_indexed_indirect,
+ op_webgpu_render_pass_draw_indirect,
+ op_webgpu_render_pass_end,
+ op_webgpu_render_pass_end_occlusion_query,
+ op_webgpu_render_pass_execute_bundles,
+ op_webgpu_render_pass_insert_debug_marker,
+ op_webgpu_render_pass_pop_debug_group,
+ op_webgpu_render_pass_push_debug_group,
+ op_webgpu_render_pass_set_bind_group,
+ op_webgpu_render_pass_set_blend_constant,
+ op_webgpu_render_pass_set_index_buffer,
+ op_webgpu_render_pass_set_pipeline,
+ op_webgpu_render_pass_set_scissor_rect,
+ op_webgpu_render_pass_set_stencil_reference,
+ op_webgpu_render_pass_set_vertex_buffer,
+ op_webgpu_render_pass_set_viewport,
+ op_webgpu_render_pipeline_get_bind_group_layout,
+ op_webgpu_request_adapter,
+ op_webgpu_request_adapter_info,
+ op_webgpu_request_device,
+ op_webgpu_write_buffer,
+ op_webgpu_write_texture,
+} from "ext:core/ops";
const {
ArrayBuffer,
- ArrayBufferIsView,
+ ArrayBufferPrototypeGetByteLength,
ArrayIsArray,
ArrayPrototypeFilter,
ArrayPrototypeMap,
ArrayPrototypePop,
ArrayPrototypePush,
+ DataViewPrototypeGetBuffer,
Error,
MathMax,
ObjectDefineProperty,
+ ObjectHasOwn,
ObjectPrototypeIsPrototypeOf,
Promise,
PromisePrototypeCatch,
@@ -31,17 +109,28 @@ const {
PromiseResolve,
SafeArrayIterator,
SafePromiseAll,
- Set,
+ SafeSet,
+ SafeWeakRef,
SetPrototypeHas,
Symbol,
SymbolFor,
SymbolIterator,
TypeError,
+ TypedArrayPrototypeGetBuffer,
+ TypedArrayPrototypeGetSymbolToStringTag,
Uint32Array,
- Uint32ArrayPrototype,
Uint8Array,
} = primordials;
+import * as webidl from "ext:deno_webidl/00_webidl.js";
+import {
+ Event,
+ EventTarget,
+ defineEventHandler,
+} from "ext:deno_web/02_event.js";
+import { DOMException } from "ext:deno_web/01_dom_exception.js";
+import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
+
const _rid = Symbol("[[rid]]");
const _size = Symbol("[[size]]");
const _usage = Symbol("[[usage]]");
@@ -228,6 +317,42 @@ class GPUOutOfMemoryError extends GPUError {
}
const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype;
+class GPUInternalError extends GPUError {
+ name = "GPUInternalError";
+ constructor() {
+ super(illegalConstructorKey);
+ this[webidl.brand] = webidl.brand;
+ }
+}
+const GPUInternalErrorPrototype = GPUInternalError.prototype;
+
+class GPUUncapturedErrorEvent extends Event {
+ #error;
+
+ constructor(type, gpuUncapturedErrorEventInitDict) {
+ super(type, gpuUncapturedErrorEventInitDict);
+ this[webidl.brand] = webidl.brand;
+
+ const prefix = "Failed to construct 'GPUUncapturedErrorEvent'";
+ webidl.requiredArguments(arguments.length, 2, prefix);
+ gpuUncapturedErrorEventInitDict = webidl.converters
+ .gpuUncapturedErrorEventInitDict(
+ gpuUncapturedErrorEventInitDict,
+ prefix,
+ "Argument 2",
+ );
+
+ this.#error = gpuUncapturedErrorEventInitDict.error;
+ }
+
+ get error() {
+ webidl.assertBranded(this, GPUUncapturedErrorEventPrototype);
+ return this.#error;
+ }
+}
+const GPUUncapturedErrorEventPrototype = GPUUncapturedErrorEvent.prototype;
+defineEventHandler(GPUUncapturedErrorEvent.prototype, "uncapturederror");
+
class GPU {
[webidl.brand] = webidl.brand;
@@ -238,6 +363,7 @@ class GPU {
/**
* @param {GPURequestAdapterOptions} options
*/
+ // deno-lint-ignore require-await
async requestAdapter(options = {}) {
webidl.assertBranded(this, GPUPrototype);
options = webidl.converters.GPURequestAdapterOptions(
@@ -246,7 +372,7 @@ class GPU {
"Argument 1",
);
- const { err, ...data } = await ops.op_webgpu_request_adapter(
+ const { err, ...data } = op_webgpu_request_adapter(
options.powerPreference,
options.forceFallbackAdapter,
);
@@ -258,6 +384,16 @@ class GPU {
}
}
+ getPreferredCanvasFormat() {
+ // Same as Gecko.
+ //
+ // https://github.com/mozilla/gecko-dev/blob/b75080bb8b11844d18cb5f9ac6e68a866ef8e243/dom/webgpu/Instance.h#L42-L47
+ if (core.build.os == "android") {
+ return "rgba8unorm";
+ }
+ return "bgra8unorm";
+ }
+
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
return `${this.constructor.name} ${inspect({}, inspectOptions)}`;
}
@@ -303,7 +439,6 @@ class GPUAdapter {
}
/** @returns {boolean} */
get isFallbackAdapter() {
- webidl.assertBranded(this, GPUAdapterPrototype);
webidl.assertBranded(this, GPUAdapterPrototype);
return this[_adapter].isFallbackAdapter;
}
@@ -316,6 +451,7 @@ class GPUAdapter {
* @param {GPUDeviceDescriptor} descriptor
* @returns {Promise}
*/
+ // deno-lint-ignore require-await
async requestDevice(descriptor = {}) {
webidl.assertBranded(this, GPUAdapterPrototype);
const prefix = "Failed to execute 'requestDevice' on 'GPUAdapter'";
@@ -336,7 +472,7 @@ class GPUAdapter {
}
}
- const { rid, features, limits } = await ops.op_webgpu_request_device(
+ const { rid, queueRid, features, limits } = op_webgpu_request_device(
this[_adapter].rid,
descriptor.label,
requiredFeatures,
@@ -349,43 +485,34 @@ class GPUAdapter {
features: createGPUSupportedFeatures(features),
limits: createGPUSupportedLimits(limits),
});
- return createGPUDevice(
+ const device = createGPUDevice(
descriptor.label,
inner,
- createGPUQueue(descriptor.label, inner),
+ createGPUQueue(descriptor.label, inner, queueRid),
);
+ inner.device = device;
+ return device;
}
/**
- * @param {string[]} unmaskHints
* @returns {Promise}
*/
- async requestAdapterInfo(unmaskHints = []) {
+ requestAdapterInfo() {
webidl.assertBranded(this, GPUAdapterPrototype);
- const prefix = "Failed to execute 'requestAdapterInfo' on 'GPUAdapter'";
- unmaskHints = webidl.converters["sequence"](
- unmaskHints,
- prefix,
- "Argument 1",
- );
const {
vendor,
architecture,
device,
description,
- } = await ops.op_webgpu_request_adapter_info(this[_adapter].rid);
+ } = op_webgpu_request_adapter_info(this[_adapter].rid);
const adapterInfo = webidl.createBranded(GPUAdapterInfo);
- adapterInfo[_vendor] = unmaskHints.includes("vendor") ? vendor : "";
- adapterInfo[_architecture] = unmaskHints.includes("architecture")
- ? architecture
- : "";
- adapterInfo[_device] = unmaskHints.includes("device") ? device : "";
- adapterInfo[_description] = unmaskHints.includes("description")
- ? description
- : "";
- return adapterInfo;
+ adapterInfo[_vendor] = vendor;
+ adapterInfo[_architecture] = architecture;
+ adapterInfo[_device] = device;
+ adapterInfo[_description] = description;
+ return PromiseResolve(adapterInfo);
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
@@ -588,6 +715,14 @@ class GPUSupportedLimits {
webidl.assertBranded(this, GPUSupportedLimitsPrototype);
return this[_limits].maxInterStageShaderComponents;
}
+ get maxColorAttachments() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxColorAttachments;
+ }
+ get maxColorAttachmentBytesPerSample() {
+ webidl.assertBranded(this, GPUSupportedLimitsPrototype);
+ return this[_limits].maxColorAttachmentBytesPerSample;
+ }
get maxComputeWorkgroupStorageSize() {
webidl.assertBranded(this, GPUSupportedLimitsPrototype);
return this[_limits].maxComputeWorkgroupStorageSize;
@@ -617,7 +752,10 @@ class GPUSupportedLimits {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUSupportedLimitsPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUSupportedLimitsPrototype,
+ this,
+ ),
keys: [
"maxTextureDimension1D",
"maxTextureDimension2D",
@@ -641,6 +779,8 @@ class GPUSupportedLimits {
"maxVertexAttributes",
"maxVertexBufferArrayStride",
"maxInterStageShaderComponents",
+ "maxColorAttachments",
+ "maxColorAttachmentBytesPerSample",
"maxComputeWorkgroupStorageSize",
"maxComputeInvocationsPerWorkgroup",
"maxComputeWorkgroupSizeX",
@@ -658,7 +798,7 @@ const GPUSupportedLimitsPrototype = GPUSupportedLimits.prototype;
function createGPUSupportedFeatures(features) {
/** @type {GPUSupportedFeatures} */
const supportedFeatures = webidl.createBranded(GPUSupportedFeatures);
- supportedFeatures[webidl.setlikeInner] = new Set(features);
+ supportedFeatures[webidl.setlikeInner] = new SafeSet(features);
webidl.setlike(
supportedFeatures,
GPUSupportedFeaturesPrototype,
@@ -676,8 +816,7 @@ class GPUSupportedFeatures {
if (ObjectPrototypeIsPrototypeOf(GPUSupportedFeaturesPrototype, this)) {
return `${this.constructor.name} ${
// deno-lint-ignore prefer-primordials
- inspect([...this], inspectOptions)
- }`;
+ inspect([...this], inspectOptions)}`;
} else {
return `${this.constructor.name} ${inspect({}, inspectOptions)}`;
}
@@ -721,7 +860,10 @@ class GPUDeviceLostInfo {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUDeviceLostInfoPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUDeviceLostInfoPrototype,
+ this,
+ ),
keys: [
"reason",
"message",
@@ -775,6 +917,7 @@ function GPUObjectBaseMixin(name, type) {
* @property {number | undefined} rid
* @property {GPUSupportedFeatures} features
* @property {GPUSupportedLimits} limits
+ * @property {GPUDevice} device
*/
class InnerGPUDevice {
@@ -786,7 +929,7 @@ class InnerGPUDevice {
features;
/** @type {GPUSupportedLimits} */
limits;
- /** @type {WeakRef[]} */
+ /** @type {SafeWeakRef[]} */
resources;
/** @type {boolean} */
isLost;
@@ -796,6 +939,8 @@ class InnerGPUDevice {
resolveLost;
/** @type {ErrorScope[]} */
errorScopeStack;
+ /** @type {GPUDevice} */
+ device;
/**
* @param {InnerGPUDeviceOptions} options
@@ -816,7 +961,7 @@ class InnerGPUDevice {
/** @param {any} resource */
trackResource(resource) {
- ArrayPrototypePush(this.resources, new WeakRef(resource));
+ ArrayPrototypePush(this.resources, new SafeWeakRef(resource));
}
/** @param {{ type: string, value: string | null } | undefined} err */
@@ -841,6 +986,8 @@ class InnerGPUDevice {
);
case "out-of-memory":
return PromiseReject(new GPUOutOfMemoryError());
+ case "internal":
+ return PromiseReject(new GPUInternalError());
}
}
});
@@ -865,8 +1012,12 @@ class InnerGPUDevice {
validationFilteredPromise,
);
} else {
- PromisePrototypeCatch(validationFilteredPromise, () => {
- // TODO(lucacasonato): emit an UncapturedErrorEvent
+ PromisePrototypeCatch(validationFilteredPromise, (err) => {
+ this.device.dispatchEvent(
+ new GPUUncapturedErrorEvent("uncapturederror", {
+ error: err,
+ }),
+ );
});
}
// prevent uncaptured promise rejections
@@ -886,12 +1037,41 @@ class InnerGPUDevice {
if (oomScope) {
ArrayPrototypePush(oomScope.operations, oomFilteredPromise);
} else {
- PromisePrototypeCatch(oomFilteredPromise, () => {
- // TODO(lucacasonato): emit an UncapturedErrorEvent
+ PromisePrototypeCatch(oomFilteredPromise, (err) => {
+ this.device.dispatchEvent(
+ new GPUUncapturedErrorEvent("uncapturederror", {
+ error: err,
+ }),
+ );
});
}
// prevent uncaptured promise rejections
PromisePrototypeCatch(oomFilteredPromise, (_err) => {});
+
+ const internalStack = ArrayPrototypeFilter(
+ this.errorScopeStack,
+ ({ filter }) => filter == "internal",
+ );
+ const internalScope = internalStack[internalStack.length - 1];
+ const internalFilteredPromise = PromisePrototypeCatch(operation, (err) => {
+ if (ObjectPrototypeIsPrototypeOf(GPUInternalErrorPrototype, err)) {
+ return PromiseReject(err);
+ }
+ return PromiseResolve();
+ });
+ if (internalScope) {
+ ArrayPrototypePush(internalScope.operations, internalFilteredPromise);
+ } else {
+ PromisePrototypeCatch(internalFilteredPromise, (err) => {
+ this.device.dispatchEvent(
+ new GPUUncapturedErrorEvent("uncapturederror", {
+ error: err,
+ }),
+ );
+ });
+ }
+ // prevent uncaptured promise rejections
+ PromisePrototypeCatch(internalFilteredPromise, (_err) => {});
}
}
@@ -971,7 +1151,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_buffer(
+ const { rid, err } = op_webgpu_create_buffer(
device.rid,
descriptor.label,
descriptor.size,
@@ -1022,7 +1202,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_texture({
+ const { rid, err } = op_webgpu_create_texture({
deviceRid: device.rid,
...descriptor,
size: normalizeGPUExtent3D(descriptor.size),
@@ -1051,7 +1231,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_sampler({
+ const { rid, err } = op_webgpu_create_sampler({
deviceRid: device.rid,
...descriptor,
});
@@ -1084,6 +1264,7 @@ class GPUDevice extends EventTarget {
const entry = descriptor.entries[i];
let j = 0;
+ // deno-lint-ignore prefer-primordials
if (entry.buffer) j++;
if (entry.sampler) j++;
if (entry.texture) j++;
@@ -1094,7 +1275,7 @@ class GPUDevice extends EventTarget {
}
}
- const { rid, err } = ops.op_webgpu_create_bind_group_layout(
+ const { rid, err } = op_webgpu_create_bind_group_layout(
device.rid,
descriptor.label,
descriptor.entries,
@@ -1137,7 +1318,7 @@ class GPUDevice extends EventTarget {
return rid;
},
);
- const { rid, err } = ops.op_webgpu_create_pipeline_layout(
+ const { rid, err } = op_webgpu_create_pipeline_layout(
device.rid,
descriptor.label,
bindGroupLayouts,
@@ -1204,7 +1385,9 @@ class GPUDevice extends EventTarget {
resource: rid,
};
} else {
+ // deno-lint-ignore prefer-primordials
const rid = assertResource(resource.buffer, prefix, context);
+ // deno-lint-ignore prefer-primordials
assertDeviceMatch(device, resource.buffer, {
prefix,
resourceContext: context,
@@ -1220,7 +1403,7 @@ class GPUDevice extends EventTarget {
}
});
- const { rid, err } = ops.op_webgpu_create_bind_group(
+ const { rid, err } = op_webgpu_create_bind_group(
device.rid,
descriptor.label,
layout,
@@ -1250,7 +1433,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_shader_module(
+ const { rid, err } = op_webgpu_create_shader_module(
device.rid,
descriptor.label,
descriptor.code,
@@ -1301,7 +1484,7 @@ class GPUDevice extends EventTarget {
selfContext: "this",
});
- const { rid, err } = ops.op_webgpu_create_compute_pipeline(
+ const { rid, err } = op_webgpu_create_compute_pipeline(
device.rid,
descriptor.label,
layout,
@@ -1375,7 +1558,7 @@ class GPUDevice extends EventTarget {
};
}
- const { rid, err } = ops.op_webgpu_create_render_pipeline({
+ const { rid, err } = op_webgpu_create_render_pipeline({
deviceRid: device.rid,
label: descriptor.label,
layout,
@@ -1402,12 +1585,166 @@ class GPUDevice extends EventTarget {
createComputePipelineAsync(descriptor) {
// TODO(lucacasonato): this should be real async
- return PromiseResolve(this.createComputePipeline(descriptor));
+
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix =
+ "Failed to execute 'createComputePipelineAsync' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, prefix);
+ descriptor = webidl.converters.GPUComputePipelineDescriptor(
+ descriptor,
+ prefix,
+ "Argument 1",
+ );
+ const device = assertDevice(this, prefix, "this");
+ let layout = descriptor.layout;
+ if (typeof descriptor.layout !== "string") {
+ const context = "layout";
+ layout = assertResource(descriptor.layout, prefix, context);
+ assertDeviceMatch(device, descriptor.layout, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ }
+ const module = assertResource(
+ descriptor.compute.module,
+ prefix,
+ "compute shader module",
+ );
+ assertDeviceMatch(device, descriptor.compute.module, {
+ prefix,
+ resourceContext: "compute shader module",
+ selfContext: "this",
+ });
+
+ const { rid, err } = op_webgpu_create_compute_pipeline(
+ device.rid,
+ descriptor.label,
+ layout,
+ {
+ module,
+ entryPoint: descriptor.compute.entryPoint,
+ constants: descriptor.compute.constants,
+ },
+ );
+ device.pushError(err);
+ if (err) {
+ switch (err.type) {
+ case "validation":
+ return PromiseReject(
+ new GPUPipelineError(err.value ?? "validation error", {
+ reason: "validation",
+ }),
+ );
+ case "internal":
+ return PromiseReject(
+ new GPUPipelineError("internal error", {
+ reason: "validation",
+ }),
+ );
+ }
+ }
+
+ const computePipeline = createGPUComputePipeline(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(computePipeline);
+ return PromiseResolve(computePipeline);
}
createRenderPipelineAsync(descriptor) {
// TODO(lucacasonato): this should be real async
- return PromiseResolve(this.createRenderPipeline(descriptor));
+
+ webidl.assertBranded(this, GPUDevicePrototype);
+ const prefix =
+ "Failed to execute 'createRenderPipelineAsync' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, prefix);
+ descriptor = webidl.converters.GPURenderPipelineDescriptor(
+ descriptor,
+ prefix,
+ "Argument 1",
+ );
+ const device = assertDevice(this, prefix, "this");
+ let layout = descriptor.layout;
+ if (typeof descriptor.layout !== "string") {
+ const context = "layout";
+ layout = assertResource(descriptor.layout, prefix, context);
+ assertDeviceMatch(device, descriptor.layout, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ }
+ const module = assertResource(
+ descriptor.vertex.module,
+ prefix,
+ "vertex shader module",
+ );
+ assertDeviceMatch(device, descriptor.vertex.module, {
+ prefix,
+ resourceContext: "vertex shader module",
+ selfContext: "this",
+ });
+ let fragment = undefined;
+ if (descriptor.fragment) {
+ const module = assertResource(
+ descriptor.fragment.module,
+ prefix,
+ "fragment shader module",
+ );
+ assertDeviceMatch(device, descriptor.fragment.module, {
+ prefix,
+ resourceContext: "fragment shader module",
+ selfContext: "this",
+ });
+ fragment = {
+ module,
+ entryPoint: descriptor.fragment.entryPoint,
+ targets: descriptor.fragment.targets,
+ };
+ }
+
+ const { rid, err } = op_webgpu_create_render_pipeline({
+ deviceRid: device.rid,
+ label: descriptor.label,
+ layout,
+ vertex: {
+ module,
+ entryPoint: descriptor.vertex.entryPoint,
+ buffers: descriptor.vertex.buffers,
+ },
+ primitive: descriptor.primitive,
+ depthStencil: descriptor.depthStencil,
+ multisample: descriptor.multisample,
+ fragment,
+ });
+ device.pushError(err);
+ if (err) {
+ switch (err.type) {
+ case "validation":
+ return PromiseReject(
+ new GPUPipelineError(err.value ?? "validation error", {
+ reason: "validation",
+ }),
+ );
+ case "internal":
+ return PromiseReject(
+ new GPUPipelineError("internal error", {
+ reason: "validation",
+ }),
+ );
+ }
+ }
+
+ const renderPipeline = createGPURenderPipeline(
+ descriptor.label,
+ device,
+ rid,
+ );
+ device.trackResource(renderPipeline);
+ return renderPipeline;
}
/**
@@ -1423,7 +1760,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_command_encoder(
+ const { rid, err } = op_webgpu_create_command_encoder(
device.rid,
descriptor.label,
);
@@ -1453,7 +1790,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_render_bundle_encoder({
+ const { rid, err } = op_webgpu_create_render_bundle_encoder({
deviceRid: device.rid,
...descriptor,
});
@@ -1482,7 +1819,7 @@ class GPUDevice extends EventTarget {
"Argument 1",
);
const device = assertDevice(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_query_set({
+ const { rid, err } = op_webgpu_create_query_set({
deviceRid: device.rid,
...descriptor,
});
@@ -1570,22 +1907,49 @@ class GPUDevice extends EventTarget {
GPUObjectBaseMixin("GPUDevice", GPUDevice);
const GPUDevicePrototype = GPUDevice.prototype;
+class GPUPipelineError extends DOMException {
+ #reason;
+
+ constructor(message = "", options = {}) {
+ const prefix = "Failed to construct 'GPUPipelineError'";
+ message = webidl.converters.DOMString(message, prefix, "Argument 1");
+ options = webidl.converters.GPUPipelineErrorInit(
+ options,
+ prefix,
+ "Argument 2",
+ );
+ super(message, "GPUPipelineError");
+
+ this.#reason = options.reason;
+ }
+
+ get reason() {
+ webidl.assertBranded(this, GPUPipelineErrorPrototype);
+ return this.#reason;
+ }
+}
+const GPUPipelineErrorPrototype = GPUPipelineError.prototype;
+
/**
* @param {string | null} label
* @param {InnerGPUDevice} device
+ * @param {number} rid
* @returns {GPUQueue}
*/
-function createGPUQueue(label, device) {
+function createGPUQueue(label, device, rid) {
/** @type {GPUQueue} */
const queue = webidl.createBranded(GPUQueue);
queue[_label] = label;
queue[_device] = device;
+ queue[_rid] = rid;
return queue;
}
class GPUQueue {
/** @type {InnerGPUDevice} */
[_device];
+ /** @type {number} */
+ [_rid];
constructor() {
webidl.illegalConstructor();
@@ -1619,7 +1983,7 @@ class GPUQueue {
return rid;
},
);
- const { err } = ops.op_webgpu_queue_submit(device.rid, commandBufferRids);
+ const { err } = op_webgpu_queue_submit(this[_rid], commandBufferRids);
for (let i = 0; i < commandBuffers.length; ++i) {
commandBuffers[i][_rid] = undefined;
}
@@ -1664,13 +2028,23 @@ class GPUQueue {
selfContext: "this",
resourceContext: "Argument 1",
});
- const { err } = ops.op_webgpu_write_buffer(
- device.rid,
+ /** @type {ArrayBufferLike} */
+ let abLike = data;
+ if (isTypedArray(data)) {
+ abLike = TypedArrayPrototypeGetBuffer(
+ /** @type {Uint8Array} */ (data),
+ );
+ } else if (isDataView(data)) {
+ abLike = DataViewPrototypeGetBuffer(/** @type {DataView} */ (data));
+ }
+
+ const { err } = op_webgpu_write_buffer(
+ this[_rid],
bufferRid,
bufferOffset,
dataOffset,
size,
- new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ new Uint8Array(abLike),
);
device.pushError(err);
}
@@ -1704,8 +2078,19 @@ class GPUQueue {
selfContext: "this",
resourceContext: "texture",
});
- const { err } = ops.op_webgpu_write_texture(
- device.rid,
+
+ /** @type {ArrayBufferLike} */
+ let abLike = data;
+ if (isTypedArray(data)) {
+ abLike = TypedArrayPrototypeGetBuffer(
+ /** @type {Uint8Array} */ (data),
+ );
+ } else if (isDataView(data)) {
+ abLike = DataViewPrototypeGetBuffer(/** @type {DataView} */ (data));
+ }
+
+ const { err } = op_webgpu_write_texture(
+ this[_rid],
{
texture: textureRid,
mipLevel: destination.mipLevel,
@@ -1716,7 +2101,7 @@ class GPUQueue {
},
dataLayout,
normalizeGPUExtent3D(size),
- new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
+ new Uint8Array(abLike),
);
device.pushError(err);
}
@@ -1900,8 +2285,7 @@ class GPUBuffer {
this[_mapMode] = mode;
this[_state] = "pending";
const promise = PromisePrototypeThen(
- core.opAsync(
- "op_webgpu_buffer_get_map_async",
+ op_webgpu_buffer_get_map_async(
bufferRid,
device.rid,
mode,
@@ -1947,9 +2331,9 @@ class GPUBuffer {
throw new DOMException(`${prefix}: invalid state.`, "OperationError");
}
for (let i = 0; i < mappedRanges.length; ++i) {
- const [buffer, _rid, start] = mappedRanges[i];
+ const { 0: buffer, 1: _rid, 2: start } = mappedRanges[i];
// TODO(lucacasonato): is this logic correct?
- const end = start + buffer.byteLength;
+ const end = start + ArrayBufferPrototypeGetByteLength(buffer);
if (
(start >= offset && start < (offset + rangeSize)) ||
(end >= offset && end < (offset + rangeSize))
@@ -1962,7 +2346,7 @@ class GPUBuffer {
}
const buffer = new ArrayBuffer(rangeSize);
- const { rid } = ops.op_webgpu_buffer_get_mapped_range(
+ const { rid } = op_webgpu_buffer_get_mapped_range(
bufferRid,
offset,
size,
@@ -2016,8 +2400,8 @@ class GPUBuffer {
throw new DOMException(`${prefix}: invalid state.`, "OperationError");
}
for (let i = 0; i < mappedRanges.length; ++i) {
- const [buffer, mappedRid] = mappedRanges[i];
- const { err } = ops.op_webgpu_buffer_unmap(
+ const { 0: buffer, 1: mappedRid } = mappedRanges[i];
+ const { err } = op_webgpu_buffer_unmap(
bufferRid,
mappedRid,
...new SafeArrayIterator(write ? [new Uint8Array(buffer)] : []),
@@ -2135,7 +2519,7 @@ class GPUTexture {
[_device];
/** @type {number | undefined} */
[_rid];
- /** @type {WeakRef[]} */
+ /** @type {SafeWeakRef[]} */
[_views];
/** @type {number} */
@@ -2189,7 +2573,7 @@ class GPUTexture {
);
const device = assertDevice(this, prefix, "this");
const textureRid = assertResource(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_create_texture_view({
+ const { rid, err } = op_webgpu_create_texture_view({
textureRid,
...descriptor,
});
@@ -2200,7 +2584,7 @@ class GPUTexture {
this,
rid,
);
- ArrayPrototypePush(this[_views], new WeakRef(textureView));
+ ArrayPrototypePush(this[_views], new SafeWeakRef(textureView));
return textureView;
}
@@ -2423,7 +2807,10 @@ class GPUBindGroupLayout {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUBindGroupLayoutPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUBindGroupLayoutPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -2471,7 +2858,10 @@ class GPUPipelineLayout {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUPipelineLayoutPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUPipelineLayoutPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -2483,7 +2873,6 @@ class GPUPipelineLayout {
GPUObjectBaseMixin("GPUPipelineLayout", GPUPipelineLayout);
const GPUPipelineLayoutPrototype = GPUPipelineLayout.prototype;
-
/**
* @param {string | null} label
* @param {InnerGPUDevice} device
@@ -2643,8 +3032,8 @@ class GPUComputePipeline {
index = webidl.converters["unsigned long"](index, prefix, "Argument 1");
const device = assertDevice(this, prefix, "this");
const computePipelineRid = assertResource(this, prefix, "this");
- const { rid, label, err } = ops
- .op_webgpu_compute_pipeline_get_bind_group_layout(
+ const { rid, label, err } =
+ op_webgpu_compute_pipeline_get_bind_group_layout(
computePipelineRid,
index,
);
@@ -2663,7 +3052,10 @@ class GPUComputePipeline {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUComputePipelinePrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUComputePipelinePrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -2719,11 +3111,10 @@ class GPURenderPipeline {
index = webidl.converters["unsigned long"](index, prefix, "Argument 1");
const device = assertDevice(this, prefix, "this");
const renderPipelineRid = assertResource(this, prefix, "this");
- const { rid, label, err } = ops
- .op_webgpu_render_pipeline_get_bind_group_layout(
- renderPipelineRid,
- index,
- );
+ const { rid, label, err } = op_webgpu_render_pipeline_get_bind_group_layout(
+ renderPipelineRid,
+ index,
+ );
device.pushError(err);
const bindGroupLayout = createGPUBindGroupLayout(
@@ -2739,7 +3130,10 @@ class GPURenderPipeline {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPURenderPipelinePrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPURenderPipelinePrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -2793,7 +3187,7 @@ class GPUCommandEncoder {
[_device];
/** @type {number | undefined} */
[_rid];
- /** @type {WeakRef[]} */
+ /** @type {SafeWeakRef[]} */
[_encoders];
[_cleanup]() {
@@ -2843,7 +3237,7 @@ class GPUCommandEncoder {
if (descriptor.depthStencilAttachment) {
if (
descriptor.depthStencilAttachment.depthLoadOp === "clear" &&
- !("depthClearValue" in descriptor.depthStencilAttachment)
+ !(ObjectHasOwn(descriptor.depthStencilAttachment, "depthClearValue"))
) {
throw webidl.makeException(
TypeError,
@@ -2903,7 +3297,11 @@ class GPUCommandEncoder {
prefix,
`resolve target texture view for ${context}`,
);
- assertResource(colorAttachment.resolveTarget[_texture], prefix, `texture backing resolve target texture view for ${context}`);
+ assertResource(
+ colorAttachment.resolveTarget[_texture],
+ prefix,
+ `texture backing resolve target texture view for ${context}`,
+ );
assertDeviceMatch(
device,
colorAttachment.resolveTarget[_texture],
@@ -2936,16 +3334,21 @@ class GPUCommandEncoder {
let timestampWrites = null;
if (descriptor.timestampWrites) {
- const querySet = assertResource(descriptor.timestampWrites.querySet, prefix, "querySet");
+ const querySet = assertResource(
+ descriptor.timestampWrites.querySet,
+ prefix,
+ "querySet",
+ );
timestampWrites = {
querySet,
- beginningOfPassWriteIndex: descriptor.timestampWrites.beginningOfPassWriteIndex,
+ beginningOfPassWriteIndex:
+ descriptor.timestampWrites.beginningOfPassWriteIndex,
endOfPassWriteIndex: descriptor.timestampWrites.endOfPassWriteIndex,
};
}
- const { rid } = ops.op_webgpu_command_encoder_begin_render_pass(
+ const { rid } = op_webgpu_command_encoder_begin_render_pass(
commandEncoderRid,
descriptor.label,
colorAttachments,
@@ -2959,7 +3362,7 @@ class GPUCommandEncoder {
this,
rid,
);
- ArrayPrototypePush(this[_encoders], new WeakRef(renderPassEncoder));
+ ArrayPrototypePush(this[_encoders], new SafeWeakRef(renderPassEncoder));
return renderPassEncoder;
}
@@ -2981,16 +3384,21 @@ class GPUCommandEncoder {
let timestampWrites = null;
if (descriptor.timestampWrites) {
- const querySet = assertResource(descriptor.timestampWrites.querySet, prefix, "querySet");
+ const querySet = assertResource(
+ descriptor.timestampWrites.querySet,
+ prefix,
+ "querySet",
+ );
timestampWrites = {
querySet,
- beginningOfPassWriteIndex: descriptor.timestampWrites.beginningOfPassWriteIndex,
+ beginningOfPassWriteIndex:
+ descriptor.timestampWrites.beginningOfPassWriteIndex,
endOfPassWriteIndex: descriptor.timestampWrites.endOfPassWriteIndex,
};
}
- const { rid } = ops.op_webgpu_command_encoder_begin_compute_pass(
+ const { rid } = op_webgpu_command_encoder_begin_compute_pass(
commandEncoderRid,
descriptor.label,
timestampWrites,
@@ -3001,7 +3409,7 @@ class GPUCommandEncoder {
this,
rid,
);
- ArrayPrototypePush(this[_encoders], new WeakRef(computePassEncoder));
+ ArrayPrototypePush(this[_encoders], new SafeWeakRef(computePassEncoder));
return computePassEncoder;
}
@@ -3055,7 +3463,7 @@ class GPUCommandEncoder {
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_buffer(
+ const { err } = op_webgpu_command_encoder_copy_buffer_to_buffer(
commandEncoderRid,
sourceRid,
sourceOffset,
@@ -3086,10 +3494,12 @@ class GPUCommandEncoder {
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
const sourceBufferRid = assertResource(
+ // deno-lint-ignore prefer-primordials
source.buffer,
prefix,
"source in Argument 1",
);
+ // deno-lint-ignore prefer-primordials
assertDeviceMatch(device, source.buffer, {
prefix,
resourceContext: "source in Argument 1",
@@ -3106,7 +3516,7 @@ class GPUCommandEncoder {
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_copy_buffer_to_texture(
+ const { err } = op_webgpu_command_encoder_copy_buffer_to_texture(
commandEncoderRid,
{
...source,
@@ -3159,16 +3569,18 @@ class GPUCommandEncoder {
selfContext: "this",
});
const destinationBufferRid = assertResource(
+ // deno-lint-ignore prefer-primordials
destination.buffer,
prefix,
"buffer in Argument 2",
);
+ // deno-lint-ignore prefer-primordials
assertDeviceMatch(device, destination.buffer, {
prefix,
resourceContext: "buffer in Argument 2",
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_copy_texture_to_buffer(
+ const { err } = op_webgpu_command_encoder_copy_texture_to_buffer(
commandEncoderRid,
{
texture: sourceTextureRid,
@@ -3228,7 +3640,7 @@ class GPUCommandEncoder {
resourceContext: "texture in Argument 2",
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_copy_texture_to_texture(
+ const { err } = op_webgpu_command_encoder_copy_texture_to_texture(
commandEncoderRid,
{
texture: sourceTextureRid,
@@ -3264,7 +3676,7 @@ class GPUCommandEncoder {
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
const bufferRid = assertResource(buffer, prefix, "Argument 1");
- const { err } = ops.op_webgpu_command_encoder_clear_buffer(
+ const { err } = op_webgpu_command_encoder_clear_buffer(
commandEncoderRid,
bufferRid,
offset,
@@ -3283,7 +3695,7 @@ class GPUCommandEncoder {
groupLabel = webidl.converters.USVString(groupLabel, prefix, "Argument 1");
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
- const { err } = ops.op_webgpu_command_encoder_push_debug_group(
+ const { err } = op_webgpu_command_encoder_push_debug_group(
commandEncoderRid,
groupLabel,
);
@@ -3295,7 +3707,7 @@ class GPUCommandEncoder {
const prefix = "Failed to execute 'popDebugGroup' on 'GPUCommandEncoder'";
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
- const { err } = ops.op_webgpu_command_encoder_pop_debug_group(
+ const { err } = op_webgpu_command_encoder_pop_debug_group(
commandEncoderRid,
);
device.pushError(err);
@@ -3316,7 +3728,7 @@ class GPUCommandEncoder {
);
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
- const { err } = ops.op_webgpu_command_encoder_insert_debug_marker(
+ const { err } = op_webgpu_command_encoder_insert_debug_marker(
commandEncoderRid,
markerLabel,
);
@@ -3341,7 +3753,7 @@ class GPUCommandEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_write_timestamp(
+ const { err } = op_webgpu_command_encoder_write_timestamp(
commandEncoderRid,
querySetRid,
queryIndex,
@@ -3393,7 +3805,7 @@ class GPUCommandEncoder {
resourceContext: "Argument 3",
selfContext: "this",
});
- const { err } = ops.op_webgpu_command_encoder_resolve_query_set(
+ const { err } = op_webgpu_command_encoder_resolve_query_set(
commandEncoderRid,
querySetRid,
firstQuery,
@@ -3418,7 +3830,7 @@ class GPUCommandEncoder {
);
const device = assertDevice(this, prefix, "this");
const commandEncoderRid = assertResource(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_command_encoder_finish(
+ const { rid, err } = op_webgpu_command_encoder_finish(
commandEncoderRid,
descriptor.label,
);
@@ -3439,7 +3851,10 @@ class GPUCommandEncoder {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUCommandEncoderPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUCommandEncoderPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -3506,7 +3921,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_set_viewport({
+ op_webgpu_render_pass_set_viewport({
renderPassRid,
x,
y,
@@ -3539,7 +3954,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_set_scissor_rect(
+ op_webgpu_render_pass_set_scissor_rect(
renderPassRid,
x,
y,
@@ -3560,7 +3975,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_set_blend_constant(
+ op_webgpu_render_pass_set_blend_constant(
renderPassRid,
normalizeGPUColor(color),
);
@@ -3582,7 +3997,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_set_stencil_reference(
+ op_webgpu_render_pass_set_stencil_reference(
renderPassRid,
reference,
);
@@ -3600,7 +4015,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_begin_occlusion_query(
+ op_webgpu_render_pass_begin_occlusion_query(
renderPassRid,
queryIndex,
);
@@ -3613,7 +4028,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_end_occlusion_query(renderPassRid);
+ op_webgpu_render_pass_end_occlusion_query(renderPassRid);
}
/**
@@ -3646,7 +4061,7 @@ class GPURenderPassEncoder {
});
return rid;
});
- ops.op_webgpu_render_pass_execute_bundles(renderPassRid, bundleRids);
+ op_webgpu_render_pass_execute_bundles(renderPassRid, bundleRids);
}
end() {
@@ -3663,7 +4078,7 @@ class GPURenderPassEncoder {
"encoder referenced by this",
);
const renderPassRid = assertResource(this, prefix, "this");
- const { err } = ops.op_webgpu_render_pass_end(
+ const { err } = op_webgpu_render_pass_end(
commandEncoderRid,
renderPassRid,
);
@@ -3695,16 +4110,14 @@ class GPURenderPassEncoder {
selfContext: "this",
});
if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
+ TypedArrayPrototypeGetSymbolToStringTag(dynamicOffsetsData) !==
+ "Uint32Array"
) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
- ops.op_webgpu_render_pass_set_bind_group(
+ op_webgpu_render_pass_set_bind_group(
renderPassRid,
index,
bindGroupRid,
@@ -3726,7 +4139,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_push_debug_group(renderPassRid, groupLabel);
+ op_webgpu_render_pass_push_debug_group(renderPassRid, groupLabel);
}
popDebugGroup() {
@@ -3736,7 +4149,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_pop_debug_group(renderPassRid);
+ op_webgpu_render_pass_pop_debug_group(renderPassRid);
}
/**
@@ -3755,7 +4168,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_insert_debug_marker(renderPassRid, markerLabel);
+ op_webgpu_render_pass_insert_debug_marker(renderPassRid, markerLabel);
}
/**
@@ -3783,7 +4196,7 @@ class GPURenderPassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_pass_set_pipeline(renderPassRid, pipelineRid);
+ op_webgpu_render_pass_set_pipeline(renderPassRid, pipelineRid);
}
/**
@@ -3820,7 +4233,7 @@ class GPURenderPassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_pass_set_index_buffer(
+ op_webgpu_render_pass_set_index_buffer(
renderPassRid,
bufferRid,
indexFormat,
@@ -3859,7 +4272,7 @@ class GPURenderPassEncoder {
resourceContext: "Argument 2",
selfContext: "this",
});
- ops.op_webgpu_render_pass_set_vertex_buffer(
+ op_webgpu_render_pass_set_vertex_buffer(
renderPassRid,
slot,
bufferRid,
@@ -3901,7 +4314,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_draw(
+ op_webgpu_render_pass_draw(
renderPassRid,
vertexCount,
instanceCount,
@@ -3947,7 +4360,7 @@ class GPURenderPassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const renderPassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_pass_draw_indexed(
+ op_webgpu_render_pass_draw_indexed(
renderPassRid,
indexCount,
instanceCount,
@@ -3992,7 +4405,7 @@ class GPURenderPassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_pass_draw_indirect(
+ op_webgpu_render_pass_draw_indirect(
renderPassRid,
indirectBufferRid,
indirectOffset,
@@ -4035,7 +4448,7 @@ class GPURenderPassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_pass_draw_indexed_indirect(
+ op_webgpu_render_pass_draw_indexed_indirect(
renderPassRid,
indirectBufferRid,
indirectOffset,
@@ -4046,7 +4459,10 @@ class GPURenderPassEncoder {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPURenderPassEncoderPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPURenderPassEncoderPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -4118,7 +4534,7 @@ class GPUComputePassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_compute_pass_set_pipeline(computePassRid, pipelineRid);
+ op_webgpu_compute_pass_set_pipeline(computePassRid, pipelineRid);
}
/**
@@ -4153,7 +4569,7 @@ class GPUComputePassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const computePassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_compute_pass_dispatch_workgroups(
+ op_webgpu_compute_pass_dispatch_workgroups(
computePassRid,
workgroupCountX,
workgroupCountY,
@@ -4197,7 +4613,7 @@ class GPUComputePassEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_compute_pass_dispatch_workgroups_indirect(
+ op_webgpu_compute_pass_dispatch_workgroups_indirect(
computePassRid,
indirectBufferRid,
indirectOffset,
@@ -4218,7 +4634,7 @@ class GPUComputePassEncoder {
"encoder referenced by this",
);
const computePassRid = assertResource(this, prefix, "this");
- const { err } = ops.op_webgpu_compute_pass_end(
+ const { err } = op_webgpu_compute_pass_end(
commandEncoderRid,
computePassRid,
);
@@ -4251,16 +4667,14 @@ class GPUComputePassEncoder {
selfContext: "this",
});
if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
+ TypedArrayPrototypeGetSymbolToStringTag(dynamicOffsetsData) !==
+ "Uint32Array"
) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
- ops.op_webgpu_compute_pass_set_bind_group(
+ op_webgpu_compute_pass_set_bind_group(
computePassRid,
index,
bindGroupRid,
@@ -4282,7 +4696,7 @@ class GPUComputePassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const computePassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_compute_pass_push_debug_group(computePassRid, groupLabel);
+ op_webgpu_compute_pass_push_debug_group(computePassRid, groupLabel);
}
popDebugGroup() {
@@ -4292,7 +4706,7 @@ class GPUComputePassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const computePassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_compute_pass_pop_debug_group(computePassRid);
+ op_webgpu_compute_pass_pop_debug_group(computePassRid);
}
/**
@@ -4311,7 +4725,7 @@ class GPUComputePassEncoder {
assertDevice(this[_encoder], prefix, "encoder referenced by this");
assertResource(this[_encoder], prefix, "encoder referenced by this");
const computePassRid = assertResource(this, prefix, "this");
- ops.op_webgpu_compute_pass_insert_debug_marker(
+ op_webgpu_compute_pass_insert_debug_marker(
computePassRid,
markerLabel,
);
@@ -4321,7 +4735,10 @@ class GPUComputePassEncoder {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPUComputePassEncoderPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPUComputePassEncoderPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -4430,7 +4847,7 @@ class GPURenderBundleEncoder {
);
const device = assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- const { rid, err } = ops.op_webgpu_render_bundle_encoder_finish(
+ const { rid, err } = op_webgpu_render_bundle_encoder_finish(
renderBundleEncoderRid,
descriptor.label,
);
@@ -4466,16 +4883,14 @@ class GPURenderBundleEncoder {
selfContext: "this",
});
if (
- !(ObjectPrototypeIsPrototypeOf(
- Uint32ArrayPrototype,
- dynamicOffsetsData,
- ))
+ TypedArrayPrototypeGetSymbolToStringTag(dynamicOffsetsData) !==
+ "Uint32Array"
) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
- ops.op_webgpu_render_bundle_encoder_set_bind_group(
+ op_webgpu_render_bundle_encoder_set_bind_group(
renderBundleEncoderRid,
index,
bindGroupRid,
@@ -4496,7 +4911,7 @@ class GPURenderBundleEncoder {
groupLabel = webidl.converters.USVString(groupLabel, prefix, "Argument 1");
assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_bundle_encoder_push_debug_group(
+ op_webgpu_render_bundle_encoder_push_debug_group(
renderBundleEncoderRid,
groupLabel,
);
@@ -4508,7 +4923,7 @@ class GPURenderBundleEncoder {
"Failed to execute 'popDebugGroup' on 'GPURenderBundleEncoder'";
assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_bundle_encoder_pop_debug_group(
+ op_webgpu_render_bundle_encoder_pop_debug_group(
renderBundleEncoderRid,
);
}
@@ -4528,7 +4943,7 @@ class GPURenderBundleEncoder {
);
assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_bundle_encoder_insert_debug_marker(
+ op_webgpu_render_bundle_encoder_insert_debug_marker(
renderBundleEncoderRid,
markerLabel,
);
@@ -4555,7 +4970,7 @@ class GPURenderBundleEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_bundle_encoder_set_pipeline(
+ op_webgpu_render_bundle_encoder_set_pipeline(
renderBundleEncoderRid,
pipelineRid,
);
@@ -4588,7 +5003,7 @@ class GPURenderBundleEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_bundle_encoder_set_index_buffer(
+ op_webgpu_render_bundle_encoder_set_index_buffer(
renderBundleEncoderRid,
bufferRid,
indexFormat,
@@ -4622,7 +5037,7 @@ class GPURenderBundleEncoder {
resourceContext: "Argument 2",
selfContext: "this",
});
- ops.op_webgpu_render_bundle_encoder_set_vertex_buffer(
+ op_webgpu_render_bundle_encoder_set_vertex_buffer(
renderBundleEncoderRid,
slot,
bufferRid,
@@ -4663,7 +5078,7 @@ class GPURenderBundleEncoder {
);
assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_bundle_encoder_draw(
+ op_webgpu_render_bundle_encoder_draw(
renderBundleEncoderRid,
vertexCount,
instanceCount,
@@ -4709,7 +5124,7 @@ class GPURenderBundleEncoder {
);
assertDevice(this, prefix, "this");
const renderBundleEncoderRid = assertResource(this, prefix, "this");
- ops.op_webgpu_render_bundle_encoder_draw_indexed(
+ op_webgpu_render_bundle_encoder_draw_indexed(
renderBundleEncoderRid,
indexCount,
instanceCount,
@@ -4750,7 +5165,7 @@ class GPURenderBundleEncoder {
resourceContext: "Argument 1",
selfContext: "this",
});
- ops.op_webgpu_render_bundle_encoder_draw_indirect(
+ op_webgpu_render_bundle_encoder_draw_indirect(
renderBundleEncoderRid,
indirectBufferRid,
indirectOffset,
@@ -4761,7 +5176,10 @@ class GPURenderBundleEncoder {
return inspect(
createFilteredInspectProxy({
object: this,
- evaluate: ObjectPrototypeIsPrototypeOf(GPURenderBundleEncoderPrototype, this),
+ evaluate: ObjectPrototypeIsPrototypeOf(
+ GPURenderBundleEncoderPrototype,
+ this,
+ ),
keys: [
"label",
],
@@ -4870,12 +5288,12 @@ class GPUQuerySet {
get type() {
webidl.assertBranded(this, GPUQuerySetPrototype);
- this[_type]();
+ return this[_type]();
}
get count() {
webidl.assertBranded(this, GPUQuerySetPrototype);
- this[_count]();
+ return this[_count]();
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
@@ -5014,6 +5432,27 @@ webidl.converters["GPUFeatureName"] = webidl.createEnumConverter(
],
);
+// DICTIONARY: GPUPipelineErrorInit
+webidl.converters["GPUPipelineErrorInit"] = webidl.createDictionaryConverter(
+ "GPUPipelineErrorInit",
+ [
+ {
+ key: "reason",
+ converter: webidl.converters.GPUPipelineErrorReason,
+ required: true,
+ },
+ ],
+);
+
+// ENUM: GPUPipelineErrorReason
+webidl.converters["GPUPipelineErrorReason"] = webidl.createEnumConverter(
+ "GPUPipelineErrorReason",
+ [
+ "validation",
+ "internal",
+ ],
+);
+
// TYPEDEF: GPUSize32
webidl.converters["GPUSize32"] = (V, opts) =>
webidl.converters["unsigned long"](V, { ...opts, enforceRange: true });
@@ -5193,6 +5632,7 @@ webidl.converters["GPUTextureFormat"] = webidl.createEnumConverter(
"bgra8unorm",
"bgra8unorm-srgb",
"rgb9e5ufloat",
+ "rgb10a2uint",
"rgb10a2unorm",
"rg11b10ufloat",
"rg32uint",
@@ -5608,6 +6048,8 @@ webidl.converters["GPUStorageTextureAccess"] = webidl.createEnumConverter(
"GPUStorageTextureAccess",
[
"write-only",
+ "read-only",
+ "read-write",
],
);
@@ -5867,7 +6309,6 @@ const dictMembersGPUProgrammableStage = [
{
key: "entryPoint",
converter: webidl.converters["USVString"],
- required: true,
},
{
key: "constants",
@@ -6910,7 +7351,7 @@ webidl.converters["GPUErrorFilter"] = webidl.createEnumConverter(
[
"out-of-memory",
"validation",
- "internal"
+ "internal",
],
);
@@ -6957,6 +7398,78 @@ webidl.converters["GPUSignedOffset32"] = (V, opts) =>
// TYPEDEF: GPUFlagsConstant
webidl.converters["GPUFlagsConstant"] = webidl.converters["unsigned long"];
+// ENUM: GPUCanvasAlphaMode
+webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter(
+ "GPUCanvasAlphaMode",
+ [
+ "opaque",
+ "premultiplied",
+ ],
+);
+
+// NON-SPEC: ENUM: GPUPresentMode
+webidl.converters["GPUPresentMode"] = webidl.createEnumConverter(
+ "GPUPresentMode",
+ [
+ "autoVsync",
+ "autoNoVsync",
+ "fifo",
+ "fifoRelaxed",
+ "immediate",
+ "mailbox",
+ ],
+);
+
+// DICT: GPUCanvasConfiguration
+const dictMembersGPUCanvasConfiguration = [
+ { key: "device", converter: webidl.converters.GPUDevice, required: true },
+ {
+ key: "format",
+ converter: webidl.converters.GPUTextureFormat,
+ required: true,
+ },
+ {
+ key: "usage",
+ converter: webidl.converters["GPUTextureUsageFlags"],
+ defaultValue: GPUTextureUsage.RENDER_ATTACHMENT,
+ },
+ {
+ key: "alphaMode",
+ converter: webidl.converters["GPUCanvasAlphaMode"],
+ defaultValue: "opaque",
+ },
+
+ // Extended from spec
+ {
+ key: "presentMode",
+ converter: webidl.converters["GPUPresentMode"],
+ },
+ {
+ key: "width",
+ converter: webidl.converters["long"],
+ required: true,
+ },
+ {
+ key: "height",
+ converter: webidl.converters["long"],
+ required: true,
+ },
+ {
+ key: "viewFormats",
+ converter: webidl.createSequenceConverter(
+ webidl.converters["GPUTextureFormat"],
+ ),
+ get defaultValue() {
+ return [];
+ },
+ },
+];
+webidl.converters["GPUCanvasConfiguration"] = webidl
+ .createDictionaryConverter(
+ "GPUCanvasConfiguration",
+ dictMembersGPUCanvasConfiguration,
+ );
+
const gpu = webidl.createBranded(GPU);
export {
_device,
@@ -6978,6 +7491,7 @@ export {
GPUDevice,
GPUDeviceLostInfo,
GPUError,
+ GPUInternalError,
GPUMapMode,
GPUOutOfMemoryError,
GPUPipelineLayout,
@@ -6995,5 +7509,6 @@ export {
GPUTexture,
GPUTextureUsage,
GPUTextureView,
+ GPUUncapturedErrorEvent,
GPUValidationError,
};
diff --git a/deno_webgpu/02_surface.js b/deno_webgpu/02_surface.js
index d16f5c245..f35f745af 100644
--- a/deno_webgpu/02_surface.js
+++ b/deno_webgpu/02_surface.js
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// @ts-check
///
@@ -6,27 +6,32 @@
///
///
-const core = globalThis.Deno.core;
-const ops = core.ops;
-import * as webidl from "ext:deno_webidl/00_webidl.js";
-const primordials = globalThis.__bootstrap.primordials;
-const { Symbol } = primordials;
+import { primordials } from "ext:core/mod.js";
import {
- _device,
- assertDevice,
- createGPUTexture,
- GPUTextureUsage,
-} from "ext:deno_webgpu/01_webgpu.js";
+ op_webgpu_surface_configure,
+ op_webgpu_surface_create,
+ op_webgpu_surface_get_current_texture,
+ op_webgpu_surface_present,
+} from "ext:core/ops";
+const {
+ ObjectPrototypeIsPrototypeOf,
+ Symbol,
+ SymbolFor,
+ TypeError,
+} = primordials;
+
+import * as webidl from "ext:deno_webidl/00_webidl.js";
+import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
+import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
const _surfaceRid = Symbol("[[surfaceRid]]");
const _configuration = Symbol("[[configuration]]");
const _canvas = Symbol("[[canvas]]");
const _currentTexture = Symbol("[[currentTexture]]");
+const _present = Symbol("[[present]]");
class GPUCanvasContext {
/** @type {number} */
[_surfaceRid];
- /** @type {InnerGPUDevice} */
- [_device];
[_configuration];
[_canvas];
/** @type {GPUTexture | undefined} */
@@ -50,11 +55,15 @@ class GPUCanvasContext {
context: "Argument 1",
});
+ const { _device, assertDevice } = loadWebGPU();
this[_device] = configuration.device[_device];
this[_configuration] = configuration;
- const device = assertDevice(this, { prefix, context: "configuration.device" });
+ const device = assertDevice(this, {
+ prefix,
+ context: "configuration.device",
+ });
- const { err } = ops.op_webgpu_surface_configure({
+ const { err } = op_webgpu_surface_configure({
surfaceRid: this[_surfaceRid],
deviceRid: device.rid,
format: configuration.format,
@@ -69,6 +78,8 @@ class GPUCanvasContext {
}
unconfigure() {
+ const { _device } = loadWebGPU();
+
webidl.assertBranded(this, GPUCanvasContextPrototype);
this[_configuration] = null;
@@ -77,11 +88,13 @@ class GPUCanvasContext {
getCurrentTexture() {
webidl.assertBranded(this, GPUCanvasContextPrototype);
- const prefix = "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'";
+ const prefix =
+ "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'";
if (this[_configuration] === null) {
throw new DOMException("context is not configured.", "InvalidStateError");
}
+ const { createGPUTexture, assertDevice } = loadWebGPU();
const device = assertDevice(this, { prefix, context: "this" });
@@ -89,7 +102,10 @@ class GPUCanvasContext {
return this[_currentTexture];
}
- const { rid } = ops.op_webgpu_surface_get_current_texture(device.rid, this[_surfaceRid]);
+ const { rid } = op_webgpu_surface_get_current_texture(
+ device.rid,
+ this[_surfaceRid],
+ );
const texture = createGPUTexture(
{
@@ -112,102 +128,66 @@ class GPUCanvasContext {
return texture;
}
- // Extended from spec. Required to present the texture; browser don't need this.
- present() {
+ // Required to present the texture; browser don't need this.
+ [_present]() {
+ const { assertDevice } = loadWebGPU();
+
webidl.assertBranded(this, GPUCanvasContextPrototype);
const prefix = "Failed to execute 'present' on 'GPUCanvasContext'";
- const device = assertDevice(this[_currentTexture], { prefix, context: "this" });
- ops.op_webgpu_surface_present(device.rid, this[_surfaceRid]);
+ const device = assertDevice(this[_currentTexture], {
+ prefix,
+ context: "this",
+ });
+ op_webgpu_surface_present(device.rid, this[_surfaceRid]);
this[_currentTexture].destroy();
this[_currentTexture] = undefined;
}
+
+ [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
+ return inspect(
+ createFilteredInspectProxy({
+ object: this,
+ evaluate: ObjectPrototypeIsPrototypeOf(GPUCanvasContextPrototype, this),
+ keys: [
+ "canvas",
+ ],
+ }),
+ inspectOptions,
+ );
+ }
}
const GPUCanvasContextPrototype = GPUCanvasContext.prototype;
function createCanvasContext(options) {
+ // lazy load webgpu if needed
const canvasContext = webidl.createBranded(GPUCanvasContext);
canvasContext[_surfaceRid] = options.surfaceRid;
canvasContext[_canvas] = options.canvas;
return canvasContext;
}
-// Converters
+// External webgpu surfaces
-// ENUM: GPUCanvasAlphaMode
-webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter(
- "GPUCanvasAlphaMode",
- [
- "opaque",
- "premultiplied",
- ],
-);
+// TODO(@littledivy): This will extend `OffscreenCanvas` when we add it.
+class UnsafeWindowSurface {
+ #ctx;
+ #surfaceRid;
-// NON-SPEC: ENUM: GPUPresentMode
-webidl.converters["GPUPresentMode"] = webidl.createEnumConverter(
- "GPUPresentMode",
- [
- "autoVsync",
- "autoNoVsync",
- "fifo",
- "fifoRelaxed",
- "immediate",
- "mailbox",
- ],
-);
+ constructor(system, win, display) {
+ this.#surfaceRid = op_webgpu_surface_create(system, win, display);
+ }
-// DICT: GPUCanvasConfiguration
-const dictMembersGPUCanvasConfiguration = [
- { key: "device", converter: webidl.converters.GPUDevice, required: true },
- {
- key: "format",
- converter: webidl.converters.GPUTextureFormat,
- required: true,
- },
- {
- key: "usage",
- converter: webidl.converters["GPUTextureUsageFlags"],
- defaultValue: GPUTextureUsage.RENDER_ATTACHMENT,
- },
- {
- key: "alphaMode",
- converter: webidl.converters["GPUCanvasAlphaMode"],
- defaultValue: "opaque",
- },
+ getContext(context) {
+ if (context !== "webgpu") {
+ throw new TypeError("Only 'webgpu' context is supported.");
+ }
+ this.#ctx = createCanvasContext({ surfaceRid: this.#surfaceRid });
+ return this.#ctx;
+ }
- // Extended from spec
- {
- key: "presentMode",
- converter: webidl.converters["GPUPresentMode"],
- },
- {
- key: "width",
- converter: webidl.converters["long"],
- required: true,
- },
- {
- key: "height",
- converter: webidl.converters["long"],
- required: true,
- },
- {
- key: "viewFormats",
- converter: webidl.createSequenceConverter(
- webidl.converters["GPUTextureFormat"],
- ),
- get defaultValue() {
- return [];
- },
- },
-];
-webidl.converters["GPUCanvasConfiguration"] = webidl
- .createDictionaryConverter(
- "GPUCanvasConfiguration",
- dictMembersGPUCanvasConfiguration,
- );
+ present() {
+ this.#ctx[_present]();
+ }
+}
-
-window.__bootstrap.webgpu = {
- ...window.__bootstrap.webgpu,
- GPUCanvasContext,
- createCanvasContext,
-};
+export { GPUCanvasContext, UnsafeWindowSurface };
diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml
index 9f6d96a95..586eb90c8 100644
--- a/deno_webgpu/Cargo.toml
+++ b/deno_webgpu/Cargo.toml
@@ -1,8 +1,8 @@
-# Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
[package]
name = "deno_webgpu"
-version = "0.85.0"
+version = "0.110.0"
authors = ["the Deno authors"]
edition.workspace = true
license = "MIT"
@@ -13,9 +13,6 @@ description = "WebGPU implementation for Deno"
[lib]
path = "lib.rs"
-[features]
-surface = ["wgpu-core/raw-window-handle", "dep:raw-window-handle"]
-
# We make all dependencies conditional on not being wasm,
# so the whole workspace can built as wasm.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -23,11 +20,11 @@ deno_core.workspace = true
serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = ["full"] }
wgpu-types = { workspace = true, features = ["serde"] }
-raw-window-handle = { workspace = true, optional = true }
+raw-window-handle = { workspace = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core]
workspace = true
-features = ["trace", "replay", "serde", "strict_asserts", "wgsl", "gles"]
+features = ["raw-window-handle", "trace", "replay", "serde", "strict_asserts", "wgsl", "gles"]
# We want the wgpu-core Metal backend on macOS and iOS.
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgpu-core]
diff --git a/deno_webgpu/LICENSE.md b/deno_webgpu/LICENSE.md
index aec557f3a..56753af36 100644
--- a/deno_webgpu/LICENSE.md
+++ b/deno_webgpu/LICENSE.md
@@ -1,6 +1,6 @@
MIT License
-Copyright 2018-2023 the Deno authors
+Copyright 2018-2024 the Deno authors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/deno_webgpu/README.md b/deno_webgpu/README.md
index 1cf031cda..c419bfc60 100644
--- a/deno_webgpu/README.md
+++ b/deno_webgpu/README.md
@@ -2,8 +2,8 @@
This op crate implements the WebGPU API as defined in
https://gpuweb.github.io/gpuweb/ in Deno. The implementation targets the spec
-draft as of February 22, 2021. The spec is still very much in flux. This op
-crate tries to stay up to date with the spec, but is constrained by the features
+draft as of March 31, 2024. The spec is still very much in flux. This extension
+tries to stay up to date with the spec, but is constrained by the features
implemented in our GPU backend library [wgpu](https://github.com/gfx-rs/wgpu).
The spec is still very bare bones, and is still missing many details. As the
diff --git a/deno_webgpu/binding.rs b/deno_webgpu/binding.rs
index c0b9b5836..0efeb6716 100644
--- a/deno_webgpu/binding.rs
+++ b/deno_webgpu/binding.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
@@ -112,25 +112,11 @@ impl From for wgpu_types::TextureSampleType {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuStorageTextureBindingLayout {
- access: GpuStorageTextureAccess,
+ access: wgpu_types::StorageTextureAccess,
format: wgpu_types::TextureFormat,
view_dimension: wgpu_types::TextureViewDimension,
}
-#[derive(Deserialize)]
-#[serde(rename_all = "kebab-case")]
-enum GpuStorageTextureAccess {
- WriteOnly,
-}
-
-impl From for wgpu_types::StorageTextureAccess {
- fn from(access: GpuStorageTextureAccess) -> Self {
- match access {
- GpuStorageTextureAccess::WriteOnly => wgpu_types::StorageTextureAccess::WriteOnly,
- }
- }
-}
-
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuBindGroupLayoutEntry {
@@ -165,7 +151,7 @@ impl From for wgpu_types::BindingType {
},
GpuBindingType::StorageTexture(storage_texture) => {
wgpu_types::BindingType::StorageTexture {
- access: storage_texture.access.into(),
+ access: storage_texture.access,
format: storage_texture.format,
view_dimension: storage_texture.view_dimension,
}
diff --git a/deno_webgpu/buffer.rs b/deno_webgpu/buffer.rs
index 9a2ebb003..5b7d20880 100644
--- a/deno_webgpu/buffer.rs
+++ b/deno_webgpu/buffer.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;
@@ -163,6 +163,7 @@ pub fn op_webgpu_buffer_get_mapped_range(
))
.map_err(|e| DomExceptionOperationError::new(&e.to_string()))?;
+ // SAFETY: guarantee to be safe from wgpu
let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) };
buf.copy_from_slice(slice);
@@ -189,6 +190,7 @@ pub fn op_webgpu_buffer_unmap(
let buffer = buffer_resource.1;
if let Some(buf) = buf {
+ // SAFETY: guarantee to be safe from wgpu
let slice = unsafe { std::slice::from_raw_parts_mut(mapped_resource.0, mapped_resource.1) };
slice.copy_from_slice(buf);
}
diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs
index d50359931..dfe5ccf49 100644
--- a/deno_webgpu/bundle.rs
+++ b/deno_webgpu/bundle.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;
diff --git a/deno_webgpu/byow.rs b/deno_webgpu/byow.rs
new file mode 100644
index 000000000..3042f46ee
--- /dev/null
+++ b/deno_webgpu/byow.rs
@@ -0,0 +1,115 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::error::type_error;
+use deno_core::error::AnyError;
+use deno_core::op2;
+use deno_core::OpState;
+use deno_core::ResourceId;
+use std::ffi::c_void;
+use std::ptr::NonNull;
+
+use crate::surface::WebGpuSurface;
+
+#[op2(fast)]
+#[smi]
+pub fn op_webgpu_surface_create(
+ state: &mut OpState,
+ #[string] system: &str,
+ p1: *const c_void,
+ p2: *const c_void,
+) -> Result {
+ let instance = state.borrow::();
+ // Security note:
+ //
+ // The `p1` and `p2` parameters are pointers to platform-specific window
+ // handles.
+ //
+ // The code below works under the assumption that:
+ //
+ // - handles can only be created by the FFI interface which
+ // enforces --allow-ffi.
+ //
+ // - `*const c_void` deserizalizes null and v8::External.
+ //
+ // - Only FFI can export v8::External to user code.
+ if p1.is_null() {
+ return Err(type_error("Invalid parameters"));
+ }
+
+ let (win_handle, display_handle) = raw_window(system, p1, p2)?;
+ let surface = unsafe { instance.instance_create_surface(display_handle, win_handle, None)? };
+
+ let rid = state
+ .resource_table
+ .add(WebGpuSurface(instance.clone(), surface));
+ Ok(rid)
+}
+
+type RawHandles = (
+ raw_window_handle::RawWindowHandle,
+ raw_window_handle::RawDisplayHandle,
+);
+
+#[cfg(target_os = "macos")]
+fn raw_window(
+ system: &str,
+ _ns_window: *const c_void,
+ ns_view: *const c_void,
+) -> Result {
+ if system != "cocoa" {
+ return Err(type_error("Invalid system on macOS"));
+ }
+
+ let win_handle =
+ raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle::new(
+ NonNull::new(ns_view as *mut c_void).ok_or(type_error("ns_view is null"))?,
+ ));
+
+ let display_handle =
+ raw_window_handle::RawDisplayHandle::AppKit(raw_window_handle::AppKitDisplayHandle::new());
+ Ok((win_handle, display_handle))
+}
+
+#[cfg(target_os = "windows")]
+fn raw_window(
+ system: &str,
+ window: *const c_void,
+ hinstance: *const c_void,
+) -> Result {
+ use raw_window_handle::WindowsDisplayHandle;
+ if system != "win32" {
+ return Err(type_error("Invalid system on Windows"));
+ }
+
+ let win_handle = {
+ let mut handle = raw_window_handle::Win32WindowHandle::new();
+ handle.hwnd = window as *mut c_void;
+ handle.hinstance = hinstance as *mut c_void;
+
+ raw_window_handle::RawWindowHandle::Win32(handle)
+ };
+
+ let display_handle = raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::new());
+ Ok((win_handle, display_handle))
+}
+
+#[cfg(target_os = "linux")]
+fn raw_window(
+ system: &str,
+ window: *const c_void,
+ display: *const c_void,
+) -> Result {
+ if system != "x11" {
+ return Err(type_error("Invalid system on Linux"));
+ }
+
+ let win_handle = raw_window_handle::RawWindowHandle::Xlib(
+ raw_window_handle::XlibWindowHandle::new(window as *mut c_void as _),
+ );
+
+ let display_handle = raw_window_handle::RawDisplayHandle::Xlib(
+ raw_window_handle::XlibDisplayHandle::new(NonNull::new(display as *mut c_void), 0),
+ );
+
+ Ok((win_handle, display_handle))
+}
diff --git a/deno_webgpu/command_encoder.rs b/deno_webgpu/command_encoder.rs
index 679ac3cab..20dfe0db0 100644
--- a/deno_webgpu/command_encoder.rs
+++ b/deno_webgpu/command_encoder.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::WebGpuQuerySet;
use deno_core::error::AnyError;
diff --git a/deno_webgpu/compute_pass.rs b/deno_webgpu/compute_pass.rs
index e1c9e2919..65ac93d63 100644
--- a/deno_webgpu/compute_pass.rs
+++ b/deno_webgpu/compute_pass.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
diff --git a/deno_webgpu/error.rs b/deno_webgpu/error.rs
index 6c509a80d..bb8200899 100644
--- a/deno_webgpu/error.rs
+++ b/deno_webgpu/error.rs
@@ -1,4 +1,5 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
use deno_core::error::AnyError;
use deno_core::ResourceId;
use serde::Serialize;
@@ -23,7 +24,6 @@ use wgpu_core::device::DeviceError;
use wgpu_core::pipeline::CreateComputePipelineError;
use wgpu_core::pipeline::CreateRenderPipelineError;
use wgpu_core::pipeline::CreateShaderModuleError;
-#[cfg(feature = "surface")]
use wgpu_core::present::ConfigureSurfaceError;
use wgpu_core::resource::BufferAccessError;
use wgpu_core::resource::CreateBufferError;
@@ -87,6 +87,7 @@ pub enum WebGpuError {
Lost,
OutOfMemory,
Validation(String),
+ Internal,
}
impl From for WebGpuError {
@@ -277,7 +278,6 @@ impl From for WebGpuError {
}
}
-#[cfg(feature = "surface")]
impl From for WebGpuError {
fn from(err: ConfigureSurfaceError) -> Self {
WebGpuError::Validation(fmt_err(&err))
diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs
index 40e76e0fa..453d4ea7e 100644
--- a/deno_webgpu/lib.rs
+++ b/deno_webgpu/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
#![cfg(not(target_arch = "wasm32"))]
#![warn(unsafe_op_in_unsafe_fn)]
@@ -19,6 +19,8 @@ pub use wgpu_types;
use error::DomExceptionOperationError;
use error::WebGpuResult;
+pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
+
#[macro_use]
mod macros {
macro_rules! gfx_select {
@@ -71,6 +73,7 @@ mod macros {
pub mod binding;
pub mod buffer;
pub mod bundle;
+pub mod byow;
pub mod command_encoder;
pub mod compute_pass;
pub mod error;
@@ -79,23 +82,9 @@ pub mod queue;
pub mod render_pass;
pub mod sampler;
pub mod shader;
-#[cfg(feature = "surface")]
pub mod surface;
pub mod texture;
-pub struct Unstable(pub bool);
-
-fn check_unstable(state: &OpState, api_name: &str) {
- let unstable = state.borrow::();
- if !unstable.0 {
- eprintln!(
- "Unstable API '{}'. The --unstable flag must be provided.",
- api_name
- );
- std::process::exit(70);
- }
-}
-
pub type Instance = std::sync::Arc;
struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId);
@@ -224,12 +213,15 @@ deno_core::extension!(
queue::op_webgpu_write_texture,
// shader
shader::op_webgpu_create_shader_module,
+ // surface
+ surface::op_webgpu_surface_configure,
+ surface::op_webgpu_surface_get_current_texture,
+ surface::op_webgpu_surface_present,
+ // byow
+ byow::op_webgpu_surface_create,
],
- esm = ["01_webgpu.js"],
- options = { unstable: bool },
- state = |state, options| {
- state.put(Unstable(options.unstable));
- },
+ esm = ["00_init.js", "02_surface.js"],
+ lazy_loaded_esm = ["01_webgpu.js"],
);
fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
@@ -377,29 +369,45 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
#[derive(Serialize)]
#[serde(untagged)]
-pub enum GpuAdapterDeviceOrErr {
+pub enum GpuAdapterResOrErr {
Error { err: String },
- Features(GpuAdapterDevice),
+ Features(GpuAdapterRes),
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct GpuAdapterDevice {
+pub struct GpuAdapterRes {
rid: ResourceId,
limits: wgpu_types::Limits,
features: Vec<&'static str>,
is_software: bool,
}
-#[op2(async)]
+#[derive(Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct GpuDeviceRes {
+ rid: ResourceId,
+ queue_rid: ResourceId,
+ limits: wgpu_types::Limits,
+ features: Vec<&'static str>,
+ is_software: bool,
+}
+
+#[op2]
#[serde]
-pub async fn op_webgpu_request_adapter(
+pub fn op_webgpu_request_adapter(
state: Rc>,
#[serde] power_preference: Option,
force_fallback_adapter: bool,
-) -> Result {
+) -> Result {
let mut state = state.borrow_mut();
- check_unstable(&state, "navigator.gpu.requestAdapter");
+
+ // TODO(bartlomieju): replace with `state.feature_checker.check_or_exit`
+ // once we phase out `check_or_exit_with_legacy_fallback`
+ state
+ .feature_checker
+ .check_or_exit_with_legacy_fallback(UNSTABLE_FEATURE_NAME, "navigator.gpu.requestAdapter");
+
let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|_| wgpu_types::Backends::all(),
|s| wgpu_core::instance::parse_backends_from_comma_list(&s),
@@ -432,7 +440,7 @@ pub async fn op_webgpu_request_adapter(
let adapter = match res {
Ok(adapter) => adapter,
Err(err) => {
- return Ok(GpuAdapterDeviceOrErr::Error {
+ return Ok(GpuAdapterResOrErr::Error {
err: err.to_string(),
})
}
@@ -445,7 +453,7 @@ pub async fn op_webgpu_request_adapter(
let rid = state.resource_table.add(WebGpuAdapter(instance, adapter));
- Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice {
+ Ok(GpuAdapterResOrErr::Features(GpuAdapterRes {
rid,
features,
limits: adapter_limits,
@@ -649,15 +657,15 @@ impl From for wgpu_types::Features {
}
}
-#[op2(async)]
+#[op2]
#[serde]
-pub async fn op_webgpu_request_device(
+pub fn op_webgpu_request_device(
state: Rc>,
#[smi] adapter_rid: ResourceId,
#[string] label: String,
#[serde] required_features: GpuRequiredFeatures,
#[serde] required_limits: Option,
-) -> Result {
+) -> Result {
let mut state = state.borrow_mut();
let adapter_resource = state.resource_table.get::(adapter_rid)?;
let adapter = adapter_resource.1;
@@ -669,7 +677,7 @@ pub async fn op_webgpu_request_device(
required_limits: required_limits.unwrap_or_default(),
};
- let (device, _queue, maybe_err) = gfx_select!(adapter => instance.adapter_request_device(
+ let (device, queue, maybe_err) = gfx_select!(adapter => instance.adapter_request_device(
adapter,
&descriptor,
std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new),
@@ -685,10 +693,15 @@ pub async fn op_webgpu_request_device(
let limits = gfx_select!(device => instance.device_limits(device))?;
let instance = instance.clone();
+ let instance2 = instance.clone();
let rid = state.resource_table.add(WebGpuDevice(instance, device));
+ let queue_rid = state
+ .resource_table
+ .add(queue::WebGpuQueue(instance2, queue));
- Ok(GpuAdapterDevice {
+ Ok(GpuDeviceRes {
rid,
+ queue_rid,
features,
limits,
// TODO(lucacasonato): report correctly from wgpu
@@ -705,9 +718,9 @@ pub struct GPUAdapterInfo {
description: String,
}
-#[op2(async)]
+#[op2]
#[serde]
-pub async fn op_webgpu_request_adapter_info(
+pub fn op_webgpu_request_adapter_info(
state: Rc>,
#[smi] adapter_rid: ResourceId,
) -> Result {
diff --git a/deno_webgpu/pipeline.rs b/deno_webgpu/pipeline.rs
index dcd4151eb..ab7cf42e7 100644
--- a/deno_webgpu/pipeline.rs
+++ b/deno_webgpu/pipeline.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
@@ -74,7 +74,7 @@ pub enum GPUPipelineLayoutOrGPUAutoLayoutMode {
#[serde(rename_all = "camelCase")]
pub struct GpuProgrammableStage {
module: ResourceId,
- entry_point: String,
+ entry_point: Option,
// constants: HashMap
}
@@ -110,7 +110,7 @@ pub fn op_webgpu_create_compute_pipeline(
layout: pipeline_layout,
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: compute_shader_module_resource.1,
- entry_point: Some(Cow::from(compute.entry_point)),
+ entry_point: compute.entry_point.map(Cow::from),
// TODO(lucacasonato): support args.compute.constants
},
};
diff --git a/deno_webgpu/queue.rs b/deno_webgpu/queue.rs
index 61b56c758..264013445 100644
--- a/deno_webgpu/queue.rs
+++ b/deno_webgpu/queue.rs
@@ -1,16 +1,28 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use crate::command_encoder::WebGpuCommandBuffer;
+use crate::Instance;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use serde::Deserialize;
+use std::borrow::Cow;
+use std::rc::Rc;
use super::error::WebGpuResult;
-type WebGpuQueue = super::WebGpuDevice;
+pub struct WebGpuQueue(pub Instance, pub wgpu_core::id::QueueId);
+impl Resource for WebGpuQueue {
+ fn name(&self) -> Cow {
+ "webGPUQueue".into()
+ }
+
+ fn close(self: Rc) {
+ gfx_select!(self.1 => self.0.queue_drop(self.1));
+ }
+}
#[op2]
#[serde]
@@ -19,7 +31,7 @@ pub fn op_webgpu_queue_submit(
#[smi] queue_rid: ResourceId,
#[serde] command_buffers: Vec,
) -> Result {
- let instance = state.borrow::();
+ let instance = state.borrow::();
let queue_resource = state.resource_table.get::(queue_rid)?;
let queue = queue_resource.1;
@@ -32,7 +44,7 @@ pub fn op_webgpu_queue_submit(
})
.collect::, AnyError>>()?;
- let maybe_err = gfx_select!(queue => instance.queue_submit(queue.transmute(), &ids)).err();
+ let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err();
for rid in command_buffers {
let resource = state.resource_table.take::(rid)?;
@@ -71,7 +83,7 @@ pub fn op_webgpu_write_buffer(
#[number] size: Option,
#[buffer] buf: &[u8],
) -> Result {
- let instance = state.borrow::();
+ let instance = state.borrow::();
let buffer_resource = state
.resource_table
.get::(buffer)?;
@@ -84,7 +96,7 @@ pub fn op_webgpu_write_buffer(
None => &buf[data_offset..],
};
let maybe_err = gfx_select!(queue => instance.queue_write_buffer(
- queue.transmute(),
+ queue,
buffer,
buffer_offset,
data
@@ -104,7 +116,7 @@ pub fn op_webgpu_write_texture(
#[serde] size: wgpu_types::Extent3d,
#[buffer] buf: &[u8],
) -> Result {
- let instance = state.borrow::();
+ let instance = state.borrow::();
let texture_resource = state
.resource_table
.get::(destination.texture)?;
@@ -120,7 +132,7 @@ pub fn op_webgpu_write_texture(
let data_layout = data_layout.into();
gfx_ok!(queue => instance.queue_write_texture(
- queue.transmute(),
+ queue,
&destination,
buf,
&data_layout,
diff --git a/deno_webgpu/render_pass.rs b/deno_webgpu/render_pass.rs
index 47b98c91f..11b2f2286 100644
--- a/deno_webgpu/render_pass.rs
+++ b/deno_webgpu/render_pass.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;
diff --git a/deno_webgpu/sampler.rs b/deno_webgpu/sampler.rs
index 0d65d727a..822c4bda1 100644
--- a/deno_webgpu/sampler.rs
+++ b/deno_webgpu/sampler.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
diff --git a/deno_webgpu/shader.rs b/deno_webgpu/shader.rs
index f4604a04a..17cde4393 100644
--- a/deno_webgpu/shader.rs
+++ b/deno_webgpu/shader.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
diff --git a/deno_webgpu/surface.rs b/deno_webgpu/surface.rs
index 4d8412999..a8b984eef 100644
--- a/deno_webgpu/surface.rs
+++ b/deno_webgpu/surface.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use super::WebGpuResult;
use deno_core::error::AnyError;
@@ -11,21 +11,6 @@ use std::borrow::Cow;
use std::rc::Rc;
use wgpu_types::SurfaceStatus;
-deno_core::extension!(
- deno_webgpu_surface,
- deps = [deno_webidl, deno_web, deno_webgpu],
- ops = [
- op_webgpu_surface_configure,
- op_webgpu_surface_get_current_texture,
- op_webgpu_surface_present,
- ],
- esm = ["02_surface.js"],
- options = { unstable: bool },
- state = |state, options| {
- state.put(super::Unstable(options.unstable));
- },
-);
-
pub struct WebGpuSurface(pub crate::Instance, pub wgpu_core::id::SurfaceId);
impl Resource for WebGpuSurface {
fn name(&self) -> Cow {
diff --git a/deno_webgpu/texture.rs b/deno_webgpu/texture.rs
index a9be7b991..2dc1a740a 100644
--- a/deno_webgpu/texture.rs
+++ b/deno_webgpu/texture.rs
@@ -1,4 +1,4 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::op2;
diff --git a/deno_webgpu/webgpu.idl b/deno_webgpu/webgpu.idl
index 46d587874..bd709d117 100644
--- a/deno_webgpu/webgpu.idl
+++ b/deno_webgpu/webgpu.idl
@@ -6,7 +6,7 @@ dictionary GPUObjectDescriptorBase {
USVString label = "";
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUSupportedLimits {
readonly attribute unsigned long maxTextureDimension1D;
readonly attribute unsigned long maxTextureDimension2D;
@@ -30,6 +30,8 @@ interface GPUSupportedLimits {
readonly attribute unsigned long maxVertexAttributes;
readonly attribute unsigned long maxVertexBufferArrayStride;
readonly attribute unsigned long maxInterStageShaderComponents;
+ readonly attribute unsigned long maxColorAttachments;
+ readonly attribute unsigned long maxColorAttachmentBytesPerSample;
readonly attribute unsigned long maxComputeWorkgroupStorageSize;
readonly attribute unsigned long maxComputeInvocationsPerWorkgroup;
readonly attribute unsigned long maxComputeWorkgroupSizeX;
@@ -38,12 +40,12 @@ interface GPUSupportedLimits {
readonly attribute unsigned long maxComputeWorkgroupsPerDimension;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUSupportedFeatures {
readonly setlike;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUAdapterInfo {
readonly attribute DOMString vendor;
readonly attribute DOMString architecture;
@@ -57,9 +59,10 @@ interface mixin NavigatorGPU {
Navigator includes NavigatorGPU;
WorkerNavigator includes NavigatorGPU;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPU {
Promise requestAdapter(optional GPURequestAdapterOptions options = {});
+ GPUTextureFormat getPreferredCanvasFormat();
};
dictionary GPURequestAdapterOptions {
@@ -72,14 +75,14 @@ enum GPUPowerPreference {
"high-performance",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUAdapter {
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
readonly attribute boolean isFallbackAdapter;
Promise requestDevice(optional GPUDeviceDescriptor descriptor = {});
- Promise requestAdapterInfo(optional sequence unmaskHints = []);
+ Promise requestAdapterInfo();
};
dictionary GPUDeviceDescriptor
@@ -141,7 +144,7 @@ enum GPUFeatureName {
"shader-early-depth-test",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUDevice : EventTarget {
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
@@ -171,7 +174,7 @@ interface GPUDevice : EventTarget {
};
GPUDevice includes GPUObjectBase;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUBuffer {
readonly attribute GPUSize64Out size;
readonly attribute GPUFlagsConstant usage;
@@ -200,7 +203,7 @@ dictionary GPUBufferDescriptor
};
typedef [EnforceRange] unsigned long GPUBufferUsageFlags;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
namespace GPUBufferUsage {
const GPUFlagsConstant MAP_READ = 0x0001;
const GPUFlagsConstant MAP_WRITE = 0x0002;
@@ -215,13 +218,13 @@ namespace GPUBufferUsage {
};
typedef [EnforceRange] unsigned long GPUMapModeFlags;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
namespace GPUMapMode {
const GPUFlagsConstant READ = 0x0001;
const GPUFlagsConstant WRITE = 0x0002;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUTexture {
GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});
@@ -256,7 +259,7 @@ enum GPUTextureDimension {
};
typedef [EnforceRange] unsigned long GPUTextureUsageFlags;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
namespace GPUTextureUsage {
const GPUFlagsConstant COPY_SRC = 0x01;
const GPUFlagsConstant COPY_DST = 0x02;
@@ -265,7 +268,7 @@ namespace GPUTextureUsage {
const GPUFlagsConstant RENDER_ATTACHMENT = 0x10;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUTextureView {
};
GPUTextureView includes GPUObjectBase;
@@ -328,6 +331,7 @@ enum GPUTextureFormat {
"bgra8unorm-srgb",
// Packed 32-bit formats
"rgb9e5ufloat",
+ "rgb10a2uint",
"rgb10a2unorm",
"rg11b10ufloat",
@@ -416,7 +420,7 @@ enum GPUTextureFormat {
"astc-12x12-unorm-srgb",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUSampler {
};
GPUSampler includes GPUObjectBase;
@@ -462,7 +466,7 @@ enum GPUCompareFunction {
"always",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUBindGroupLayout {
};
GPUBindGroupLayout includes GPUObjectBase;
@@ -483,7 +487,7 @@ dictionary GPUBindGroupLayoutEntry {
};
typedef [EnforceRange] unsigned long GPUShaderStageFlags;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
namespace GPUShaderStage {
const GPUFlagsConstant VERTEX = 0x1;
const GPUFlagsConstant FRAGMENT = 0x2;
@@ -528,6 +532,8 @@ dictionary GPUTextureBindingLayout {
enum GPUStorageTextureAccess {
"write-only",
+ "read-only",
+ "read-write",
};
dictionary GPUStorageTextureBindingLayout {
@@ -536,7 +542,7 @@ dictionary GPUStorageTextureBindingLayout {
GPUTextureViewDimension viewDimension = "2d";
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUBindGroup {
};
GPUBindGroup includes GPUObjectBase;
@@ -560,7 +566,7 @@ dictionary GPUBufferBinding {
GPUSize64 size;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUPipelineLayout {
};
GPUPipelineLayout includes GPUObjectBase;
@@ -570,7 +576,7 @@ dictionary GPUPipelineLayoutDescriptor
required sequence bindGroupLayouts;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUShaderModule {
};
GPUShaderModule includes GPUObjectBase;
@@ -586,7 +592,7 @@ enum GPUCompilationMessageType {
"info",
};
-[Exposed=(Window, DedicatedWorker), Serializable, SecureContext]
+[Exposed=(Window, Worker), Serializable, SecureContext]
interface GPUCompilationMessage {
readonly attribute DOMString message;
readonly attribute GPUCompilationMessageType type;
@@ -596,11 +602,26 @@ interface GPUCompilationMessage {
readonly attribute unsigned long long length;
};
-[Exposed=(Window, DedicatedWorker), Serializable, SecureContext]
+[Exposed=(Window, Worker), Serializable, SecureContext]
interface GPUCompilationInfo {
readonly attribute FrozenArray messages;
};
+[Exposed=(Window, Worker), SecureContext, Serializable]
+interface GPUPipelineError : DOMException {
+ constructor(optional DOMString message = "", GPUPipelineErrorInit options);
+ readonly attribute GPUPipelineErrorReason reason;
+};
+
+dictionary GPUPipelineErrorInit {
+ required GPUPipelineErrorReason reason;
+};
+
+enum GPUPipelineErrorReason {
+ "validation",
+ "internal",
+};
+
enum GPUAutoLayoutMode {
"auto",
};
@@ -616,13 +637,13 @@ interface mixin GPUPipelineBase {
dictionary GPUProgrammableStage {
required GPUShaderModule module;
- required USVString entryPoint;
+ USVString entryPoint;
record constants;
};
-typedef double GPUPipelineConstantValue; // May represent WGSL’s bool, f32, i32, u32, and f16 if enabled.
+typedef double GPUPipelineConstantValue; // May represent WGSL's bool, f32, i32, u32, and f16 if enabled.
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUComputePipeline {
};
GPUComputePipeline includes GPUObjectBase;
@@ -633,7 +654,7 @@ dictionary GPUComputePipelineDescriptor
required GPUProgrammableStage compute;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPURenderPipeline {
};
GPURenderPipeline includes GPUObjectBase;
@@ -701,7 +722,7 @@ dictionary GPUBlendState {
};
typedef [EnforceRange] unsigned long GPUColorWriteFlags;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
namespace GPUColorWrite {
const GPUFlagsConstant RED = 0x1;
const GPUFlagsConstant GREEN = 0x2;
@@ -854,7 +875,7 @@ dictionary GPUImageCopyTexture {
GPUTextureAspect aspect = "all";
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUCommandBuffer {
};
GPUCommandBuffer includes GPUObjectBase;
@@ -866,7 +887,7 @@ dictionary GPUCommandBufferDescriptor
interface mixin GPUCommandsMixin {
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUCommandEncoder {
GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
@@ -933,7 +954,7 @@ interface mixin GPUDebugCommandsMixin {
undefined insertDebugMarker(USVString markerLabel);
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUComputePassEncoder {
undefined setPipeline(GPUComputePipeline pipeline);
undefined dispatchWorkgroups(GPUSize32 workgroupCountX, optional GPUSize32 workgroupCountY = 1, optional GPUSize32 workgroupCountZ = 1);
@@ -957,7 +978,7 @@ dictionary GPUComputePassDescriptor
GPUComputePassTimestampWrites timestampWrites;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPURenderPassEncoder {
undefined setViewport(float x, float y,
float width, float height,
@@ -1052,7 +1073,7 @@ interface mixin GPURenderCommandsMixin {
undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPURenderBundle {
};
GPURenderBundle includes GPUObjectBase;
@@ -1061,7 +1082,7 @@ dictionary GPURenderBundleDescriptor
: GPUObjectDescriptorBase {
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPURenderBundleEncoder {
GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
};
@@ -1077,7 +1098,7 @@ dictionary GPURenderBundleEncoderDescriptor
boolean stencilReadOnly = false;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUQueue {
undefined submit(sequence commandBuffers);
@@ -1098,7 +1119,7 @@ interface GPUQueue {
};
GPUQueue includes GPUObjectBase;
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUQuerySet {
undefined destroy();
@@ -1118,7 +1139,7 @@ enum GPUQueryType {
"timestamp",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUCanvasContext {
readonly attribute (HTMLCanvasElement or OffscreenCanvas) canvas;
@@ -1146,7 +1167,7 @@ enum GPUDeviceLostReason {
"destroyed",
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUDeviceLostInfo {
readonly attribute GPUDeviceLostReason reason;
readonly attribute DOMString message;
@@ -1156,27 +1177,33 @@ partial interface GPUDevice {
readonly attribute Promise lost;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUError {
readonly attribute DOMString message;
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUValidationError
: GPUError {
constructor(DOMString message);
};
-[Exposed=(Window, DedicatedWorker), SecureContext]
+[Exposed=(Window, Worker), SecureContext]
interface GPUOutOfMemoryError
: GPUError {
constructor(DOMString message);
};
+[Exposed=(Window, Worker), SecureContext]
+interface GPUInternalError
+ : GPUError {
+ constructor(DOMString message);
+};
+
enum GPUErrorFilter {
"validation",
"out-of-memory",
- "internal"
+ "internal",
};
partial interface GPUDevice {
@@ -1184,8 +1211,21 @@ partial interface GPUDevice {
Promise popErrorScope();
};
+[Exposed=(Window, Worker), SecureContext]
+interface GPUUncapturedErrorEvent : Event {
+ constructor(
+ DOMString type,
+ GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict
+ );
+ [SameObject] readonly attribute GPUError error;
+};
+
+dictionary GPUUncapturedErrorEventInit : EventInit {
+ required GPUError error;
+};
+
partial interface GPUDevice {
- [Exposed=(Window, DedicatedWorker)]
+ [Exposed=(Window, Worker)]
attribute EventHandler onuncapturederror;
};