wgpu/deno_webgpu/01_webgpu.js

5124 lines
145 KiB
JavaScript
Raw Normal View History

// 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;
const { DOMException } = window.__bootstrap.domException;
const {
ArrayBuffer,
ArrayBufferIsView,
ArrayIsArray,
ArrayPrototypeFilter,
ArrayPrototypeMap,
ArrayPrototypePop,
ArrayPrototypePush,
Error,
MathMax,
ObjectDefineProperty,
ObjectFreeze,
Promise,
PromiseAll,
PromisePrototypeCatch,
PromisePrototypeThen,
PromiseReject,
PromiseResolve,
Set,
SetPrototypeEntries,
SetPrototypeForEach,
SetPrototypeHas,
SetPrototypeKeys,
SetPrototypeValues,
Symbol,
SymbolFor,
SymbolIterator,
TypeError,
Uint32Array,
Uint8Array,
} = window.__bootstrap.primordials;
/**
* @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 (ArrayIsArray(data)) {
return {
width: data[0],
height: data[1],
depthOrArrayLayers: data[2],
};
} else {
return data;
}
}
/**
* @param {number[] | GPUOrigin3DDict} data
* @returns {GPUOrigin3DDict}
*/
function normalizeGPUOrigin3D(data) {
if (ArrayIsArray(data)) {
return {
x: data[0],
y: data[1],
z: data[2],
};
} else {
return data;
}
}
/**
* @param {number[] | GPUColor} data
* @returns {GPUColor}
*/
function normalizeGPUColor(data) {
if (ArrayIsArray(data)) {
return {
r: data[0],
g: data[1],
b: data[2],
a: data[3],
};
} else {
return data;
}
}
class GPUOutOfMemoryError extends Error {
name = "GPUOutOfMemoryError";
constructor() {
super("device out of memory");
}
}
class GPUValidationError extends Error {
name = "GPUValidationError";
/** @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.opAsync(
"op_webgpu_request_adapter",
{ ...options },
);
if (err) {
return null;
} else {
return createGPUAdapter(data.name, data);
}
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect({})}`;
}
}
const _name = Symbol("[[name]]");
const _adapter = Symbol("[[adapter]]");
const _cleanup = Symbol("[[cleanup]]");
/**
* @typedef InnerGPUAdapter
* @property {number} rid
* @property {GPUSupportedFeatures} features
* @property {GPUSupportedLimits} limits
* @property {boolean} isFallbackAdapter
*/
/**
* @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: createGPUSupportedFeatures(inner.features),
limits: createGPUSupportedLimits(inner.limits),
};
return adapter;
}
class GPUAdapter {
/** @type {string} */
[_name];
/** @type {InnerGPUAdapter} */
[_adapter];
/** @returns {string} */
get name() {
webidl.assertBranded(this, GPUAdapter);
return this[_name];
}
/** @returns {GPUSupportedFeatures} */
get features() {
webidl.assertBranded(this, GPUAdapter);
return this[_adapter].features;
}
/** @returns {GPUSupportedLimits} */
get limits() {
webidl.assertBranded(this, GPUAdapter);
return this[_adapter].limits;
}
/** @returns {boolean} */
get isFallbackAdapter() {
return this[_adapter].isFallbackAdapter;
}
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 requiredFeatures = descriptor.requiredFeatures ?? [];
for (const feature of requiredFeatures) {
if (!SetPrototypeHas(this[_adapter].features[_features], feature)) {
throw new TypeError(
`${prefix}: nonGuaranteedFeatures must be a subset of the adapter features.`,
);
}
}
const requiredLimits = descriptor.requiredLimits;
// TODO(lucacasonato): validate requiredLimits
const { rid, features, limits } = await core.opAsync(
"op_webgpu_request_device",
{
adapterRid: this[_adapter].rid,
labe: descriptor.label,
requiredFeatures,
requiredLimits,
},
);
const inner = new InnerGPUDevice({
rid,
adapter: this,
features: ObjectFreeze(features),
limits: ObjectFreeze(limits),
});
return createGPUDevice(
descriptor.label ?? null,
inner,
createGPUQueue(descriptor.label ?? null, inner),
);
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${
inspect({
name: this.name,
features: this.features,
limits: this.limits,
})
}`;
}
}
const _limits = Symbol("[[limits]]");
function createGPUSupportedLimits(features) {
/** @type {GPUSupportedLimits} */
const adapterFeatures = webidl.createBranded(GPUSupportedLimits);
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} minUniformBufferOffsetAlignment
* @property {number} minStorageBufferOffsetAlignment
* @property {number} maxVertexBuffers
* @property {number} maxVertexAttributes
* @property {number} maxVertexBufferArrayStride
* @property {number} maxInterStageShaderComponents
* @property {number} maxComputeWorkgroupStorageSize
* @property {number} maxComputeInvocationsPerWorkgroup
* @property {number} maxComputeWorkgroupSizeX
* @property {number} maxComputeWorkgroupSizeY
* @property {number} maxComputeWorkgroupSizeZ
* @property {number} maxComputeWorkgroupsPerDimension
*/
class GPUSupportedLimits {
/** @type {InnerAdapterLimits} */
[_limits];
constructor() {
webidl.illegalConstructor();
}
get maxTextureDimension1D() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxTextureDimension1D;
}
get maxTextureDimension2D() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxTextureDimension2D;
}
get maxTextureDimension3D() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxTextureDimension3D;
}
get maxTextureArrayLayers() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxTextureArrayLayers;
}
get maxBindGroups() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxBindGroups;
}
get maxDynamicUniformBuffersPerPipelineLayout() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxDynamicUniformBuffersPerPipelineLayout;
}
get maxDynamicStorageBuffersPerPipelineLayout() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxDynamicStorageBuffersPerPipelineLayout;
}
get maxSampledTexturesPerShaderStage() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxSampledTexturesPerShaderStage;
}
get maxSamplersPerShaderStage() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxSamplersPerShaderStage;
}
get maxStorageBuffersPerShaderStage() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxStorageBuffersPerShaderStage;
}
get maxStorageTexturesPerShaderStage() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxStorageTexturesPerShaderStage;
}
get maxUniformBuffersPerShaderStage() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxUniformBuffersPerShaderStage;
}
get maxUniformBufferBindingSize() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxUniformBufferBindingSize;
}
get maxStorageBufferBindingSize() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxStorageBufferBindingSize;
}
get minUniformBufferOffsetAlignment() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].minUniformBufferOffsetAlignment;
}
get minStorageBufferOffsetAlignment() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].minStorageBufferOffsetAlignment;
}
get maxVertexBuffers() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxVertexBuffers;
}
get maxVertexAttributes() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxVertexAttributes;
}
get maxVertexBufferArrayStride() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxVertexBufferArrayStride;
}
get maxInterStageShaderComponents() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxInterStageShaderComponents;
}
get maxComputeWorkgroupStorageSize() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeWorkgroupStorageSize;
}
get maxComputeInvocationsPerWorkgroup() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeInvocationsPerWorkgroup;
}
get maxComputeWorkgroupSizeX() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeWorkgroupSizeX;
}
get maxComputeWorkgroupSizeY() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeWorkgroupSizeY;
}
get maxComputeWorkgroupSizeZ() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeWorkgroupSizeZ;
}
get maxComputeWorkgroupsPerDimension() {
webidl.assertBranded(this, GPUSupportedLimits);
return this[_limits].maxComputeWorkgroupsPerDimension;
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect(this[_limits])}`;
}
}
const _features = Symbol("[[features]]");
function createGPUSupportedFeatures(features) {
/** @type {GPUSupportedFeatures} */
const adapterFeatures = webidl.createBranded(GPUSupportedFeatures);
adapterFeatures[_features] = new Set(features);
return adapterFeatures;
}
class GPUSupportedFeatures {
/** @type {Set<string>} */
[_features];
constructor() {
webidl.illegalConstructor();
}
/** @return {IterableIterator<[string, string]>} */
entries() {
webidl.assertBranded(this, GPUSupportedFeatures);
return SetPrototypeEntries(this[_features]);
}
/** @return {void} */
forEach(callbackfn, thisArg) {
webidl.assertBranded(this, GPUSupportedFeatures);
SetPrototypeForEach(this[_features], callbackfn, thisArg);
}
/** @return {boolean} */
has(value) {
webidl.assertBranded(this, GPUSupportedFeatures);
return SetPrototypeHas(this[_features], value);
}
/** @return {IterableIterator<string>} */
keys() {
webidl.assertBranded(this, GPUSupportedFeatures);
return SetPrototypeKeys(this[_features]);
}
/** @return {IterableIterator<string>} */
values() {
webidl.assertBranded(this, GPUSupportedFeatures);
return SetPrototypeValues(this[_features]);
}
/** @return {number} */
get size() {
webidl.assertBranded(this, GPUSupportedFeatures);
return this[_features].size;
}
[SymbolIterator]() {
webidl.assertBranded(this, GPUSupportedFeatures);
return this[_features][SymbolIterator]();
}
[SymbolFor("Deno.privateCustomInspect")](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];
}
[SymbolFor("Deno.privateCustomInspect")](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;
ObjectDefineProperty(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 {Promise<void>[]} operations
*/
/**
* @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) {
ArrayPrototypePush(this.resources, new WeakRef(resource));
}
/** @param {{ type: string, value: string | null } | undefined} err */
pushError(err) {
this.pushErrorPromise(PromiseResolve(err));
}
/** @param {Promise<{ type: string, value: string | null } | undefined>} promise */
pushErrorPromise(promise) {
const operation = PromisePrototypeThen(promise, (err) => {
if (err) {
switch (err.type) {
case "lost":
this.isLost = true;
this.resolveLost(
createGPUDeviceLostInfo(undefined, "device was lost"),
);
break;
case "validation":
return PromiseReject(
new GPUValidationError(err.value ?? "validation error"),
);
case "out-of-memory":
return PromiseReject(new GPUOutOfMemoryError());
}
}
});
const validationStack = ArrayPrototypeFilter(
this.errorScopeStack,
({ filter }) => filter == "validation",
);
const validationScope = validationStack[validationStack.length - 1];
const validationFilteredPromise = PromisePrototypeCatch(
operation,
(err) => {
if (err instanceof GPUValidationError) return PromiseReject(err);
return PromiseResolve();
},
);
if (validationScope) {
ArrayPrototypePush(
validationScope.operations,
validationFilteredPromise,
);
} else {
PromisePrototypeCatch(validationFilteredPromise, () => {
// TODO(lucacasonato): emit an UncapturedErrorEvent
});
}
// prevent uncaptured promise rejections
PromisePrototypeCatch(validationFilteredPromise, (_err) => {});
const oomStack = ArrayPrototypeFilter(
this.errorScopeStack,
({ filter }) => filter == "out-of-memory",
);
const oomScope = oomStack[oomStack.length - 1];
const oomFilteredPromise = PromisePrototypeCatch(operation, (err) => {
if (err instanceof GPUOutOfMemoryError) return PromiseReject(err);
return PromiseResolve();
});
if (oomScope) {
ArrayPrototypePush(oomScope.operations, oomFilteredPromise);
} else {
PromisePrototypeCatch(oomFilteredPromise, () => {
// TODO(lucacasonato): emit an UncapturedErrorEvent
});
}
// prevent uncaptured promise rejections
PromisePrototypeCatch(oomFilteredPromise, (_err) => {});
}
}
/**
* @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 = ArrayPrototypePop(resources)?.deref();
if (resource) {
resource[_cleanup]();
}
}
const rid = device.rid;
if (rid !== undefined) {
core.close(rid);
/** @type {number | undefined} */
device.rid = undefined;
}
}
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.opSync("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.opSync("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.opSync("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.opSync(
"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 = ArrayPrototypeMap(
descriptor.bindGroupLayouts,
(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.opSync("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 = ArrayPrototypeMap(descriptor.entries, (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.opSync("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.opSync(
"op_webgpu_create_shader_module",
{
deviceRid: device.rid,
label: descriptor.label,
code: descriptor.code,
sourceMap: descriptor.sourceMap,
},
);
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.opSync(
"op_webgpu_create_compute_pipeline",
{
deviceRid: device.rid,
label: descriptor.label,
layout,
compute: {
module,
entryPoint: descriptor.compute.entryPoint,
constants: descriptor.compute.constants,
},
},
);
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.opSync("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 PromiseResolve(this.createComputePipeline(descriptor));
}
createRenderPipelineAsync(descriptor) {
// TODO(lucacasonato): this should be real async
return PromiseResolve(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.opSync("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.opSync(
"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.opSync("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 PromiseResolve(true);
}
if (device.rid === undefined) {
return PromiseResolve(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" });
ArrayPrototypePush(device.errorScopeStack, { filter, operations: [] });
}
/**
* @returns {Promise<GPUError | null>}
*/
// deno-lint-ignore require-await
async popErrorScope() {
webidl.assertBranded(this, GPUDevice);
const prefix = "Failed to execute 'popErrorScope' on 'GPUDevice'";
const device = assertDevice(this, { prefix, context: "this" });
if (device.isLost) {
throw new DOMException("Device has been lost.", "OperationError");
}
const scope = ArrayPrototypePop(device.errorScopeStack);
if (!scope) {
throw new DOMException(
"There are no error scopes on the error scope stack.",
"OperationError",
);
}
const operations = PromiseAll(scope.operations);
return PromisePrototypeThen(
operations,
() => PromiseResolve(null),
(err) => PromiseResolve(err),
);
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${
inspect({
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 = ArrayPrototypeMap(
commandBuffers,
(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.opSync("op_webgpu_queue_submit", {
queueRid: device.rid,
commandBuffers: commandBufferRids,
});
device.pushError(err);
}
onSubmittedWorkDone() {
webidl.assertBranded(this, GPUQueue);
return PromiseResolve();
}
/**
* @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.opSync(
"op_webgpu_write_buffer",
{
queueRid: device.rid,
buffer: bufferRid,
bufferOffset,
dataOffset,
size,
},
new Uint8Array(ArrayBufferIsView(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.opSync(
"op_webgpu_write_texture",
{
queueRid: device.rid,
destination: {
texture: textureRid,
mipLevel: destination.mipLevel,
origin: destination.origin
? normalizeGPUOrigin3D(destination.origin)
: undefined,
aspect: destination.aspect,
},
dataLayout,
size: normalizeGPUExtent3D(size),
},
new Uint8Array(ArrayBufferIsView(data) ? data.buffer : data),
);
device.pushError(err);
}
copyImageBitmapToTexture(_source, _destination, _copySize) {
throw new Error("Not yet implemented");
}
[SymbolFor("Deno.privateCustomInspect")](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 = ArrayPrototypePop(mappedRanges);
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 = MathMax(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 promise = PromisePrototypeThen(
core.opAsync(
"op_webgpu_buffer_get_map_async",
{
bufferRid,
deviceRid: device.rid,
mode,
offset,
size: rangeSize,
},
),
({ err }) => err,
);
device.pushErrorPromise(promise);
const err = await promise;
if (err) {
throw new DOMException("validation error occured", "OperationError");
}
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",
});
if (size !== undefined) {
size = 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 = MathMax(0, this[_size] - offset);
} else {
rangeSize = size;
}
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.opSync(
"op_webgpu_buffer_get_mapped_range",
{
bufferRid,
offset,
size,
},
new Uint8Array(buffer),
);
ArrayPrototypePush(mappedRanges, [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.opSync("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]();
}
[SymbolFor("Deno.privateCustomInspect")](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 = ArrayPrototypePop(views)?.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.opSync("op_webgpu_create_texture_view", {
textureRid,
...descriptor,
});
device.pushError(err);
const textureView = createGPUTextureView(
descriptor.label ?? null,
this,
rid,
);
ArrayPrototypePush(this[_views], new WeakRef(textureView));
return textureView;
}
destroy() {
webidl.assertBranded(this, GPUTexture);
this[_cleanup]();
}
[SymbolFor("Deno.privateCustomInspect")](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 TEXTURE_BINDING() {
return 0x04;
}
static get STORAGE_BINDING() {
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();
}
[SymbolFor("Deno.privateCustomInspect")](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();
}
[SymbolFor("Deno.privateCustomInspect")](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();
}
[SymbolFor("Deno.privateCustomInspect")](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();
}
[SymbolFor("Deno.privateCustomInspect")](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();
}
[SymbolFor("Deno.privateCustomInspect")](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");
}
[SymbolFor("Deno.privateCustomInspect")](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, GPUComputePipeline);
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.opSync(
"op_webgpu_compute_pipeline_get_bind_group_layout",
{ computePipelineRid, index },
);
device.pushError(err);
const bindGroupLayout = createGPUBindGroupLayout(
label,
device,
rid,
);
device.trackResource((bindGroupLayout));
return bindGroupLayout;
}
[SymbolFor("Deno.privateCustomInspect")](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.opSync(
"op_webgpu_render_pipeline_get_bind_group_layout",
{ renderPipelineRid, index },
);
device.pushError(err);
const bindGroupLayout = createGPUBindGroupLayout(
label,
device,
rid,
);
device.trackResource((bindGroupLayout));
return bindGroupLayout;
}
[SymbolFor("Deno.privateCustomInspect")](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 = ArrayPrototypePop(encoders)?.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: descriptor.depthStencilAttachment.depthLoadValue,
};
}
if (
typeof descriptor.depthStencilAttachment.stencilLoadValue === "string"
) {
depthStencilAttachment.stencilLoadOp =
descriptor.depthStencilAttachment.stencilLoadValue;
} else {
depthStencilAttachment.stencilLoadOp = {
clear: descriptor.depthStencilAttachment.stencilLoadValue,
};
}
}
const colorAttachments = ArrayPrototypeMap(
descriptor.colorAttachments,
(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: normalizeGPUColor(colorAttachment.loadValue),
};
}
return attachment;
},
);
const { rid } = core.opSync(
"op_webgpu_command_encoder_begin_render_pass",
{
commandEncoderRid,
...descriptor,
colorAttachments,
depthStencilAttachment,
},
);
const renderPassEncoder = createGPURenderPassEncoder(
descriptor.label ?? null,
this,
rid,
);
ArrayPrototypePush(this[_encoders], 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.opSync(
"op_webgpu_command_encoder_begin_compute_pass",
{
commandEncoderRid,
...descriptor,
},
);
const computePassEncoder = createGPUComputePassEncoder(
descriptor.label ?? null,
this,
rid,
);
ArrayPrototypePush(this[_encoders], 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.opSync(
"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.opSync(
"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,
aspect: destination.aspect,
},
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.opSync(
"op_webgpu_command_encoder_copy_texture_to_buffer",
{
commandEncoderRid,
source: {
texture: sourceTextureRid,
mipLevel: source.mipLevel,
origin: source.origin
? normalizeGPUOrigin3D(source.origin)
: undefined,
aspect: source.aspect,
},
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.opSync(
"op_webgpu_command_encoder_copy_texture_to_texture",
{
commandEncoderRid,
source: {
texture: sourceTextureRid,
mipLevel: source.mipLevel,
origin: source.origin
? normalizeGPUOrigin3D(source.origin)
: undefined,
aspect: source.aspect,
},
destination: {
texture: destinationTextureRid,
mipLevel: destination.mipLevel,
origin: destination.origin
? normalizeGPUOrigin3D(destination.origin)
: undefined,
aspect: source.aspect,
},
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.opSync(
"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.opSync(
"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.opSync(
"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.opSync(
"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.opSync(
"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.opSync("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;
}
[SymbolFor("Deno.privateCustomInspect")](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.opSync("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.opSync("op_webgpu_render_pass_set_scissor_rect", {
renderPassRid,
x,
y,
width,
height,
});
}
/**
* @param {GPUColor} color
*/
setBlendConstant(color) {
webidl.assertBranded(this, GPURenderPassEncoder);
const prefix =
"Failed to execute 'setBlendConstant' 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.opSync("op_webgpu_render_pass_set_blend_constant", {
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.opSync("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.opSync("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.opSync("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.opSync("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 = ArrayPrototypeMap(bundles, (bundle, i) => {
const context = `bundle ${i + 1}`;
const rid = assertResource(bundle, { prefix, context });
assertDeviceMatch(device, bundle, {
prefix,
resourceContext: context,
selfContext: "this",
});
return rid;
});
core.opSync("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.opSync("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)) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
core.opSync("op_webgpu_render_pass_set_bind_group", {
renderPassRid,
index,
bindGroup: bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
});
}
/**
* @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.opSync("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.opSync("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.opSync("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.opSync("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) {
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",
});
if (size !== undefined) {
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.opSync("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) {
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",
});
if (size !== undefined) {
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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("op_webgpu_render_pass_draw_indexed_indirect", {
renderPassRid,
indirectBuffer: indirectBufferRid,
indirectOffset,
});
}
[SymbolFor("Deno.privateCustomInspect")](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.opSync("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.opSync("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.opSync("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.opSync(
"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.opSync("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.opSync("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.opSync("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)) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
core.opSync("op_webgpu_compute_pass_set_bind_group", {
computePassRid,
index,
bindGroup: bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
});
}
/**
* @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.opSync("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.opSync("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.opSync("op_webgpu_compute_pass_insert_debug_marker", {
computePassRid,
markerLabel,
});
}
[SymbolFor("Deno.privateCustomInspect")](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");
}
[SymbolFor("Deno.privateCustomInspect")](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.opSync(
"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)) {
dynamicOffsetsData = new Uint32Array(dynamicOffsetsData ?? []);
dynamicOffsetsDataStart = 0;
dynamicOffsetsDataLength = dynamicOffsetsData.length;
}
core.opSync("op_webgpu_render_bundle_encoder_set_bind_group", {
renderBundleEncoderRid,
index,
bindGroup: bindGroupRid,
dynamicOffsetsData,
dynamicOffsetsDataStart,
dynamicOffsetsDataLength,
});
}
/**
* @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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("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.opSync("op_webgpu_render_bundle_encoder_draw_indirect", {
renderBundleEncoderRid,
indirectBuffer: indirectBufferRid,
indirectOffset,
});
}
drawIndexedIndirect(_indirectBuffer, _indirectOffset) {
throw new Error("Not yet implemented");
}
[SymbolFor("Deno.privateCustomInspect")](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();
}
[SymbolFor("Deno.privateCustomInspect")](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]();
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${
inspect({
label: this.label,
})
}`;
}
}
GPUObjectBaseMixin("GPUQuerySet", GPUQuerySet);
window.__bootstrap.webgpu = {
gpu: webidl.createBranded(GPU),
GPU,
GPUAdapter,
GPUSupportedLimits,
GPUSupportedFeatures,
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);