summaryrefslogtreecommitdiff
path: root/op_crates/webgpu/01_webgpu.js
diff options
context:
space:
mode:
authorcrowlKats <13135287+crowlKats@users.noreply.github.com>2021-03-01 11:31:13 +0100
committerGitHub <noreply@github.com>2021-03-01 11:31:13 +0100
commit7cd14f97c9300357475e3e461fa57cbb7ec5bfec (patch)
tree39eb11e8a9c53001ffe814f5aac3ec5e37de6357 /op_crates/webgpu/01_webgpu.js
parentdbdbe7a1cf0d56df85305eb3638bc177d8a0216f (diff)
feat: WebGPU API (#7977)
Co-authored-by: Luca Casonato <lucacasonato@yahoo.com>
Diffstat (limited to 'op_crates/webgpu/01_webgpu.js')
-rw-r--r--op_crates/webgpu/01_webgpu.js5048
1 files changed, 5048 insertions, 0 deletions
diff --git a/op_crates/webgpu/01_webgpu.js b/op_crates/webgpu/01_webgpu.js
new file mode 100644
index 000000000..7a078619e
--- /dev/null
+++ b/op_crates/webgpu/01_webgpu.js
@@ -0,0 +1,5048 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+// @ts-check
+/// <reference path="../../core/lib.deno_core.d.ts" />
+/// <reference path="../web/internal.d.ts" />
+/// <reference path="../web/lib.deno_web.d.ts" />
+/// <reference path="./lib.deno_webgpu.d.ts" />
+
+"use strict";
+
+((window) => {
+ const core = window.Deno.core;
+ const webidl = window.__bootstrap.webidl;
+ const eventTarget = window.__bootstrap.eventTarget;
+
+ /**
+ * @param {any} self
+ * @param {{prefix: string, context: string}} opts
+ * @returns {InnerGPUDevice & {rid: number}}
+ */
+ function assertDevice(self, { prefix, context }) {
+ const device = self[_device];
+ const deviceRid = device?.rid;
+ if (deviceRid === undefined) {
+ throw new DOMException(
+ `${prefix}: ${context} references an invalid or destroyed device.`,
+ "OperationError",
+ );
+ }
+ return device;
+ }
+
+ /**
+ * @param {InnerGPUDevice} self
+ * @param {any} resource
+ * @param {{prefix: string, resourceContext: string, selfContext: string}} opts
+ * @returns {InnerGPUDevice & {rid: number}}
+ */
+ function assertDeviceMatch(
+ self,
+ resource,
+ { prefix, resourceContext, selfContext },
+ ) {
+ const resourceDevice = assertDevice(resource, {
+ prefix,
+ context: resourceContext,
+ });
+ if (resourceDevice.rid !== self.rid) {
+ throw new DOMException(
+ `${prefix}: ${resourceContext} belongs to a diffent device than ${selfContext}.`,
+ "OperationError",
+ );
+ }
+ return { ...resourceDevice, rid: resourceDevice.rid };
+ }
+
+ /**
+ * @param {any} self
+ * @param {{prefix: string, context: string}} opts
+ * @returns {number}
+ */
+ function assertResource(self, { prefix, context }) {
+ const rid = self[_rid];
+ if (rid === undefined) {
+ throw new DOMException(
+ `${prefix}: ${context} an invalid or destroyed resource.`,
+ "OperationError",
+ );
+ }
+ return rid;
+ }
+
+ /**
+ * @param {number[] | GPUExtent3DDict} data
+ * @returns {GPUExtent3DDict}
+ */
+ function normalizeGPUExtent3D(data) {
+ if (Array.isArray(data)) {
+ return {
+ width: data[0],
+ height: data[1],
+ depth: data[2],
+ };
+ } else {
+ return data;
+ }
+ }
+
+ /**
+ * @param {number[] | GPUOrigin3DDict} data
+ * @returns {GPUOrigin3DDict}
+ */
+ function normalizeGPUOrigin3D(data) {
+ if (Array.isArray(data)) {
+ return {
+ x: data[0],
+ y: data[1],
+ z: data[2],
+ };
+ } else {
+ return data;
+ }
+ }
+
+ /**
+ * @param {number[] | GPUColor} data
+ * @returns {GPUColor}
+ */
+ function normalizeGPUColor(data) {
+ if (Array.isArray(data)) {
+ return {
+ r: data[0],
+ g: data[1],
+ b: data[2],
+ a: data[3],
+ };
+ } else {
+ return data;
+ }
+ }
+
+ class GPUOutOfMemoryError extends Error {
+ constructor() {
+ super();
+ }
+ }
+
+ class GPUValidationError extends Error {
+ /** @param {string} message */
+ constructor(message) {
+ const prefix = "Failed to construct 'GPUValidationError'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ message = webidl.converters.DOMString(message, {
+ prefix,
+ context: "Argument 1",
+ });
+ super(message);
+ }
+ }
+
+ class GPU {
+ [webidl.brand] = webidl.brand;
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPURequestAdapterOptions} options
+ */
+ async requestAdapter(options = {}) {
+ webidl.assertBranded(this, GPU);
+ options = webidl.converters.GPURequestAdapterOptions(options, {
+ prefix: "Failed to execute 'requestAdapter' on 'GPU'",
+ context: "Argument 1",
+ });
+
+ const { err, ...data } = await core.jsonOpAsync(
+ "op_webgpu_request_adapter",
+ { ...options },
+ );
+
+ if (err) {
+ return null;
+ } else {
+ return createGPUAdapter(data.name, data);
+ }
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${inspect({})}`;
+ }
+ }
+
+ const _name = Symbol("[[name]]");
+ const _adapter = Symbol("[[adapter]]");
+ const _cleanup = Symbol("[[cleanup]]");
+
+ /**
+ * @typedef InnerGPUAdapter
+ * @property {number} rid
+ * @property {GPUAdapterFeatures} features
+ * @property {GPUAdapterLimits} limits
+ */
+
+ /**
+ * @param {string} name
+ * @param {InnerGPUAdapter} inner
+ * @returns {GPUAdapter}
+ */
+ function createGPUAdapter(name, inner) {
+ /** @type {GPUAdapter} */
+ const adapter = webidl.createBranded(GPUAdapter);
+ adapter[_name] = name;
+ adapter[_adapter] = {
+ ...inner,
+ features: createGPUAdapterFeatures(inner.features),
+ limits: createGPUAdapterLimits(inner.limits),
+ };
+ return adapter;
+ }
+
+ class GPUAdapter {
+ /** @type {string} */
+ [_name];
+ /** @type {InnerGPUAdapter} */
+ [_adapter];
+
+ /** @returns {string} */
+ get name() {
+ webidl.assertBranded(this, GPUAdapter);
+ return this[_name];
+ }
+ /** @returns {GPUAdapterFeatures} */
+ get features() {
+ webidl.assertBranded(this, GPUAdapter);
+ return this[_adapter].features;
+ }
+ /** @returns {GPUAdapterLimits} */
+ get limits() {
+ webidl.assertBranded(this, GPUAdapter);
+ return this[_adapter].limits;
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPUDeviceDescriptor} descriptor
+ * @returns {Promise<GPUDevice>}
+ */
+ async requestDevice(descriptor = {}) {
+ webidl.assertBranded(this, GPUAdapter);
+ const prefix = "Failed to execute 'requestDevice' on 'GPUAdapter'";
+ descriptor = webidl.converters.GPUDeviceDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const nonGuaranteedFeatures = descriptor.nonGuaranteedFeatures ?? [];
+ for (const feature of nonGuaranteedFeatures) {
+ if (!this[_adapter].features.has(feature)) {
+ throw new TypeError(
+ `${prefix}: nonGuaranteedFeatures must be a subset of the adapter features.`,
+ );
+ }
+ }
+ const nonGuaranteedLimits = descriptor.nonGuaranteedLimits ?? [];
+ // TODO(lucacasonato): validate nonGuaranteedLimits
+
+ const { rid, features, limits } = await core.jsonOpAsync(
+ "op_webgpu_request_device",
+ {
+ adapterRid: this[_adapter].rid,
+ labe: descriptor.label,
+ nonGuaranteedFeatures,
+ nonGuaranteedLimits,
+ },
+ );
+
+ const inner = new InnerGPUDevice({
+ rid,
+ adapter: this,
+ features: Object.freeze(features),
+ limits: Object.freeze(limits),
+ });
+ return createGPUDevice(
+ descriptor.label ?? null,
+ inner,
+ createGPUQueue(descriptor.label ?? null, inner),
+ );
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ name: this.name,
+ features: this.features,
+ limits: this.limits,
+ })
+ }`;
+ }
+ }
+
+ const _limits = Symbol("[[limits]]");
+
+ function createGPUAdapterLimits(features) {
+ /** @type {GPUAdapterLimits} */
+ const adapterFeatures = webidl.createBranded(GPUAdapterLimits);
+ adapterFeatures[_limits] = features;
+ return adapterFeatures;
+ }
+
+ /**
+ * @typedef InnerAdapterLimits
+ * @property {number} maxTextureDimension1D
+ * @property {number} maxTextureDimension2D
+ * @property {number} maxTextureDimension3D
+ * @property {number} maxTextureArrayLayers
+ * @property {number} maxBindGroups
+ * @property {number} maxDynamicUniformBuffersPerPipelineLayout
+ * @property {number} maxDynamicStorageBuffersPerPipelineLayout
+ * @property {number} maxSampledTexturesPerShaderStage
+ * @property {number} maxSamplersPerShaderStage
+ * @property {number} maxStorageBuffersPerShaderStage
+ * @property {number} maxStorageTexturesPerShaderStage
+ * @property {number} maxUniformBuffersPerShaderStage
+ * @property {number} maxUniformBufferBindingSize
+ * @property {number} maxStorageBufferBindingSize
+ * @property {number} maxVertexBuffers
+ * @property {number} maxVertexAttributes
+ * @property {number} maxVertexBufferArrayStride
+ */
+
+ class GPUAdapterLimits {
+ /** @type {InnerAdapterLimits} */
+ [_limits];
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ get maxTextureDimension1D() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxTextureDimension2D() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxTextureDimension3D() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxTextureArrayLayers() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxBindGroups() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxBindGroups;
+ }
+ get maxDynamicUniformBuffersPerPipelineLayout() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxDynamicUniformBuffersPerPipelineLayout;
+ }
+ get maxDynamicStorageBuffersPerPipelineLayout() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxDynamicStorageBuffersPerPipelineLayout;
+ }
+ get maxSampledTexturesPerShaderStage() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxSampledTexturesPerShaderStage;
+ }
+ get maxSamplersPerShaderStage() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxSamplersPerShaderStage;
+ }
+ get maxStorageBuffersPerShaderStage() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxStorageBuffersPerShaderStage;
+ }
+ get maxStorageTexturesPerShaderStage() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxStorageTexturesPerShaderStage;
+ }
+ get maxUniformBuffersPerShaderStage() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxUniformBuffersPerShaderStage;
+ }
+ get maxUniformBufferBindingSize() {
+ webidl.assertBranded(this, GPUAdapterLimits);
+ return this[_limits].maxUniformBufferBindingSize;
+ }
+ get maxStorageBufferBindingSize() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxVertexBuffers() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxVertexAttributes() {
+ throw new TypeError("Not yet implemented");
+ }
+ get maxVertexBufferArrayStride() {
+ throw new TypeError("Not yet implemented");
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${inspect(this[_limits])}`;
+ }
+ }
+
+ const _features = Symbol("[[features]]");
+
+ function createGPUAdapterFeatures(features) {
+ /** @type {GPUAdapterFeatures} */
+ const adapterFeatures = webidl.createBranded(GPUAdapterFeatures);
+ adapterFeatures[_features] = new Set(features);
+ return adapterFeatures;
+ }
+
+ class GPUAdapterFeatures {
+ /** @type {Set<string>} */
+ [_features];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /** @return {IterableIterator<[string, string]>} */
+ entries() {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features].entries();
+ }
+
+ /** @return {void} */
+ forEach(callbackfn, thisArg) {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ this[_features].forEach(callbackfn, thisArg);
+ }
+
+ /** @return {boolean} */
+ has(value) {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features].has(value);
+ }
+
+ /** @return {IterableIterator<string>} */
+ keys() {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features].keys();
+ }
+
+ /** @return {IterableIterator<string>} */
+ values() {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features].values();
+ }
+
+ /** @return {number} */
+ get size() {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features].size;
+ }
+
+ [Symbol.iterator]() {
+ webidl.assertBranded(this, GPUAdapterFeatures);
+ return this[_features][Symbol.iterator]();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${inspect([...this.values()])}`;
+ }
+ }
+
+ const _reason = Symbol("[[reason]]");
+ const _message = Symbol("[[message]]");
+
+ /**
+ *
+ * @param {string | undefined} reason
+ * @param {string} message
+ * @returns {GPUDeviceLostInfo}
+ */
+ function createGPUDeviceLostInfo(reason, message) {
+ /** @type {GPUDeviceLostInfo} */
+ const deviceLostInfo = webidl.createBranded(GPUDeviceLostInfo);
+ deviceLostInfo[_reason] = reason;
+ deviceLostInfo[_message] = message;
+ return deviceLostInfo;
+ }
+
+ class GPUDeviceLostInfo {
+ /** @type {string | undefined} */
+ [_reason];
+ /** @type {string} */
+ [_message];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ get reason() {
+ webidl.assertBranded(this, GPUDeviceLostInfo);
+ return this[_reason];
+ }
+ get message() {
+ webidl.assertBranded(this, GPUDeviceLostInfo);
+ return this[_message];
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({ reason: this[_reason], message: this[_message] })
+ }`;
+ }
+ }
+
+ const _label = Symbol("[[label]]");
+
+ /**
+ * @param {string} name
+ * @param {any} type
+ */
+ function GPUObjectBaseMixin(name, type) {
+ type.prototype[_label] = null;
+ Object.defineProperty(type.prototype, "label", {
+ /**
+ * @return {string | null}
+ */
+ get() {
+ webidl.assertBranded(this, type);
+ return this[_label];
+ },
+ /**
+ * @param {string | null} label
+ */
+ set(label) {
+ webidl.assertBranded(this, type);
+ label = webidl.converters["UVString?"](label, {
+ prefix: `Failed to set 'label' on '${name}'`,
+ context: "Argument 1",
+ });
+ this[_label] = label;
+ },
+ });
+ }
+
+ const _device = Symbol("[[device]]");
+ const _queue = Symbol("[[queue]]");
+
+ /**
+ * @typedef ErrorScope
+ * @property {string} filter
+ * @property {GPUError | undefined} error
+ */
+
+ /**
+ * @typedef InnerGPUDeviceOptions
+ * @property {GPUAdapter} adapter
+ * @property {number | undefined} rid
+ * @property {GPUFeatureName[]} features
+ * @property {object} limits
+ */
+
+ class InnerGPUDevice {
+ /** @type {GPUAdapter} */
+ adapter;
+ /** @type {number | undefined} */
+ rid;
+ /** @type {GPUFeatureName[]} */
+ features;
+ /** @type {object} */
+ limits;
+ /** @type {WeakRef<any>[]} */
+ resources;
+ /** @type {boolean} */
+ isLost;
+ /** @type {Promise<GPUDeviceLostInfo>} */
+ lost;
+ /** @type {(info: GPUDeviceLostInfo) => void} */
+ resolveLost;
+ /** @type {ErrorScope[]} */
+ errorScopeStack;
+
+ /**
+ * @param {InnerGPUDeviceOptions} options
+ */
+ constructor(options) {
+ this.adapter = options.adapter;
+ this.rid = options.rid;
+ this.features = options.features;
+ this.limits = options.limits;
+ this.resources = [];
+ this.isLost = false;
+ this.resolveLost = () => {};
+ this.lost = new Promise((resolve) => {
+ this.resolveLost = resolve;
+ });
+ this.errorScopeStack = [];
+ }
+
+ /** @param {any} resource */
+ trackResource(resource) {
+ this.resources.push(new WeakRef(resource));
+ }
+
+ /** @param {{ type: string, value: string | null } | undefined} err */
+ pushError(err) {
+ if (err) {
+ switch (err.type) {
+ case "lost":
+ this.isLost = true;
+ this.resolveLost(
+ createGPUDeviceLostInfo(undefined, "device was lost"),
+ );
+ break;
+ case "validation":
+ case "out-of-memory":
+ for (
+ let i = this.errorScopeStack.length - 1;
+ i >= 0;
+ i--
+ ) {
+ const scope = this.errorScopeStack[i];
+ if (scope.filter == err.type) {
+ if (!scope.error) {
+ switch (err.type) {
+ case "validation":
+ scope.error = new GPUValidationError(
+ err.value ?? "validation error",
+ );
+ break;
+ case "out-of-memory":
+ scope.error = new GPUOutOfMemoryError();
+ break;
+ }
+ }
+ return;
+ }
+ }
+ // TODO(lucacasonato): emit a UncapturedErrorEvent
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} inner
+ * @param {GPUQueue} queue
+ * @returns {GPUDevice}
+ */
+ function createGPUDevice(label, inner, queue) {
+ /** @type {GPUDevice} */
+ const device = webidl.createBranded(GPUDevice);
+ device[_label] = label;
+ device[_device] = inner;
+ device[_queue] = queue;
+ return device;
+ }
+
+ // TODO(@crowlKats): https://gpuweb.github.io/gpuweb/#errors-and-debugging
+ class GPUDevice extends eventTarget.EventTarget {
+ /** @type {InnerGPUDevice} */
+ [_device];
+
+ /** @type {GPUQueue} */
+ [_queue];
+
+ [_cleanup]() {
+ const device = this[_device];
+ const resources = device.resources;
+ while (resources.length > 0) {
+ const resource = resources.pop()?.deref();
+ if (resource) {
+ resource[_cleanup]();
+ }
+ }
+ const rid = device.rid;
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ device.rid = undefined;
+ }
+ }
+
+ get adapter() {
+ webidl.assertBranded(this, GPUDevice);
+ return this[_device].adapter;
+ }
+ get features() {
+ webidl.assertBranded(this, GPUDevice);
+ return this[_device].features;
+ }
+ get limits() {
+ webidl.assertBranded(this, GPUDevice);
+ return this[_device].limits;
+ }
+ get queue() {
+ webidl.assertBranded(this, GPUDevice);
+ return this[_queue];
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ super();
+ }
+
+ destroy() {
+ webidl.assertBranded(this, GPUDevice);
+ this[_cleanup]();
+ }
+
+ /**
+ * @param {GPUBufferDescriptor} descriptor
+ * @returns {GPUBuffer}
+ */
+ createBuffer(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createBuffer' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBufferDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_buffer", {
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
+ /** @type {CreateGPUBufferOptions} */
+ let options;
+ if (descriptor.mappedAtCreation) {
+ options = {
+ mapping: new ArrayBuffer(descriptor.size),
+ mappingRange: [0, descriptor.size],
+ mappedRanges: [],
+ state: "mapped at creation",
+ };
+ } else {
+ options = {
+ mapping: null,
+ mappedRanges: null,
+ mappingRange: null,
+ state: "unmapped",
+ };
+ }
+ const buffer = createGPUBuffer(
+ descriptor.label ?? null,
+ device,
+ rid,
+ descriptor.size,
+ descriptor.usage,
+ options,
+ );
+ device.trackResource((buffer));
+ return buffer;
+ }
+
+ /**
+ * @param {GPUTextureDescriptor} descriptor
+ * @returns {GPUTexture}
+ */
+ createTexture(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createTexture' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUTextureDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_texture", {
+ deviceRid: device.rid,
+ ...descriptor,
+ size: normalizeGPUExtent3D(descriptor.size),
+ });
+ device.pushError(err);
+
+ const texture = createGPUTexture(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((texture));
+ return texture;
+ }
+
+ /**
+ * @param {GPUSamplerDescriptor} descriptor
+ * @returns {GPUSampler}
+ */
+ createSampler(descriptor = {}) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createSampler' on 'GPUDevice'";
+ descriptor = webidl.converters.GPUSamplerDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_sampler", {
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
+
+ const sampler = createGPUSampler(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((sampler));
+ return sampler;
+ }
+
+ /**
+ * @param {GPUBindGroupLayoutDescriptor} descriptor
+ * @returns {GPUBindGroupLayout}
+ */
+ createBindGroupLayout(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createBindGroupLayout' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBindGroupLayoutDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ for (const entry of descriptor.entries) {
+ let i = 0;
+ if (entry.buffer) i++;
+ if (entry.sampler) i++;
+ if (entry.texture) i++;
+ if (entry.storageTexture) i++;
+
+ if (i !== 1) {
+ throw new Error(); // TODO(@crowlKats): correct error
+ }
+ }
+
+ const { rid, err } = core.jsonOpSync(
+ "op_webgpu_create_bind_group_layout",
+ {
+ deviceRid: device.rid,
+ ...descriptor,
+ },
+ );
+ device.pushError(err);
+
+ const bindGroupLayout = createGPUBindGroupLayout(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((bindGroupLayout));
+ return bindGroupLayout;
+ }
+
+ /**
+ * @param {GPUPipelineLayoutDescriptor} descriptor
+ * @returns {GPUPipelineLayout}
+ */
+ createPipelineLayout(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createPipelineLayout' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUPipelineLayoutDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bindGroupLayouts = descriptor.bindGroupLayouts.map(
+ (layout, i) => {
+ const context = `bind group layout ${i + 1}`;
+ const rid = assertResource(layout, { prefix, context });
+ assertDeviceMatch(device, layout, {
+ prefix,
+ selfContext: "this",
+ resourceContext: context,
+ });
+ return rid;
+ },
+ );
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_pipeline_layout", {
+ deviceRid: device.rid,
+ label: descriptor.label,
+ bindGroupLayouts,
+ });
+ device.pushError(err);
+
+ const pipelineLayout = createGPUPipelineLayout(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((pipelineLayout));
+ return pipelineLayout;
+ }
+
+ /**
+ * @param {GPUBindGroupDescriptor} descriptor
+ * @returns {GPUBindGroup}
+ */
+ createBindGroup(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createBindGroup' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUBindGroupDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const layout = assertResource(descriptor.layout, {
+ prefix,
+ context: "layout",
+ });
+ assertDeviceMatch(device, descriptor.layout, {
+ prefix,
+ resourceContext: "layout",
+ selfContext: "this",
+ });
+ const entries = descriptor.entries.map((entry, i) => {
+ const context = `entry ${i + 1}`;
+ const resource = entry.resource;
+ if (resource instanceof GPUSampler) {
+ const rid = assertResource(resource, {
+ prefix,
+ context,
+ });
+ assertDeviceMatch(device, resource, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUSampler",
+ resource: rid,
+ };
+ } else if (resource instanceof GPUTextureView) {
+ const rid = assertResource(resource, {
+ prefix,
+ context,
+ });
+ assertResource(resource[_texture], {
+ prefix,
+ context,
+ });
+ assertDeviceMatch(device, resource[_texture], {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUTextureView",
+ resource: rid,
+ };
+ } else {
+ const rid = assertResource(resource.buffer, { prefix, context });
+ assertDeviceMatch(device, resource.buffer, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return {
+ binding: entry.binding,
+ kind: "GPUBufferBinding",
+ resource: rid,
+ offset: entry.resource.offset,
+ size: entry.resource.size,
+ };
+ }
+ });
+
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_bind_group", {
+ deviceRid: device.rid,
+ label: descriptor.label,
+ layout,
+ entries,
+ });
+ device.pushError(err);
+
+ const bindGroup = createGPUBindGroup(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((bindGroup));
+ return bindGroup;
+ }
+
+ /**
+ * @param {GPUShaderModuleDescriptor} descriptor
+ */
+ createShaderModule(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createShaderModule' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUShaderModuleDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync(
+ "op_webgpu_create_shader_module",
+ {
+ deviceRid: device.rid,
+ label: descriptor.label,
+ code: (typeof descriptor.code === "string")
+ ? descriptor.code
+ : undefined,
+ sourceMap: descriptor.sourceMap,
+ },
+ ...(descriptor.code instanceof Uint32Array
+ ? [new Uint8Array(descriptor.code.buffer)]
+ : []),
+ );
+ device.pushError(err);
+
+ const shaderModule = createGPUShaderModule(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((shaderModule));
+ return shaderModule;
+ }
+
+ /**
+ * @param {GPUComputePipelineDescriptor} descriptor
+ * @returns {GPUComputePipeline}
+ */
+ createComputePipeline(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createComputePipeline' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUComputePipelineDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ let layout = undefined;
+ if (descriptor.layout) {
+ 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,
+ context: "compute shader module",
+ });
+ assertDeviceMatch(device, descriptor.compute.module, {
+ prefix,
+ resourceContext: "compute shader module",
+ selfContext: "this",
+ });
+
+ const { rid, err } = core.jsonOpSync(
+ "op_webgpu_create_compute_pipeline",
+ {
+ deviceRid: device.rid,
+ label: descriptor.label,
+ layout,
+ compute: {
+ module,
+ entryPoint: descriptor.compute.entryPoint,
+ },
+ },
+ );
+ device.pushError(err);
+
+ const computePipeline = createGPUComputePipeline(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((computePipeline));
+ return computePipeline;
+ }
+
+ /**
+ * @param {GPURenderPipelineDescriptor} descriptor
+ * @returns {GPURenderPipeline}
+ */
+ createRenderPipeline(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createRenderPipeline' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderPipelineDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ let layout = undefined;
+ if (descriptor.layout) {
+ 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,
+ context: "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,
+ context: "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 } = core.jsonOpSync("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);
+
+ const renderPipeline = createGPURenderPipeline(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((renderPipeline));
+ return renderPipeline;
+ }
+
+ createComputePipelineAsync(descriptor) {
+ // TODO(lucacasonato): this should be real async
+ return Promise.resolve(this.createComputePipeline(descriptor));
+ }
+
+ createRenderPipelineAsync(descriptor) {
+ // TODO(lucacasonato): this should be real async
+ return Promise.resolve(this.createRenderPipeline(descriptor));
+ }
+
+ /**
+ * @param {GPUCommandEncoderDescriptor} descriptor
+ * @returns {GPUCommandEncoder}
+ */
+ createCommandEncoder(descriptor = {}) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createCommandEncoder' on 'GPUDevice'";
+ descriptor = webidl.converters.GPUCommandEncoderDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_command_encoder", {
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
+
+ const commandEncoder = createGPUCommandEncoder(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((commandEncoder));
+ return commandEncoder;
+ }
+
+ /**
+ * @param {GPURenderBundleEncoderDescriptor} descriptor
+ * @returns {GPURenderBundleEncoder}
+ */
+ createRenderBundleEncoder(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix =
+ "Failed to execute 'createRenderBundleEncoder' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderBundleEncoderDescriptor(
+ descriptor,
+ {
+ prefix,
+ context: "Argument 1",
+ },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync(
+ "op_webgpu_create_render_bundle_encoder",
+ {
+ deviceRid: device.rid,
+ ...descriptor,
+ },
+ );
+ device.pushError(err);
+
+ const renderBundleEncoder = createGPURenderBundleEncoder(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((renderBundleEncoder));
+ return renderBundleEncoder;
+ }
+
+ /**
+ * @param {GPUQuerySetDescriptor} descriptor
+ * @returns {GPUQuerySet}
+ */
+ createQuerySet(descriptor) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'createQuerySet' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPUQuerySetDescriptor(
+ descriptor,
+ {
+ prefix,
+ context: "Argument 1",
+ },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_query_set", {
+ deviceRid: device.rid,
+ ...descriptor,
+ });
+ device.pushError(err);
+
+ const querySet = createGPUQuerySet(
+ descriptor.label ?? null,
+ device,
+ rid,
+ descriptor,
+ );
+ device.trackResource((querySet));
+ return querySet;
+ }
+
+ get lost() {
+ webidl.assertBranded(this, GPUDevice);
+ const device = this[_device];
+ if (!device) {
+ return Promise.resolve(true);
+ }
+ if (device.rid === undefined) {
+ return Promise.resolve(true);
+ }
+ return device.lost;
+ }
+
+ /**
+ * @param {GPUErrorFilter} filter
+ */
+ pushErrorScope(filter) {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'pushErrorScope' on 'GPUDevice'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ filter = webidl.converters.GPUErrorFilter(filter, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ device.errorScopeStack.push({ filter, error: undefined });
+ }
+
+ /**
+ * @returns {Promise<GPUError | null>}
+ */
+ // deno-lint-ignore require-await
+ async popErrorScope() {
+ webidl.assertBranded(this, GPUDevice);
+ const prefix = "Failed to execute 'pushErrorScope' on 'GPUDevice'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ if (device.isLost) {
+ throw new DOMException("Device has been lost.", "OperationError");
+ }
+ const scope = device.errorScopeStack.pop();
+ if (!scope) {
+ throw new DOMException(
+ "There are no error scopes on that stack.",
+ "OperationError",
+ );
+ }
+ return scope.error ?? null;
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ adapter: this.adapter,
+ features: this.features,
+ label: this.label,
+ limits: this.limits,
+ queue: this.queue,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUDevice", GPUDevice);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @returns {GPUQueue}
+ */
+ function createGPUQueue(label, device) {
+ /** @type {GPUQueue} */
+ const queue = webidl.createBranded(GPUQueue);
+ queue[_label] = label;
+ queue[_device] = device;
+ return queue;
+ }
+
+ class GPUQueue {
+ /** @type {InnerGPUDevice} */
+ [_device];
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPUCommandBuffer[]} commandBuffers
+ */
+ submit(commandBuffers) {
+ webidl.assertBranded(this, GPUQueue);
+ const prefix = "Failed to execute 'submit' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 1, {
+ prefix,
+ });
+ commandBuffers = webidl.converters["sequence<GPUCommandBuffer>"](
+ commandBuffers,
+ { prefix, context: "Argument 1" },
+ );
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandBufferRids = commandBuffers.map((buffer, i) => {
+ const context = `command buffer ${i + 1}`;
+ const rid = assertResource(buffer, { prefix, context });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ selfContext: "this",
+ resourceContext: context,
+ });
+ return rid;
+ });
+ const { err } = core.jsonOpSync("op_webgpu_queue_submit", {
+ queueRid: device.rid,
+ commandBuffers: commandBufferRids,
+ });
+ device.pushError(err);
+ }
+
+ onSubmittedWorkDone() {
+ webidl.assertBranded(this, GPUQueue);
+ return Promise.resolve();
+ }
+
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {number} bufferOffset
+ * @param {BufferSource} data
+ * @param {number} [dataOffset]
+ * @param {number} [size]
+ */
+ writeBuffer(buffer, bufferOffset, data, dataOffset = 0, size) {
+ webidl.assertBranded(this, GPUQueue);
+ const prefix = "Failed to execute 'writeBuffer' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ buffer = webidl.converters["GPUBuffer"](buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ bufferOffset = webidl.converters["GPUSize64"](bufferOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 3",
+ });
+ dataOffset = webidl.converters["GPUSize64"](dataOffset, {
+ prefix,
+ context: "Argument 4",
+ });
+ size = size === undefined
+ ? undefined
+ : webidl.converters["GPUSize64"](size, {
+ prefix,
+ context: "Argument 5",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ selfContext: "this",
+ resourceContext: "Argument 1",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_write_buffer",
+ {
+ queueRid: device.rid,
+ buffer: bufferRid,
+ bufferOffset,
+ dataOffset,
+ size,
+ },
+ new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data),
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUImageCopyTexture} destination
+ * @param {BufferSource} data
+ * @param {GPUImageDataLayout} dataLayout
+ * @param {GPUExtent3D} size
+ */
+ writeTexture(destination, data, dataLayout, size) {
+ webidl.assertBranded(this, GPUQueue);
+ const prefix = "Failed to execute 'writeTexture' on 'GPUQueue'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 1",
+ });
+ data = webidl.converters.BufferSource(data, {
+ prefix,
+ context: "Argument 2",
+ });
+ dataLayout = webidl.converters.GPUImageDataLayout(dataLayout, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUExtent3D(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const textureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ selfContext: "this",
+ resourceContext: "texture",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_write_texture",
+ {
+ queueRid: device.rid,
+ destination: {
+ texture: textureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ },
+ dataLayout,
+ size: normalizeGPUExtent3D(size),
+ },
+ new Uint8Array(ArrayBuffer.isView(data) ? data.buffer : data),
+ );
+ device.pushError(err);
+ }
+
+ copyImageBitmapToTexture(_source, _destination, _copySize) {
+ throw new Error("Not yet implemented");
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUQueue", GPUQueue);
+
+ const _rid = Symbol("[[rid]]");
+
+ const _size = Symbol("[[size]]");
+ const _usage = Symbol("[[usage]]");
+ const _state = Symbol("[[state]]");
+ const _mappingRange = Symbol("[[mapping_range]]");
+ const _mappedRanges = Symbol("[[mapped_ranges]]");
+ const _mapMode = Symbol("[[map_mode]]");
+
+ /**
+ * @typedef CreateGPUBufferOptions
+ * @property {ArrayBuffer | null} mapping
+ * @property {number[] | null} mappingRange
+ * @property {[ArrayBuffer, number, number][] | null} mappedRanges
+ * @property {"mapped" | "mapped at creation" | "mapped pending" | "unmapped" | "destroy" } state
+ */
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @param {number} size
+ * @param {number} usage
+ * @param {CreateGPUBufferOptions} options
+ * @returns {GPUBuffer}
+ */
+ function createGPUBuffer(label, device, rid, size, usage, options) {
+ /** @type {GPUBuffer} */
+ const buffer = webidl.createBranded(GPUBuffer);
+ buffer[_label] = label;
+ buffer[_device] = device;
+ buffer[_rid] = rid;
+ buffer[_size] = size;
+ buffer[_usage] = usage;
+ buffer[_mappingRange] = options.mappingRange;
+ buffer[_mappedRanges] = options.mappedRanges;
+ buffer[_state] = options.state;
+ return buffer;
+ }
+
+ class GPUBuffer {
+ /** @type {InnerGPUDevice} */
+ [_device];
+
+ /** @type {number} */
+ [_rid];
+
+ /** @type {number} */
+ [_size];
+
+ /** @type {number} */
+ [_usage];
+
+ /** @type {"mapped" | "mapped at creation" | "mapped pending" | "unmapped" | "destroy"} */
+ [_state];
+
+ /** @type {[number, number] | null} */
+ [_mappingRange];
+
+ /** @type {[ArrayBuffer, number, number][] | null} */
+ [_mappedRanges];
+
+ /** @type {number} */
+ [_mapMode];
+
+ [_cleanup]() {
+ const mappedRanges = this[_mappedRanges];
+ if (mappedRanges) {
+ while (mappedRanges.length > 0) {
+ const mappedRange = mappedRanges.pop();
+ if (mappedRange !== undefined) {
+ core.close(mappedRange[1]);
+ }
+ }
+ }
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ this[_state] = "destroy";
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {number} mode
+ * @param {number} offset
+ * @param {number} [size]
+ */
+ async mapAsync(mode, offset = 0, size) {
+ webidl.assertBranded(this, GPUBuffer);
+ const prefix = "Failed to execute 'mapAsync' on 'GPUBuffer'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ mode = webidl.converters.GPUMapModeFlags(mode, {
+ prefix,
+ context: "Argument 1",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 2",
+ });
+ size = size === undefined
+ ? undefined
+ : webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ /** @type {number} */
+ let rangeSize;
+ if (size === undefined) {
+ rangeSize = Math.max(0, this[_size] - offset);
+ } else {
+ rangeSize = this[_size];
+ }
+ if ((offset % 8) !== 0) {
+ throw new DOMException(
+ `${prefix}: offset must be a multiple of 8.`,
+ "OperationError",
+ );
+ }
+ if ((rangeSize % 4) !== 0) {
+ throw new DOMException(
+ `${prefix}: rangeSize must be a multiple of 4.`,
+ "OperationError",
+ );
+ }
+ if ((offset + rangeSize) > this[_size]) {
+ throw new DOMException(
+ `${prefix}: offset + rangeSize must be less than or equal to buffer size.`,
+ "OperationError",
+ );
+ }
+ if (this[_state] !== "unmapped") {
+ throw new DOMException(
+ `${prefix}: GPUBuffer is not currently unmapped.`,
+ "OperationError",
+ );
+ }
+ const readMode = (mode & 0x0001) === 0x0001;
+ const writeMode = (mode & 0x0002) === 0x0002;
+ if ((readMode && writeMode) || (!readMode && !writeMode)) {
+ throw new DOMException(
+ `${prefix}: exactly one of READ or WRITE map mode must be set.`,
+ "OperationError",
+ );
+ }
+ if (readMode && !((this[_usage] && 0x0001) === 0x0001)) {
+ throw new DOMException(
+ `${prefix}: READ map mode not valid because buffer does not have MAP_READ usage.`,
+ "OperationError",
+ );
+ }
+ if (writeMode && !((this[_usage] && 0x0002) === 0x0002)) {
+ throw new DOMException(
+ `${prefix}: WRITE map mode not valid because buffer does not have MAP_WRITE usage.`,
+ "OperationError",
+ );
+ }
+
+ this[_mapMode] = mode;
+ this[_state] = "mapping pending";
+ const { err } = await core.jsonOpAsync(
+ "op_webgpu_buffer_get_map_async",
+ {
+ bufferRid,
+ deviceRid: device.rid,
+ mode,
+ offset,
+ size: rangeSize,
+ },
+ );
+ device.pushError(err);
+ this[_state] = "mapped";
+ this[_mappingRange] = [offset, offset + rangeSize];
+ /** @type {[ArrayBuffer, number, number][] | null} */
+ this[_mappedRanges] = [];
+ }
+
+ /**
+ * @param {number} offset
+ * @param {number} size
+ */
+ getMappedRange(offset = 0, size) {
+ webidl.assertBranded(this, GPUBuffer);
+ const prefix = "Failed to execute 'getMappedRange' on 'GPUBuffer'";
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 1",
+ });
+ size = size === undefined
+ ? undefined
+ : webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ /** @type {number} */
+ let rangeSize;
+ if (size === undefined) {
+ rangeSize = Math.max(0, this[_size] - offset);
+ } else {
+ rangeSize = this[_size];
+ }
+ if (this[_state] !== "mapped" && this[_state] !== "mapped at creation") {
+ throw new DOMException(
+ `${prefix}: buffer is not mapped.`,
+ "OperationError",
+ );
+ }
+ if ((offset % 8) !== 0) {
+ throw new DOMException(
+ `${prefix}: offset must be a multiple of 8.`,
+ "OperationError",
+ );
+ }
+ if ((rangeSize % 4) !== 0) {
+ throw new DOMException(
+ `${prefix}: rangeSize must be a multiple of 4.`,
+ "OperationError",
+ );
+ }
+ const mappingRange = this[_mappingRange];
+ if (!mappingRange) {
+ throw new DOMException(`${prefix}: invalid state.`, "OperationError");
+ }
+ if (offset < mappingRange[0]) {
+ throw new DOMException(
+ `${prefix}: offset is out of bounds.`,
+ "OperationError",
+ );
+ }
+ if ((offset + rangeSize) > mappingRange[1]) {
+ throw new DOMException(
+ `${prefix}: offset is out of bounds.`,
+ "OperationError",
+ );
+ }
+ const mappedRanges = this[_mappedRanges];
+ if (!mappedRanges) {
+ throw new DOMException(`${prefix}: invalid state.`, "OperationError");
+ }
+ for (const [buffer, _rid, start] of mappedRanges) {
+ // TODO(lucacasonato): is this logic correct?
+ const end = start + buffer.byteLength;
+ if (
+ (start >= offset && start < (offset + rangeSize)) ||
+ (end >= offset && end < (offset + rangeSize))
+ ) {
+ throw new DOMException(
+ `${prefix}: requested buffer overlaps with another mapped range.`,
+ "OperationError",
+ );
+ }
+ }
+
+ const buffer = new ArrayBuffer(rangeSize);
+ const { rid } = core.jsonOpSync(
+ "op_webgpu_buffer_get_mapped_range",
+ {
+ bufferRid,
+ offset: offset - mappingRange[0],
+ size: rangeSize,
+ },
+ new Uint8Array(buffer),
+ );
+
+ mappedRanges.push([buffer, rid, offset]);
+
+ return buffer;
+ }
+
+ unmap() {
+ webidl.assertBranded(this, GPUBuffer);
+ const prefix = "Failed to execute 'unmap' on 'GPUBuffer'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const bufferRid = assertResource(this, { prefix, context: "this" });
+ if (this[_state] === "unmapped" || this[_state] === "destroyed") {
+ throw new DOMException(
+ `${prefix}: buffer is not ready to be unmapped.`,
+ "OperationError",
+ );
+ }
+ if (this[_state] === "mapping pending") {
+ // TODO(lucacasonato): this is not spec compliant.
+ throw new DOMException(
+ `${prefix}: can not unmap while mapping. This is a Deno limitation.`,
+ "OperationError",
+ );
+ } else if (
+ this[_state] === "mapped" || this[_state] === "mapped at creation"
+ ) {
+ /** @type {boolean} */
+ let write = false;
+ if (this[_state] === "mapped at creation") {
+ write = true;
+ } else if (this[_state] === "mapped") {
+ const mapMode = this[_mapMode];
+ if (mapMode === undefined) {
+ throw new DOMException(
+ `${prefix}: invalid state.`,
+ "OperationError",
+ );
+ }
+ if ((mapMode & 0x0002) === 0x0002) {
+ write = true;
+ }
+ }
+
+ const mappedRanges = this[_mappedRanges];
+ if (!mappedRanges) {
+ throw new DOMException(`${prefix}: invalid state.`, "OperationError");
+ }
+ for (const [buffer, mappedRid] of mappedRanges) {
+ const { err } = core.jsonOpSync("op_webgpu_buffer_unmap", {
+ bufferRid,
+ mappedRid,
+ }, ...(write ? [new Uint8Array(buffer)] : []));
+ device.pushError(err);
+ if (err) return;
+ }
+ this[_mappingRange] = null;
+ this[_mappedRanges] = null;
+ }
+
+ this[_state] = "unmapped";
+ }
+
+ destroy() {
+ webidl.assertBranded(this, GPUBuffer);
+ this[_cleanup]();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUBuffer", GPUBuffer);
+
+ class GPUBufferUsage {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get MAP_READ() {
+ return 0x0001;
+ }
+ static get MAP_WRITE() {
+ return 0x0002;
+ }
+ static get COPY_SRC() {
+ return 0x0004;
+ }
+ static get COPY_DST() {
+ return 0x0008;
+ }
+ static get INDEX() {
+ return 0x0010;
+ }
+ static get VERTEX() {
+ return 0x0020;
+ }
+ static get UNIFORM() {
+ return 0x0040;
+ }
+ static get STORAGE() {
+ return 0x0080;
+ }
+ static get INDIRECT() {
+ return 0x0100;
+ }
+ static get QUERY_RESOLVE() {
+ return 0x0200;
+ }
+ }
+
+ class GPUMapMode {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get READ() {
+ return 0x0001;
+ }
+ static get WRITE() {
+ return 0x0002;
+ }
+ }
+
+ const _views = Symbol("[[views]]");
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUTexture}
+ */
+ function createGPUTexture(label, device, rid) {
+ /** @type {GPUTexture} */
+ const texture = webidl.createBranded(GPUTexture);
+ texture[_label] = label;
+ texture[_device] = device;
+ texture[_rid] = rid;
+ texture[_views] = [];
+ return texture;
+ }
+
+ class GPUTexture {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {WeakRef<GPUTextureView>[]} */
+ [_views];
+
+ [_cleanup]() {
+ const views = this[_views];
+ while (views.length > 0) {
+ const view = views.pop()?.deref();
+ if (view) {
+ view[_cleanup]();
+ }
+ }
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPUTextureViewDescriptor} descriptor
+ */
+ createView(descriptor = {}) {
+ webidl.assertBranded(this, GPUTexture);
+ const prefix = "Failed to execute 'createView' on 'GPUTexture'";
+ webidl.requiredArguments(arguments.length, 0, { prefix });
+ descriptor = webidl.converters.GPUTextureViewDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const textureRid = assertResource(this, { prefix, context: "this" });
+ const { rid, err } = core.jsonOpSync("op_webgpu_create_texture_view", {
+ textureRid,
+ ...descriptor,
+ });
+ device.pushError(err);
+
+ const textureView = createGPUTextureView(
+ descriptor.label ?? null,
+ this,
+ rid,
+ );
+ this[_views].push(new WeakRef(textureView));
+ return textureView;
+ }
+
+ destroy() {
+ webidl.assertBranded(this, GPUTexture);
+ this[_cleanup]();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUTexture", GPUTexture);
+
+ class GPUTextureUsage {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get COPY_SRC() {
+ return 0x01;
+ }
+ static get COPY_DST() {
+ return 0x02;
+ }
+ static get SAMPLED() {
+ return 0x04;
+ }
+ static get STORAGE() {
+ return 0x08;
+ }
+ static get RENDER_ATTACHMENT() {
+ return 0x10;
+ }
+ }
+
+ const _texture = Symbol("[[texture]]");
+
+ /**
+ * @param {string | null} label
+ * @param {GPUTexture} texture
+ * @param {number} rid
+ * @returns {GPUTextureView}
+ */
+ function createGPUTextureView(label, texture, rid) {
+ /** @type {GPUTextureView} */
+ const textureView = webidl.createBranded(GPUTextureView);
+ textureView[_label] = label;
+ textureView[_texture] = texture;
+ textureView[_rid] = rid;
+ return textureView;
+ }
+ class GPUTextureView {
+ /** @type {GPUTexture} */
+ [_texture];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUTextureView", GPUTextureView);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUSampler}
+ */
+ function createGPUSampler(label, device, rid) {
+ /** @type {GPUSampler} */
+ const sampler = webidl.createBranded(GPUSampler);
+ sampler[_label] = label;
+ sampler[_device] = device;
+ sampler[_rid] = rid;
+ return sampler;
+ }
+ class GPUSampler {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUSampler", GPUSampler);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUBindGroupLayout}
+ */
+ function createGPUBindGroupLayout(label, device, rid) {
+ /** @type {GPUBindGroupLayout} */
+ const bindGroupLayout = webidl.createBranded(GPUBindGroupLayout);
+ bindGroupLayout[_label] = label;
+ bindGroupLayout[_device] = device;
+ bindGroupLayout[_rid] = rid;
+ return bindGroupLayout;
+ }
+ class GPUBindGroupLayout {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUBindGroupLayout", GPUBindGroupLayout);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUPipelineLayout}
+ */
+ function createGPUPipelineLayout(label, device, rid) {
+ /** @type {GPUPipelineLayout} */
+ const pipelineLayout = webidl.createBranded(GPUPipelineLayout);
+ pipelineLayout[_label] = label;
+ pipelineLayout[_device] = device;
+ pipelineLayout[_rid] = rid;
+ return pipelineLayout;
+ }
+ class GPUPipelineLayout {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUPipelineLayout", GPUPipelineLayout);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUBindGroup}
+ */
+ function createGPUBindGroup(label, device, rid) {
+ /** @type {GPUBindGroup} */
+ const bindGroup = webidl.createBranded(GPUBindGroup);
+ bindGroup[_label] = label;
+ bindGroup[_device] = device;
+ bindGroup[_rid] = rid;
+ return bindGroup;
+ }
+ class GPUBindGroup {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUBindGroup", GPUBindGroup);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUShaderModule}
+ */
+ function createGPUShaderModule(label, device, rid) {
+ /** @type {GPUShaderModule} */
+ const bindGroup = webidl.createBranded(GPUShaderModule);
+ bindGroup[_label] = label;
+ bindGroup[_device] = device;
+ bindGroup[_rid] = rid;
+ return bindGroup;
+ }
+ class GPUShaderModule {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ compilationInfo() {
+ throw new Error("Not yet implemented");
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUShaderModule", GPUShaderModule);
+
+ class GPUShaderStage {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get VERTEX() {
+ return 0x1;
+ }
+
+ static get FRAGMENT() {
+ return 0x2;
+ }
+
+ static get COMPUTE() {
+ return 0x4;
+ }
+ }
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUComputePipeline}
+ */
+ function createGPUComputePipeline(label, device, rid) {
+ /** @type {GPUComputePipeline} */
+ const pipeline = webidl.createBranded(GPUComputePipeline);
+ pipeline[_label] = label;
+ pipeline[_device] = device;
+ pipeline[_rid] = rid;
+ return pipeline;
+ }
+ class GPUComputePipeline {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {number} index
+ * @returns {GPUBindGroupLayout}
+ */
+ getBindGroupLayout(index) {
+ webidl.assertBranded(this, GPURenderPipeline);
+ const prefix =
+ "Failed to execute 'getBindGroupLayout' on 'GPUComputePipeline'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ index = webidl.converters["unsigned long"](index, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const computePipelineRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, label, err } = core.jsonOpSync(
+ "op_webgpu_compute_pipeline_get_bind_group_layout",
+ { computePipelineRid, index },
+ );
+ device.pushError(err);
+
+ const bindGroupLayout = createGPUBindGroupLayout(
+ label,
+ device,
+ rid,
+ );
+ device.trackResource((bindGroupLayout));
+ return bindGroupLayout;
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUComputePipeline", GPUComputePipeline);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderPipeline}
+ */
+ function createGPURenderPipeline(label, device, rid) {
+ /** @type {GPURenderPipeline} */
+ const pipeline = webidl.createBranded(GPURenderPipeline);
+ pipeline[_label] = label;
+ pipeline[_device] = device;
+ pipeline[_rid] = rid;
+ return pipeline;
+ }
+ class GPURenderPipeline {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {number} index
+ */
+ getBindGroupLayout(index) {
+ webidl.assertBranded(this, GPURenderPipeline);
+ const prefix =
+ "Failed to execute 'getBindGroupLayout' on 'GPURenderPipeline'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ index = webidl.converters["unsigned long"](index, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderPipelineRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, label, err } = core.jsonOpSync(
+ "op_webgpu_render_pipeline_get_bind_group_layout",
+ { renderPipelineRid, index },
+ );
+ device.pushError(err);
+
+ const bindGroupLayout = createGPUBindGroupLayout(
+ label,
+ device,
+ rid,
+ );
+ device.trackResource((bindGroupLayout));
+ return bindGroupLayout;
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPURenderPipeline", GPURenderPipeline);
+
+ class GPUColorWrite {
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ static get RED() {
+ return 0x1;
+ }
+ static get GREEN() {
+ return 0x2;
+ }
+ static get BLUE() {
+ return 0x4;
+ }
+ static get ALPHA() {
+ return 0x8;
+ }
+ static get ALL() {
+ return 0xF;
+ }
+ }
+
+ const _encoders = Symbol("[[encoders]]");
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUCommandEncoder}
+ */
+ function createGPUCommandEncoder(label, device, rid) {
+ /** @type {GPUCommandEncoder} */
+ const encoder = webidl.createBranded(GPUCommandEncoder);
+ encoder[_label] = label;
+ encoder[_device] = device;
+ encoder[_rid] = rid;
+ encoder[_encoders] = [];
+ return encoder;
+ }
+ class GPUCommandEncoder {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {WeakRef<GPURenderPassEncoder | GPUComputePassEncoder>[]} */
+ [_encoders];
+
+ [_cleanup]() {
+ const encoders = this[_encoders];
+ while (encoders.length > 0) {
+ const encoder = encoders.pop()?.deref();
+ if (encoder) {
+ encoder[_cleanup]();
+ }
+ }
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPURenderPassDescriptor} descriptor
+ * @return {GPURenderPassEncoder}
+ */
+ beginRenderPass(descriptor) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ descriptor = webidl.converters.GPURenderPassDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+
+ if (this[_rid] === undefined) {
+ throw new DOMException(
+ "Failed to execute 'beginRenderPass' on 'GPUCommandEncoder': already consumed",
+ "OperationError",
+ );
+ }
+
+ let depthStencilAttachment;
+ if (descriptor.depthStencilAttachment) {
+ const view = assertResource(descriptor.depthStencilAttachment.view, {
+ prefix,
+ context: "texture view for depth stencil attachment",
+ });
+ assertDeviceMatch(
+ device,
+ descriptor.depthStencilAttachment.view[_texture],
+ {
+ prefix,
+ resourceContext: "texture view for depth stencil attachment",
+ selfContext: "this",
+ },
+ );
+
+ depthStencilAttachment = {
+ ...descriptor.depthStencilAttachment,
+ view,
+ };
+
+ if (
+ typeof descriptor.depthStencilAttachment.depthLoadValue === "string"
+ ) {
+ depthStencilAttachment.depthLoadOp =
+ descriptor.depthStencilAttachment.depthLoadValue;
+ } else {
+ depthStencilAttachment.depthLoadOp = "clear";
+ depthStencilAttachment.depthLoadValue =
+ descriptor.depthStencilAttachment.depthLoadValue;
+ }
+
+ if (
+ typeof descriptor.depthStencilAttachment.stencilLoadValue === "string"
+ ) {
+ depthStencilAttachment.stencilLoadOp =
+ descriptor.depthStencilAttachment.stencilLoadValue;
+ depthStencilAttachment.stencilLoadValue = undefined;
+ } else {
+ depthStencilAttachment.stencilLoadOp = "clear";
+ depthStencilAttachment.stencilLoadValue =
+ descriptor.depthStencilAttachment.stencilLoadValue;
+ }
+ }
+ const colorAttachments = descriptor.colorAttachments.map(
+ (colorAttachment, i) => {
+ const context = `color attachment ${i + 1}`;
+ const view = assertResource(colorAttachment.view, {
+ prefix,
+ context: `texture view for ${context}`,
+ });
+ assertResource(colorAttachment.view[_texture], {
+ prefix,
+ context: `texture backing texture view for ${context}`,
+ });
+ assertDeviceMatch(
+ device,
+ colorAttachment.view[_texture],
+ {
+ prefix,
+ resourceContext: `texture view for ${context}`,
+ selfContext: "this",
+ },
+ );
+ let resolveTarget;
+ if (colorAttachment.resolveTarget) {
+ resolveTarget = assertResource(
+ colorAttachment.resolveTarget,
+ {
+ prefix,
+ context: `resolve target texture view for ${context}`,
+ },
+ );
+ assertResource(colorAttachment.resolveTarget[_texture], {
+ prefix,
+ context:
+ `texture backing resolve target texture view for ${context}`,
+ });
+ assertDeviceMatch(
+ device,
+ colorAttachment.resolveTarget[_texture],
+ {
+ prefix,
+ resourceContext: `resolve target texture view for ${context}`,
+ selfContext: "this",
+ },
+ );
+ }
+ const attachment = {
+ view: view,
+ resolveTarget,
+ storeOp: colorAttachment.storeOp,
+ };
+
+ if (typeof colorAttachment.loadValue === "string") {
+ attachment.loadOp = colorAttachment.loadValue;
+ } else {
+ attachment.loadOp = "clear";
+ attachment.loadValue = normalizeGPUColor(
+ colorAttachment.loadValue,
+ );
+ }
+
+ return attachment;
+ },
+ );
+
+ const { rid } = core.jsonOpSync(
+ "op_webgpu_command_encoder_begin_render_pass",
+ {
+ commandEncoderRid,
+ ...descriptor,
+ colorAttachments,
+ depthStencilAttachment,
+ },
+ );
+
+ const renderPassEncoder = createGPURenderPassEncoder(
+ descriptor.label ?? null,
+ this,
+ rid,
+ );
+ this[_encoders].push(new WeakRef(renderPassEncoder));
+ return renderPassEncoder;
+ }
+
+ /**
+ * @param {GPUComputePassDescriptor} descriptor
+ */
+ beginComputePass(descriptor = {}) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'beginComputePass' on 'GPUCommandEncoder'";
+ descriptor = webidl.converters.GPUComputePassDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+
+ const { rid } = core.jsonOpSync(
+ "op_webgpu_command_encoder_begin_compute_pass",
+ {
+ commandEncoderRid,
+ ...descriptor,
+ },
+ );
+
+ const computePassEncoder = createGPUComputePassEncoder(
+ descriptor.label ?? null,
+ this,
+ rid,
+ );
+ this[_encoders].push(new WeakRef(computePassEncoder));
+ return computePassEncoder;
+ }
+
+ /**
+ * @param {GPUBuffer} source
+ * @param {number} sourceOffset
+ * @param {GPUBuffer} destination
+ * @param {number} destinationOffset
+ * @param {number} size
+ */
+ copyBufferToBuffer(
+ source,
+ sourceOffset,
+ destination,
+ destinationOffset,
+ size,
+ ) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'copyBufferToBuffer' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ source = webidl.converters.GPUBuffer(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ sourceOffset = webidl.converters.GPUSize64(sourceOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ destination = webidl.converters.GPUBuffer(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
+ prefix,
+ context: "Argument 4",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 5",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceRid = assertResource(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, source, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const destinationRid = assertResource(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ assertDeviceMatch(device, destination, {
+ prefix,
+ resourceContext: "Argument 3",
+ selfContext: "this",
+ });
+
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_copy_buffer_to_buffer",
+ {
+ commandEncoderRid,
+ source: sourceRid,
+ sourceOffset,
+ destination: destinationRid,
+ destinationOffset,
+ size,
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUImageCopyBuffer} source
+ * @param {GPUImageCopyTexture} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyBufferToTexture(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'copyBufferToTexture' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyBuffer(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceBufferRid = assertResource(source.buffer, {
+ prefix,
+ context: "source in Argument 1",
+ });
+ assertDeviceMatch(device, source.buffer, {
+ prefix,
+ resourceContext: "source in Argument 1",
+ selfContext: "this",
+ });
+ const destinationTextureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture in Argument 2",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ resourceContext: "texture in Argument 2",
+ selfContext: "this",
+ });
+
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_copy_buffer_to_texture",
+ {
+ commandEncoderRid,
+ source: {
+ ...source,
+ buffer: sourceBufferRid,
+ },
+ destination: {
+ texture: destinationTextureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ },
+ copySize: normalizeGPUExtent3D(copySize),
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUImageCopyTexture} source
+ * @param {GPUImageCopyBuffer} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyTextureToBuffer(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'copyTextureToBuffer' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyTexture(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyBuffer(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceTextureRid = assertResource(source.texture, {
+ prefix,
+ context: "texture in Argument 1",
+ });
+ assertDeviceMatch(device, source.texture, {
+ prefix,
+ resourceContext: "texture in Argument 1",
+ selfContext: "this",
+ });
+ const destinationBufferRid = assertResource(destination.buffer, {
+ prefix,
+ context: "buffer in Argument 2",
+ });
+ assertDeviceMatch(device, destination.buffer, {
+ prefix,
+ resourceContext: "buffer in Argument 2",
+ selfContext: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_copy_texture_to_buffer",
+ {
+ commandEncoderRid,
+ source: {
+ texture: sourceTextureRid,
+ mipLevel: source.mipLevel,
+ origin: source.origin
+ ? normalizeGPUOrigin3D(source.origin)
+ : undefined,
+ },
+ destination: {
+ ...destination,
+ buffer: destinationBufferRid,
+ },
+ copySize: normalizeGPUExtent3D(copySize),
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUImageCopyTexture} source
+ * @param {GPUImageCopyTexture} destination
+ * @param {GPUExtent3D} copySize
+ */
+ copyTextureToTexture(source, destination, copySize) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'copyTextureToTexture' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ source = webidl.converters.GPUImageCopyTexture(source, {
+ prefix,
+ context: "Argument 1",
+ });
+ destination = webidl.converters.GPUImageCopyTexture(destination, {
+ prefix,
+ context: "Argument 2",
+ });
+ copySize = webidl.converters.GPUExtent3D(copySize, {
+ prefix,
+ context: "Argument 3",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const sourceTextureRid = assertResource(source.texture, {
+ prefix,
+ context: "texture in Argument 1",
+ });
+ assertDeviceMatch(device, source.texture, {
+ prefix,
+ resourceContext: "texture in Argument 1",
+ selfContext: "this",
+ });
+ const destinationTextureRid = assertResource(destination.texture, {
+ prefix,
+ context: "texture in Argument 2",
+ });
+ assertDeviceMatch(device, destination.texture, {
+ prefix,
+ resourceContext: "texture in Argument 2",
+ selfContext: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_copy_texture_to_texture",
+ {
+ commandEncoderRid,
+ source: {
+ texture: sourceTextureRid,
+ mipLevel: source.mipLevel,
+ origin: source.origin
+ ? normalizeGPUOrigin3D(source.origin)
+ : undefined,
+ },
+ destination: {
+ texture: destinationTextureRid,
+ mipLevel: destination.mipLevel,
+ origin: destination.origin
+ ? normalizeGPUOrigin3D(destination.origin)
+ : undefined,
+ },
+ copySize: normalizeGPUExtent3D(copySize),
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_push_debug_group",
+ {
+ commandEncoderRid,
+ groupLabel,
+ },
+ );
+ device.pushError(err);
+ }
+
+ popDebugGroup() {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix = "Failed to execute 'popDebugGroup' on 'GPUCommandEncoder'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_pop_debug_group",
+ {
+ commandEncoderRid,
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_insert_debug_marker",
+ {
+ commandEncoderRid,
+ markerLabel,
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'writeTimestamp' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_write_timestamp",
+ {
+ commandEncoderRid,
+ querySet: querySetRid,
+ queryIndex,
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} firstQuery
+ * @param {number} queryCount
+ * @param {GPUBuffer} destination
+ * @param {number} destinationOffset
+ */
+ resolveQuerySet(
+ querySet,
+ firstQuery,
+ queryCount,
+ destination,
+ destinationOffset,
+ ) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix =
+ "Failed to execute 'resolveQuerySet' on 'GPUCommandEncoder'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ firstQuery = webidl.converters.GPUSize32(firstQuery, {
+ prefix,
+ context: "Argument 2",
+ });
+ queryCount = webidl.converters.GPUSize32(queryCount, {
+ prefix,
+ context: "Argument 3",
+ });
+ destination = webidl.converters.GPUQuerySet(destination, {
+ prefix,
+ context: "Argument 4",
+ });
+ destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
+ prefix,
+ context: "Argument 5",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ const destinationRid = assertResource(destination, {
+ prefix,
+ context: "Argument 3",
+ });
+ assertDeviceMatch(device, destination, {
+ prefix,
+ resourceContext: "Argument 3",
+ selfContext: "this",
+ });
+ const { err } = core.jsonOpSync(
+ "op_webgpu_command_encoder_resolve_query_set",
+ {
+ commandEncoderRid,
+ querySet: querySetRid,
+ firstQuery,
+ queryCount,
+ destination: destinationRid,
+ destinationOffset,
+ },
+ );
+ device.pushError(err);
+ }
+
+ /**
+ * @param {GPUCommandBufferDescriptor} descriptor
+ * @returns {GPUCommandBuffer}
+ */
+ finish(descriptor = {}) {
+ webidl.assertBranded(this, GPUCommandEncoder);
+ const prefix = "Failed to execute 'finish' on 'GPUCommandEncoder'";
+ descriptor = webidl.converters.GPUCommandBufferDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const commandEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, err } = core.jsonOpSync("op_webgpu_command_encoder_finish", {
+ commandEncoderRid,
+ ...descriptor,
+ });
+ device.pushError(err);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+
+ const commandBuffer = createGPUCommandBuffer(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((commandBuffer));
+ return commandBuffer;
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUCommandEncoder", GPUCommandEncoder);
+
+ const _encoder = Symbol("[[encoder]]");
+
+ /**
+ * @param {string | null} label
+ * @param {GPUCommandEncoder} encoder
+ * @param {number} rid
+ * @returns {GPURenderPassEncoder}
+ */
+ function createGPURenderPassEncoder(label, encoder, rid) {
+ /** @type {GPURenderPassEncoder} */
+ const passEncoder = webidl.createBranded(GPURenderPassEncoder);
+ passEncoder[_label] = label;
+ passEncoder[_encoder] = encoder;
+ passEncoder[_rid] = rid;
+ return passEncoder;
+ }
+
+ class GPURenderPassEncoder {
+ /** @type {GPUCommandEncoder} */
+ [_encoder];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} minDepth
+ * @param {number} maxDepth
+ */
+ setViewport(x, y, width, height, minDepth, maxDepth) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setViewport' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 6, { prefix });
+ x = webidl.converters.float(x, { prefix, context: "Argument 1" });
+ y = webidl.converters.float(y, { prefix, context: "Argument 2" });
+ width = webidl.converters.float(width, { prefix, context: "Argument 3" });
+ height = webidl.converters.float(height, {
+ prefix,
+ context: "Argument 4",
+ });
+ minDepth = webidl.converters.float(minDepth, {
+ prefix,
+ context: "Argument 5",
+ });
+ maxDepth = webidl.converters.float(maxDepth, {
+ prefix,
+ context: "Argument 6",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_set_viewport", {
+ renderPassRid,
+ x,
+ y,
+ width,
+ height,
+ minDepth,
+ maxDepth,
+ });
+ }
+
+ /**
+ *
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ setScissorRect(x, y, width, height) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setScissorRect' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 4, { prefix });
+ x = webidl.converters.GPUIntegerCoordinate(x, {
+ prefix,
+ context: "Argument 1",
+ });
+ y = webidl.converters.GPUIntegerCoordinate(y, {
+ prefix,
+ context: "Argument 2",
+ });
+ width = webidl.converters.GPUIntegerCoordinate(width, {
+ prefix,
+ context: "Argument 3",
+ });
+ height = webidl.converters.GPUIntegerCoordinate(height, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_set_scissor_rect", {
+ renderPassRid,
+ x,
+ y,
+ width,
+ height,
+ });
+ }
+
+ /**
+ * @param {GPUColor} color
+ */
+ setBlendColor(color) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setBlendColor' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ color = webidl.converters.GPUColor(color, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_set_blend_color", {
+ renderPassRid,
+ color: normalizeGPUColor(color),
+ });
+ }
+
+ /**
+ * @param {number} reference
+ */
+ setStencilReference(reference) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setStencilReference' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ reference = webidl.converters.GPUStencilValue(reference, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_set_stencil_reference", {
+ renderPassRid,
+ reference,
+ });
+ }
+
+ beginOcclusionQuery(_queryIndex) {
+ throw new Error("Not yet implemented");
+ }
+
+ endOcclusionQuery() {
+ throw new Error("Not yet implemented");
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ beginPipelineStatisticsQuery(querySet, queryIndex) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'beginPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_begin_pipeline_statistics_query", {
+ renderPassRid,
+ querySet: querySetRid,
+ queryIndex,
+ });
+ }
+
+ endPipelineStatisticsQuery() {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'endPipelineStatisticsQuery' on 'GPURenderPassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_end_pipeline_statistics_query", {
+ renderPassRid,
+ });
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'writeTimestamp' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_write_timestamp", {
+ renderPassRid,
+ querySet: querySetRid,
+ queryIndex,
+ });
+ }
+
+ /**
+ * @param {GPURenderBundle[]} bundles
+ */
+ executeBundles(bundles) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'executeBundles' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ bundles = webidl.converters["sequence<GPURenderBundle>"](bundles, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bundleRids = bundles.map((bundle, i) => {
+ const context = `bundle ${i + 1}`;
+ const rid = assertResource(bundle, { prefix, context });
+ assertDeviceMatch(device, bundle, {
+ prefix,
+ resourceContext: context,
+ selfContext: "this",
+ });
+ return rid;
+ });
+ core.jsonOpSync("op_webgpu_render_pass_execute_bundles", {
+ renderPassRid,
+ bundles: bundleRids,
+ });
+ }
+
+ endPass() {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix = "Failed to execute 'endPass' on 'GPURenderPassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const commandEncoderRid = assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const { err } = core.jsonOpSync("op_webgpu_render_pass_end_pass", {
+ commandEncoderRid,
+ renderPassRid,
+ });
+ device.pushError(err);
+ this[_rid] = undefined;
+ }
+
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setBindGroup' on 'GPURenderPassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (dynamicOffsetsData instanceof Uint32Array) {
+ core.jsonOpSync(
+ "op_webgpu_render_pass_set_bind_group",
+ {
+ renderPassRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ },
+ dynamicOffsetsData,
+ );
+ } else {
+ dynamicOffsetsData ??= [];
+ core.jsonOpSync("op_webgpu_render_pass_set_bind_group", {
+ renderPassRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart: 0,
+ dynamicOffsetsDataLength: dynamicOffsetsData.length,
+ });
+ }
+ }
+
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_push_debug_group", {
+ renderPassRid,
+ groupLabel,
+ });
+ }
+
+ popDebugGroup() {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPURenderPassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_pop_debug_group", {
+ renderPassRid,
+ });
+ }
+
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_insert_debug_marker", {
+ renderPassRid,
+ markerLabel,
+ });
+ }
+
+ /**
+ * @param {GPURenderPipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setPipeline' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPURenderPipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_set_pipeline", {
+ renderPassRid,
+ pipeline: pipelineRid,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {GPUIndexFormat} indexFormat
+ * @param {number} offset
+ * @param {number} size
+ */
+ setIndexBuffer(buffer, indexFormat, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setIndexBuffer' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_set_index_buffer", {
+ renderPassRid,
+ buffer: bufferRid,
+ indexFormat,
+ offset,
+ size,
+ });
+ }
+
+ /**
+ * @param {number} slot
+ * @param {GPUBuffer} buffer
+ * @param {number} offset
+ * @param {number} size
+ */
+ setVertexBuffer(slot, buffer, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'setVertexBuffer' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ slot = webidl.converters.GPUSize32(slot, {
+ prefix,
+ context: "Argument 2",
+ });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_set_vertex_buffer", {
+ renderPassRid,
+ slot,
+ buffer: bufferRid,
+ offset,
+ size,
+ });
+ }
+
+ /**
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix = "Failed to execute 'draw' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ vertexCount = webidl.converters.GPUSize32(vertexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstVertex = webidl.converters.GPUSize32(firstVertex, {
+ prefix,
+ context: "Argument 3",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_draw", {
+ renderPassRid,
+ vertexCount,
+ instanceCount,
+ firstVertex,
+ firstInstance,
+ });
+ }
+
+ /**
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ drawIndexed(
+ indexCount,
+ instanceCount = 1,
+ firstIndex = 0,
+ baseVertex = 0,
+ firstInstance = 0,
+ ) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'drawIndexed' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ indexCount = webidl.converters.GPUSize32(indexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstIndex = webidl.converters.GPUSize32(firstIndex, {
+ prefix,
+ context: "Argument 3",
+ });
+ baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
+ prefix,
+ context: "Argument 4",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 5",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_render_pass_draw_indexed", {
+ renderPassRid,
+ indexCount,
+ instanceCount,
+ firstIndex,
+ baseVertex,
+ firstInstance,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ drawIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_draw_indirect", {
+ renderPassRid,
+ indirectBuffer: indirectBufferRid,
+ indirectOffset,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ drawIndexedIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderPassEncoder);
+ const prefix =
+ "Failed to execute 'drawIndirect' on 'GPURenderPassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const renderPassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_pass_draw_indexed_indirect", {
+ renderPassRid,
+ indirectBuffer: indirectBufferRid,
+ indirectOffset,
+ });
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPURenderPassEncoder", GPURenderPassEncoder);
+
+ /**
+ * @param {string | null} label
+ * @param {GPUCommandEncoder} encoder
+ * @param {number} rid
+ * @returns {GPUComputePassEncoder}
+ */
+ function createGPUComputePassEncoder(label, encoder, rid) {
+ /** @type {GPUComputePassEncoder} */
+ const computePassEncoder = webidl.createBranded(GPUComputePassEncoder);
+ computePassEncoder[_label] = label;
+ computePassEncoder[_encoder] = encoder;
+ computePassEncoder[_rid] = rid;
+ return computePassEncoder;
+ }
+
+ class GPUComputePassEncoder {
+ /** @type {GPUCommandEncoder} */
+ [_encoder];
+
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPUComputePipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'setPipeline' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPUComputePipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_compute_pass_set_pipeline", {
+ computePassRid,
+ pipeline: pipelineRid,
+ });
+ }
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ */
+ dispatch(x, y = 1, z = 1) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix = "Failed to execute 'dispatch' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ x = webidl.converters.GPUSize32(x, { prefix, context: "Argument 1" });
+ y = webidl.converters.GPUSize32(y, { prefix, context: "Argument 2" });
+ z = webidl.converters.GPUSize32(z, { prefix, context: "Argument 3" });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_compute_pass_dispatch", {
+ computePassRid,
+ x,
+ y,
+ z,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ dispatchIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'dispatchIndirect' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_compute_pass_dispatch_indirect", {
+ computePassRid: computePassRid,
+ indirectBuffer: indirectBufferRid,
+ indirectOffset,
+ });
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ beginPipelineStatisticsQuery(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'beginPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync(
+ "op_webgpu_compute_pass_begin_pipeline_statistics_query",
+ {
+ computePassRid,
+ querySet: querySetRid,
+ queryIndex,
+ },
+ );
+ }
+
+ endPipelineStatisticsQuery() {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'endPipelineStatisticsQuery' on 'GPUComputePassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_compute_pass_end_pipeline_statistics_query", {
+ computePassRid,
+ });
+ }
+
+ /**
+ * @param {GPUQuerySet} querySet
+ * @param {number} queryIndex
+ */
+ writeTimestamp(querySet, queryIndex) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'writeTimestamp' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ querySet = webidl.converters.GPUQuerySet(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ queryIndex = webidl.converters.GPUSize32(queryIndex, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const querySetRid = assertResource(querySet, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, querySet, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_compute_pass_write_timestamp", {
+ computePassRid,
+ querySet: querySetRid,
+ queryIndex,
+ });
+ }
+
+ endPass() {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix = "Failed to execute 'endPass' on 'GPUComputePassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const commandEncoderRid = assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const { err } = core.jsonOpSync("op_webgpu_compute_pass_end_pass", {
+ commandEncoderRid,
+ computePassRid,
+ });
+ device.pushError(err);
+ this[_rid] = undefined;
+ }
+
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
+ const device = assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (dynamicOffsetsData instanceof Uint32Array) {
+ core.jsonOpSync(
+ "op_webgpu_compute_pass_set_bind_group",
+ {
+ computePassRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ },
+ dynamicOffsetsData,
+ );
+ } else {
+ dynamicOffsetsData ??= [];
+ core.jsonOpSync("op_webgpu_compute_pass_set_bind_group", {
+ computePassRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart: 0,
+ dynamicOffsetsDataLength: dynamicOffsetsData.length,
+ });
+ }
+ }
+
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_compute_pass_push_debug_group", {
+ computePassRid,
+ groupLabel,
+ });
+ }
+
+ popDebugGroup() {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPUComputePassEncoder'";
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_compute_pass_pop_debug_group", {
+ computePassRid,
+ });
+ }
+
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPUComputePassEncoder);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPUComputePassEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ assertResource(this[_encoder], {
+ prefix,
+ context: "encoder referenced by this",
+ });
+ const computePassRid = assertResource(this, { prefix, context: "this" });
+ core.jsonOpSync("op_webgpu_compute_pass_insert_debug_marker", {
+ computePassRid,
+ markerLabel,
+ });
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUComputePassEncoder", GPUComputePassEncoder);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUCommandBuffer}
+ */
+ function createGPUCommandBuffer(label, device, rid) {
+ /** @type {GPUCommandBuffer} */
+ const commandBuffer = webidl.createBranded(GPUCommandBuffer);
+ commandBuffer[_label] = label;
+ commandBuffer[_device] = device;
+ commandBuffer[_rid] = rid;
+ return commandBuffer;
+ }
+
+ class GPUCommandBuffer {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ get executionTime() {
+ throw new Error("Not yet implemented");
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ // TODO(crowlKats): executionTime
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUCommandBuffer", GPUCommandBuffer);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderBundleEncoder}
+ */
+ function createGPURenderBundleEncoder(label, device, rid) {
+ /** @type {GPURenderBundleEncoder} */
+ const bundleEncoder = webidl.createBranded(GPURenderBundleEncoder);
+ bundleEncoder[_label] = label;
+ bundleEncoder[_device] = device;
+ bundleEncoder[_rid] = rid;
+ return bundleEncoder;
+ }
+
+ class GPURenderBundleEncoder {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ /**
+ * @param {GPURenderBundleDescriptor} descriptor
+ */
+ finish(descriptor = {}) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix = "Failed to execute 'finish' on 'GPURenderBundleEncoder'";
+ descriptor = webidl.converters.GPURenderBundleDescriptor(descriptor, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const { rid, err } = core.jsonOpSync(
+ "op_webgpu_render_bundle_encoder_finish",
+ {
+ renderBundleEncoderRid,
+ ...descriptor,
+ },
+ );
+ device.pushError(err);
+ this[_rid] = undefined;
+
+ const renderBundle = createGPURenderBundle(
+ descriptor.label ?? null,
+ device,
+ rid,
+ );
+ device.trackResource((renderBundle));
+ return renderBundle;
+ }
+
+ // TODO(lucacasonato): has an overload
+ setBindGroup(
+ index,
+ bindGroup,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ ) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'setBindGroup' on 'GPURenderBundleEncoder'";
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bindGroupRid = assertResource(bindGroup, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, bindGroup, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ if (dynamicOffsetsData instanceof Uint32Array) {
+ core.jsonOpSync(
+ "op_webgpu_render_bundle_encoder_set_bind_group",
+ {
+ renderBundleEncoderRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsDataStart,
+ dynamicOffsetsDataLength,
+ },
+ dynamicOffsetsData,
+ );
+ } else {
+ dynamicOffsetsData ??= [];
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_set_bind_group", {
+ renderBundleEncoderRid,
+ index,
+ bindGroup: bindGroupRid,
+ dynamicOffsetsData,
+ dynamicOffsetsDataStart: 0,
+ dynamicOffsetsDataLength: dynamicOffsetsData.length,
+ });
+ }
+ }
+
+ /**
+ * @param {string} groupLabel
+ */
+ pushDebugGroup(groupLabel) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'pushDebugGroup' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ groupLabel = webidl.converters.USVString(groupLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_push_debug_group", {
+ renderBundleEncoderRid,
+ groupLabel,
+ });
+ }
+
+ popDebugGroup() {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'popDebugGroup' on 'GPURenderBundleEncoder'";
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_pop_debug_group", {
+ renderBundleEncoderRid,
+ });
+ }
+
+ /**
+ * @param {string} markerLabel
+ */
+ insertDebugMarker(markerLabel) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'insertDebugMarker' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ markerLabel = webidl.converters.USVString(markerLabel, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_push_debug_group", {
+ renderBundleEncoderRid,
+ markerLabel,
+ });
+ }
+
+ /**
+ * @param {GPURenderPipeline} pipeline
+ */
+ setPipeline(pipeline) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'setPipeline' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ pipeline = webidl.converters.GPURenderPipeline(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const pipelineRid = assertResource(pipeline, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, pipeline, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_set_pipeline", {
+ renderBundleEncoderRid,
+ pipeline: pipelineRid,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} buffer
+ * @param {GPUIndexFormat} indexFormat
+ * @param {number} offset
+ * @param {number} size
+ */
+ setIndexBuffer(buffer, indexFormat, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'setIndexBuffer' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indexFormat = webidl.converters.GPUIndexFormat(indexFormat, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_set_index_buffer", {
+ renderBundleEncoderRid,
+ buffer: bufferRid,
+ indexFormat,
+ offset,
+ size,
+ });
+ }
+
+ /**
+ * @param {number} slot
+ * @param {GPUBuffer} buffer
+ * @param {number} offset
+ * @param {number} size
+ */
+ setVertexBuffer(slot, buffer, offset = 0, size = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'setVertexBuffer' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ slot = webidl.converters.GPUSize32(slot, {
+ prefix,
+ context: "Argument 2",
+ });
+ buffer = webidl.converters.GPUBuffer(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ offset = webidl.converters.GPUSize64(offset, {
+ prefix,
+ context: "Argument 3",
+ });
+ size = webidl.converters.GPUSize64(size, {
+ prefix,
+ context: "Argument 4",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const bufferRid = assertResource(buffer, {
+ prefix,
+ context: "Argument 2",
+ });
+ assertDeviceMatch(device, buffer, {
+ prefix,
+ resourceContext: "Argument 2",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_set_vertex_buffer", {
+ renderBundleEncoderRid,
+ slot,
+ buffer: bufferRid,
+ offset,
+ size,
+ });
+ }
+
+ /**
+ * @param {number} vertexCount
+ * @param {number} instanceCount
+ * @param {number} firstVertex
+ * @param {number} firstInstance
+ */
+ draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix = "Failed to execute 'draw' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ vertexCount = webidl.converters.GPUSize32(vertexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstVertex = webidl.converters.GPUSize32(firstVertex, {
+ prefix,
+ context: "Argument 3",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 4",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_draw", {
+ renderBundleEncoderRid,
+ vertexCount,
+ instanceCount,
+ firstVertex,
+ firstInstance,
+ });
+ }
+
+ /**
+ * @param {number} indexCount
+ * @param {number} instanceCount
+ * @param {number} firstIndex
+ * @param {number} baseVertex
+ * @param {number} firstInstance
+ */
+ drawIndexed(
+ indexCount,
+ instanceCount = 1,
+ firstIndex = 0,
+ baseVertex = 0,
+ firstInstance = 0,
+ ) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'drawIndexed' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ indexCount = webidl.converters.GPUSize32(indexCount, {
+ prefix,
+ context: "Argument 1",
+ });
+ instanceCount = webidl.converters.GPUSize32(instanceCount, {
+ prefix,
+ context: "Argument 2",
+ });
+ firstIndex = webidl.converters.GPUSize32(firstIndex, {
+ prefix,
+ context: "Argument 3",
+ });
+ baseVertex = webidl.converters.GPUSignedOffset32(baseVertex, {
+ prefix,
+ context: "Argument 4",
+ });
+ firstInstance = webidl.converters.GPUSize32(firstInstance, {
+ prefix,
+ context: "Argument 5",
+ });
+ assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_draw_indexed", {
+ renderBundleEncoderRid,
+ indexCount,
+ instanceCount,
+ firstIndex,
+ baseVertex,
+ firstInstance,
+ });
+ }
+
+ /**
+ * @param {GPUBuffer} indirectBuffer
+ * @param {number} indirectOffset
+ */
+ drawIndirect(indirectBuffer, indirectOffset) {
+ webidl.assertBranded(this, GPURenderBundleEncoder);
+ const prefix =
+ "Failed to execute 'drawIndirect' on 'GPURenderBundleEncoder'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ indirectBuffer = webidl.converters.GPUBuffer(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ indirectOffset = webidl.converters.GPUSize64(indirectOffset, {
+ prefix,
+ context: "Argument 2",
+ });
+ const device = assertDevice(this, { prefix, context: "this" });
+ const renderBundleEncoderRid = assertResource(this, {
+ prefix,
+ context: "this",
+ });
+ const indirectBufferRid = assertResource(indirectBuffer, {
+ prefix,
+ context: "Argument 1",
+ });
+ assertDeviceMatch(device, indirectBuffer, {
+ prefix,
+ resourceContext: "Argument 1",
+ selfContext: "this",
+ });
+ core.jsonOpSync("op_webgpu_render_bundle_encoder_draw_indirect", {
+ renderBundleEncoderRid,
+ indirectBuffer: indirectBufferRid,
+ indirectOffset,
+ });
+ }
+
+ drawIndexedIndirect(_indirectBuffer, _indirectOffset) {
+ throw new Error("Not yet implemented");
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPURenderBundleEncoder", GPURenderBundleEncoder);
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPURenderBundle}
+ */
+ function createGPURenderBundle(label, device, rid) {
+ /** @type {GPURenderBundle} */
+ const bundle = webidl.createBranded(GPURenderBundle);
+ bundle[_label] = label;
+ bundle[_device] = device;
+ bundle[_rid] = rid;
+ return bundle;
+ }
+
+ class GPURenderBundle {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPURenderBundle", GPURenderBundle);
+
+ const _descriptor = Symbol("[[descriptor]]");
+
+ /**
+ * @param {string | null} label
+ * @param {InnerGPUDevice} device
+ * @param {number} rid
+ * @returns {GPUQuerySet}
+ */
+ function createGPUQuerySet(label, device, rid, descriptor) {
+ /** @type {GPUQuerySet} */
+ const queue = webidl.createBranded(GPUQuerySet);
+ queue[_label] = label;
+ queue[_device] = device;
+ queue[_rid] = rid;
+ queue[_descriptor] = descriptor;
+ return queue;
+ }
+
+ class GPUQuerySet {
+ /** @type {InnerGPUDevice} */
+ [_device];
+ /** @type {number | undefined} */
+ [_rid];
+ /** @type {GPUQuerySetDescriptor} */
+ [_descriptor];
+
+ [_cleanup]() {
+ const rid = this[_rid];
+ if (rid !== undefined) {
+ core.close(rid);
+ /** @type {number | undefined} */
+ this[_rid] = undefined;
+ }
+ }
+
+ constructor() {
+ webidl.illegalConstructor();
+ }
+
+ destroy() {
+ webidl.assertBranded(this, GPUQuerySet);
+ this[_cleanup]();
+ }
+
+ [Symbol.for("Deno.customInspect")](inspect) {
+ return `${this.constructor.name} ${
+ inspect({
+ label: this.label,
+ })
+ }`;
+ }
+ }
+ GPUObjectBaseMixin("GPUQuerySet", GPUQuerySet);
+
+ window.__bootstrap.webgpu = {
+ gpu: webidl.createBranded(GPU),
+ GPU,
+ GPUAdapter,
+ GPUAdapterLimits,
+ GPUAdapterFeatures,
+ GPUDevice,
+ GPUQueue,
+ GPUBuffer,
+ GPUBufferUsage,
+ GPUMapMode,
+ GPUTextureUsage,
+ GPUTexture,
+ GPUTextureView,
+ GPUSampler,
+ GPUBindGroupLayout,
+ GPUPipelineLayout,
+ GPUBindGroup,
+ GPUShaderModule,
+ GPUShaderStage,
+ GPUComputePipeline,
+ GPURenderPipeline,
+ GPUColorWrite,
+ GPUCommandEncoder,
+ GPURenderPassEncoder,
+ GPUComputePassEncoder,
+ GPUCommandBuffer,
+ GPURenderBundleEncoder,
+ GPURenderBundle,
+ GPUQuerySet,
+ GPUOutOfMemoryError,
+ GPUValidationError,
+ };
+})(this);