diff --git a/Cargo.lock b/Cargo.lock index e632a658c0..54deb53983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,6 +608,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.37" @@ -981,9 +987,9 @@ dependencies = [ [[package]] name = "d3d12" -version = "0.7.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16e44ab292b1dddfdaf7be62cfd8877df52f2f3fde5858d95bab606be259f20" +checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" dependencies = [ "bitflags 2.5.0", "libloading 0.8.3", @@ -2218,6 +2224,15 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -3020,23 +3035,22 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fe17c8a05d60c38c0a4e5a3c802f2f1ceb66b76c67d96ffb34bef0475a7fad" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" dependencies = [ - "backtrace", "log", "presser", "thiserror", "winapi", - "windows 0.51.1", + "windows", ] [[package]] name = "gpu-descriptor" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" dependencies = [ "bitflags 2.5.0", "gpu-descriptor-types", @@ -3045,9 +3059,9 @@ dependencies = [ [[package]] name = "gpu-descriptor-types" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ "bitflags 2.5.0", ] @@ -3621,6 +3635,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.29" @@ -3892,6 +3912,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -4040,9 +4066,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" +checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" dependencies = [ "bitflags 2.5.0", "block", @@ -4101,10 +4127,11 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "naga" -version = "0.14.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae585df4b6514cf8842ac0f1ab4992edc975892704835b549cf818dc0191249e" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" dependencies = [ + "arrayvec", "bit-set", "bitflags 2.5.0", "codespan-reporting", @@ -4146,6 +4173,15 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + [[package]] name = "netif" version = "0.1.6" @@ -4327,16 +4363,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", ] [[package]] @@ -5112,9 +5138,9 @@ checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "8cc3bcbdb1ddfc11e700e62968e6b4cc9c75bb466464ad28fb61c5b2c964418b" [[package]] name = "rayon" @@ -5631,9 +5657,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -5659,9 +5685,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", @@ -5916,12 +5942,11 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spirv" -version = "0.2.0+1.5.4" +version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 1.3.2", - "num-traits", + "bitflags 2.5.0", ] [[package]] @@ -6655,18 +6680,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -7424,16 +7449,20 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "wgpu-core" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef91c1d62d1e9e81c79e600131a258edf75c9531cbdbde09c44a011a47312726" +checksum = "ac6a86eaa5e763e59c73cf9e97d55fffd4dfda69fd8bda19589fcf851ddfef1f" dependencies = [ "arrayvec", "bit-vec", "bitflags 2.5.0", + "cfg_aliases", "codespan-reporting", + "document-features", + "indexmap", "log", "naga", + "once_cell", "parking_lot 0.12.1", "profiling", "raw-window-handle", @@ -7449,9 +7478,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84ecc802da3eb67b4cf3dd9ea6fe45bbb47ef13e6c49c5c3240868a9cc6cdd9" +checksum = "4d71c8ae05170583049b65ee562fd839fdc0b3e9ddb84f4e40c9d5f8ea0d4c8c" dependencies = [ "android_system_properties", "arrayvec", @@ -7459,6 +7488,7 @@ dependencies = [ "bit-set", "bitflags 2.5.0", "block", + "cfg_aliases", "core-graphics-types", "d3d12", "glow", @@ -7473,6 +7503,7 @@ dependencies = [ "log", "metal", "naga", + "ndk-sys", "objc", "once_cell", "parking_lot 0.12.1", @@ -7490,9 +7521,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d5ed5f0edf0de351fe311c53304986315ce866f394a2e6df0c4b3c70774bcdd" +checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" dependencies = [ "bitflags 2.5.0", "js-sys", @@ -7549,7 +7580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c" dependencies = [ "thiserror", - "windows 0.52.0", + "windows", ] [[package]] @@ -7583,35 +7614,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" -dependencies = [ - "windows-core 0.51.1", - "windows-targets 0.48.5", -] - [[package]] name = "windows" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core 0.52.0", + "windows-core", "windows-targets 0.52.4", ] -[[package]] -name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-core" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index a49a72d512..243469d8ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,10 +185,10 @@ hkdf = "0.12.3" rsa = { version = "0.9.3", default-features = false, features = ["std", "pem", "hazmat"] } # hazmat needed for PrehashSigner in ext/node # webgpu -raw-window-handle = "0.5.0" -wgpu-core = { version = "=0.18", features = ["raw-window-handle"] } -wgpu-hal = "=0.18" -wgpu-types = "=0.18" +raw-window-handle = "0.6.0" +wgpu-core = "0.20" +wgpu-hal = "0.20" +wgpu-types = "0.20" # macros proc-macro2 = "1" diff --git a/cli/tsc/dts/lib.deno_webgpu.d.ts b/cli/tsc/dts/lib.deno_webgpu.d.ts index 1b5f92918c..8362ba2e26 100644 --- a/cli/tsc/dts/lib.deno_webgpu.d.ts +++ b/cli/tsc/dts/lib.deno_webgpu.d.ts @@ -48,6 +48,8 @@ declare class GPUSupportedLimits { maxVertexAttributes?: number; maxVertexBufferArrayStride?: number; maxInterStageShaderComponents?: number; + maxColorAttachments?: number; + maxColorAttachmentBytesPerSample?: number; maxComputeWorkgroupStorageSize?: number; maxComputeInvocationsPerWorkgroup?: number; maxComputeWorkgroupSizeX?: number; @@ -124,7 +126,7 @@ declare class GPUAdapter { readonly isFallbackAdapter: boolean; requestDevice(descriptor?: GPUDeviceDescriptor): Promise; - requestAdapterInfo(unmaskHints?: string[]): Promise; + requestAdapterInfo(): Promise; } /** @@ -150,6 +152,9 @@ declare type GPUFeatureName = | "timestamp-query" | "indirect-first-instance" | "shader-f16" + | "rg11b10ufloat-renderable" + | "bgra8unorm-storage" + | "float32-filterable" // extended from spec | "mappable-primary-buffers" | "sampled-texture-binding-array" @@ -427,6 +432,7 @@ declare type GPUTextureFormat = | "bgra8unorm" | "bgra8unorm-srgb" | "rgb9e5ufloat" + | "rgb10a2uint" | "rgb10a2unorm" | "rg11b10ufloat" | "rg32uint" @@ -658,7 +664,10 @@ declare type GPUTextureSampleType = * @category WebGPU * @tags unstable */ -declare type GPUStorageTextureAccess = "write-only"; +declare type GPUStorageTextureAccess = + | "write-only" + | "read-only" + | "read-write"; /** * @category WebGPU @@ -756,6 +765,30 @@ declare interface GPUCompilationInfo { readonly messages: ReadonlyArray; } +/** + * @category GPU + * @tags unstable + */ +declare class GPUPipelineError extends DOMException { + constructor(message?: string, options?: GPUPipelineErrorInit); + + readonly reason: GPUPipelineErrorReason; +} + +/** + * @category GPU + * @tags unstable + */ +declare interface GPUPipelineErrorInit { + reason: GPUPipelineErrorReason; +} + +/** + * @category GPU + * @tags unstable + */ +declare type GPUPipelineErrorReason = "validation" | "internal"; + /** * @category WebGPU * @tags unstable @@ -801,7 +834,8 @@ declare interface GPUPipelineBase { */ declare interface GPUProgrammableStage { module: GPUShaderModule; - entryPoint: string; + entryPoint?: string; + constants?: Record; } /** @@ -1063,7 +1097,8 @@ declare type GPUVertexFormat = | "sint32" | "sint32x2" | "sint32x3" - | "sint32x4"; + | "sint32x4" + | "unorm10-10-10-2"; /** * @category WebGPU @@ -1653,11 +1688,40 @@ declare class GPUValidationError extends GPUError { constructor(message: string); } +/** + * @category GPU + * @tags unstable + */ +declare class GPUInternalError extends GPUError { + constructor(message: string); +} + /** * @category WebGPU * @tags unstable */ -declare type GPUErrorFilter = "out-of-memory" | "validation"; +declare type GPUErrorFilter = "out-of-memory" | "validation" | "internal"; + +/** + * @category GPU + * @tags unstable + */ +declare class GPUUncapturedErrorEvent extends EventTarget { + constructor( + type: string, + gpuUncapturedErrorEventInitDict: GPUUncapturedErrorEventInit, + ); + + readonly error: GPUError; +} + +/** + * @category GPU + * @tags unstable + */ +declare interface GPUUncapturedErrorEventInit extends EventInit { + error: GPUError; +} /** * @category WebGPU diff --git a/ext/webgpu/01_webgpu.js b/ext/webgpu/01_webgpu.js index d3e9bf4e38..5ca8c0fdbd 100644 --- a/ext/webgpu/01_webgpu.js +++ b/ext/webgpu/01_webgpu.js @@ -92,8 +92,7 @@ const { ArrayBuffer, ArrayBufferPrototypeGetByteLength, ArrayIsArray, - ArrayPrototypeFilter, - ArrayPrototypeIncludes, + ArrayPrototypeFindLast, ArrayPrototypeMap, ArrayPrototypePop, ArrayPrototypePush, @@ -104,12 +103,9 @@ const { ObjectHasOwn, ObjectPrototypeIsPrototypeOf, Promise, - PromisePrototypeCatch, - PromisePrototypeThen, PromiseReject, PromiseResolve, SafeArrayIterator, - SafePromiseAll, SafeSet, SafeWeakRef, SetPrototypeHas, @@ -124,7 +120,12 @@ const { } = primordials; import * as webidl from "ext:deno_webidl/00_webidl.js"; -import { EventTarget } from "ext:deno_web/02_event.js"; +import { + defineEventHandler, + Event, + EventTarget, + setEventTargetData, +} from "ext:deno_web/02_event.js"; import { DOMException } from "ext:deno_web/01_dom_exception.js"; import { createFilteredInspectProxy } from "ext:deno_console/01_console.js"; @@ -299,7 +300,6 @@ class GPUValidationError extends GPUError { this[_message] = message; } } -const GPUValidationErrorPrototype = GPUValidationError.prototype; class GPUOutOfMemoryError extends GPUError { name = "GPUOutOfMemoryError"; @@ -312,7 +312,40 @@ class GPUOutOfMemoryError extends GPUError { this[_message] = message; } } -const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype; + +class GPUInternalError extends GPUError { + name = "GPUInternalError"; + constructor() { + super(illegalConstructorKey); + this[webidl.brand] = webidl.brand; + } +} + +class GPUUncapturedErrorEvent extends Event { + #error; + + constructor(type, gpuUncapturedErrorEventInitDict) { + super(type, gpuUncapturedErrorEventInitDict); + this[webidl.brand] = webidl.brand; + + const prefix = "Failed to construct 'GPUUncapturedErrorEvent'"; + webidl.requiredArguments(arguments.length, 2, prefix); + gpuUncapturedErrorEventInitDict = webidl.converters + .GPUUncapturedErrorEventInit( + gpuUncapturedErrorEventInitDict, + prefix, + "Argument 2", + ); + + this.#error = gpuUncapturedErrorEventInitDict.error; + } + + get error() { + webidl.assertBranded(this, GPUUncapturedErrorEventPrototype); + return this.#error; + } +} +const GPUUncapturedErrorEventPrototype = GPUUncapturedErrorEvent.prototype; class GPU { [webidl.brand] = webidl.brand; @@ -433,7 +466,7 @@ class GPUAdapter { } } - const { rid, features, limits } = op_webgpu_request_device( + const { rid, queueRid, features, limits } = op_webgpu_request_device( this[_adapter].rid, descriptor.label, requiredFeatures, @@ -446,25 +479,22 @@ class GPUAdapter { features: createGPUSupportedFeatures(features), limits: createGPUSupportedLimits(limits), }); - return createGPUDevice( + const queue = createGPUQueue(descriptor.label, inner, queueRid); + inner.trackResource(queue); + const device = createGPUDevice( descriptor.label, inner, - createGPUQueue(descriptor.label, inner), + queue, ); + inner.device = device; + return device; } /** - * @param {string[]} unmaskHints * @returns {Promise} */ - requestAdapterInfo(unmaskHints = []) { + requestAdapterInfo() { webidl.assertBranded(this, GPUAdapterPrototype); - const prefix = "Failed to execute 'requestAdapterInfo' on 'GPUAdapter'"; - unmaskHints = webidl.converters["sequence"]( - unmaskHints, - prefix, - "Argument 1", - ); const { vendor, @@ -474,16 +504,10 @@ class GPUAdapter { } = op_webgpu_request_adapter_info(this[_adapter].rid); const adapterInfo = webidl.createBranded(GPUAdapterInfo); - adapterInfo[_vendor] = ArrayPrototypeIncludes(unmaskHints, "vendor") - ? vendor - : ""; - adapterInfo[_architecture] = - ArrayPrototypeIncludes(unmaskHints, "architecture") ? architecture : ""; - adapterInfo[_device] = ArrayPrototypeIncludes(unmaskHints, "device") - ? device - : ""; - adapterInfo[_description] = - ArrayPrototypeIncludes(unmaskHints, "description") ? description : ""; + adapterInfo[_vendor] = vendor; + adapterInfo[_architecture] = architecture; + adapterInfo[_device] = device; + adapterInfo[_description] = description; return PromiseResolve(adapterInfo); } @@ -687,6 +711,14 @@ class GPUSupportedLimits { webidl.assertBranded(this, GPUSupportedLimitsPrototype); return this[_limits].maxInterStageShaderComponents; } + get maxColorAttachments() { + webidl.assertBranded(this, GPUSupportedLimitsPrototype); + return this[_limits].maxColorAttachments; + } + get maxColorAttachmentBytesPerSample() { + webidl.assertBranded(this, GPUSupportedLimitsPrototype); + return this[_limits].maxColorAttachmentBytesPerSample; + } get maxComputeWorkgroupStorageSize() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); return this[_limits].maxComputeWorkgroupStorageSize; @@ -743,6 +775,8 @@ class GPUSupportedLimits { "maxVertexAttributes", "maxVertexBufferArrayStride", "maxInterStageShaderComponents", + "maxColorAttachments", + "maxColorAttachmentBytesPerSample", "maxComputeWorkgroupStorageSize", "maxComputeInvocationsPerWorkgroup", "maxComputeWorkgroupSizeX", @@ -773,6 +807,7 @@ class GPUSupportedFeatures { constructor() { webidl.illegalConstructor(); } + [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { if (ObjectPrototypeIsPrototypeOf(GPUSupportedFeaturesPrototype, this)) { return `${this.constructor.name} ${ @@ -783,7 +818,6 @@ class GPUSupportedFeatures { } } } - const GPUSupportedFeaturesPrototype = GPUSupportedFeatures.prototype; /** @@ -870,7 +904,7 @@ function GPUObjectBaseMixin(name, type) { /** * @typedef ErrorScope * @property {string} filter - * @property {Promise[]} operations + * @property {GPUError[]} errors */ /** @@ -879,6 +913,7 @@ function GPUObjectBaseMixin(name, type) { * @property {number | undefined} rid * @property {GPUSupportedFeatures} features * @property {GPUSupportedLimits} limits + * @property {GPUDevice} device */ class InnerGPUDevice { @@ -900,6 +935,8 @@ class InnerGPUDevice { resolveLost; /** @type {ErrorScope[]} */ errorScopeStack; + /** @type {GPUDevice} */ + device; /** * @param {InnerGPUDeviceOptions} options @@ -923,79 +960,51 @@ class InnerGPUDevice { ArrayPrototypePush(this.resources, new SafeWeakRef(resource)); } - /** @param {{ type: string, value: string | null } | undefined} err */ - pushError(err) { - this.pushErrorPromise(PromiseResolve(err)); - } + // Ref: https://gpuweb.github.io/gpuweb/#abstract-opdef-dispatch-error + /** @param {{ type: string, value: string | null } | undefined} error */ + pushError(error) { + if (!error) { + return; + } - /** @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()); - } - } - }); + let constructedError; + switch (error.type) { + case "lost": + this.isLost = true; + this.resolveLost( + createGPUDeviceLostInfo(undefined, "device was lost"), + ); + return; + case "validation": + constructedError = new GPUValidationError( + error.value ?? "validation error", + ); + break; + case "out-of-memory": + constructedError = new GPUOutOfMemoryError(); + break; + case "internal": + constructedError = new GPUInternalError(); + break; + } - const validationStack = ArrayPrototypeFilter( + if (this.isLost) { + return; + } + + const scope = ArrayPrototypeFindLast( this.errorScopeStack, - ({ filter }) => filter == "validation", + ({ filter }) => filter === error.type, ); - const validationScope = validationStack[validationStack.length - 1]; - const validationFilteredPromise = PromisePrototypeCatch( - operation, - (err) => { - if (ObjectPrototypeIsPrototypeOf(GPUValidationErrorPrototype, err)) { - return PromiseReject(err); - } - return PromiseResolve(); - }, - ); - if (validationScope) { - ArrayPrototypePush( - validationScope.operations, - validationFilteredPromise, + if (scope) { + ArrayPrototypePush(scope.errors, constructedError); + } else { + this.device.dispatchEvent( + new GPUUncapturedErrorEvent("uncapturederror", { + error: constructedError, + }), ); - } 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 (ObjectPrototypeIsPrototypeOf(GPUOutOfMemoryErrorPrototype, err)) { - 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) => {}); } } @@ -1011,6 +1020,7 @@ function createGPUDevice(label, inner, queue) { device[_label] = label; device[_device] = inner; device[_queue] = queue; + setEventTargetData(device); return device; } @@ -1283,11 +1293,6 @@ class GPUDevice extends EventTarget { const resource = entry.resource; if (ObjectPrototypeIsPrototypeOf(GPUSamplerPrototype, resource)) { const rid = assertResource(resource, prefix, context); - assertDeviceMatch(device, resource, { - prefix, - resourceContext: context, - selfContext: "this", - }); return { binding: entry.binding, kind: "GPUSampler", @@ -1298,11 +1303,6 @@ class GPUDevice extends EventTarget { ) { 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", @@ -1311,12 +1311,6 @@ class GPUDevice extends EventTarget { } else { // deno-lint-ignore prefer-primordials const rid = assertResource(resource.buffer, prefix, context); - // deno-lint-ignore prefer-primordials - assertDeviceMatch(device, resource.buffer, { - prefix, - resourceContext: context, - selfContext: "this", - }); return { binding: entry.binding, kind: "GPUBufferBinding", @@ -1509,12 +1503,166 @@ class GPUDevice extends EventTarget { createComputePipelineAsync(descriptor) { // TODO(lucacasonato): this should be real async - return PromiseResolve(this.createComputePipeline(descriptor)); + + webidl.assertBranded(this, GPUDevicePrototype); + const prefix = + "Failed to execute 'createComputePipelineAsync' on 'GPUDevice'"; + webidl.requiredArguments(arguments.length, 1, prefix); + descriptor = webidl.converters.GPUComputePipelineDescriptor( + descriptor, + prefix, + "Argument 1", + ); + const device = assertDevice(this, prefix, "this"); + let layout = descriptor.layout; + if (typeof descriptor.layout !== "string") { + const context = "layout"; + layout = assertResource(descriptor.layout, prefix, context); + assertDeviceMatch(device, descriptor.layout, { + prefix, + resourceContext: context, + selfContext: "this", + }); + } + const module = assertResource( + descriptor.compute.module, + prefix, + "compute shader module", + ); + assertDeviceMatch(device, descriptor.compute.module, { + prefix, + resourceContext: "compute shader module", + selfContext: "this", + }); + + const { rid, err } = op_webgpu_create_compute_pipeline( + device.rid, + descriptor.label, + layout, + { + module, + entryPoint: descriptor.compute.entryPoint, + constants: descriptor.compute.constants, + }, + ); + device.pushError(err); + if (err) { + switch (err.type) { + case "validation": + return PromiseReject( + new GPUPipelineError(err.value ?? "validation error", { + reason: "validation", + }), + ); + case "internal": + return PromiseReject( + new GPUPipelineError("internal error", { + reason: "validation", + }), + ); + } + } + + const computePipeline = createGPUComputePipeline( + descriptor.label, + device, + rid, + ); + device.trackResource(computePipeline); + return PromiseResolve(computePipeline); } createRenderPipelineAsync(descriptor) { // TODO(lucacasonato): this should be real async - return PromiseResolve(this.createRenderPipeline(descriptor)); + + webidl.assertBranded(this, GPUDevicePrototype); + const prefix = + "Failed to execute 'createRenderPipelineAsync' on 'GPUDevice'"; + webidl.requiredArguments(arguments.length, 1, prefix); + descriptor = webidl.converters.GPURenderPipelineDescriptor( + descriptor, + prefix, + "Argument 1", + ); + const device = assertDevice(this, prefix, "this"); + let layout = descriptor.layout; + if (typeof descriptor.layout !== "string") { + const context = "layout"; + layout = assertResource(descriptor.layout, prefix, context); + assertDeviceMatch(device, descriptor.layout, { + prefix, + resourceContext: context, + selfContext: "this", + }); + } + const module = assertResource( + descriptor.vertex.module, + prefix, + "vertex shader module", + ); + assertDeviceMatch(device, descriptor.vertex.module, { + prefix, + resourceContext: "vertex shader module", + selfContext: "this", + }); + let fragment = undefined; + if (descriptor.fragment) { + const module = assertResource( + descriptor.fragment.module, + prefix, + "fragment shader module", + ); + assertDeviceMatch(device, descriptor.fragment.module, { + prefix, + resourceContext: "fragment shader module", + selfContext: "this", + }); + fragment = { + module, + entryPoint: descriptor.fragment.entryPoint, + targets: descriptor.fragment.targets, + }; + } + + const { rid, err } = op_webgpu_create_render_pipeline({ + deviceRid: device.rid, + label: descriptor.label, + layout, + vertex: { + module, + entryPoint: descriptor.vertex.entryPoint, + buffers: descriptor.vertex.buffers, + }, + primitive: descriptor.primitive, + depthStencil: descriptor.depthStencil, + multisample: descriptor.multisample, + fragment, + }); + device.pushError(err); + if (err) { + switch (err.type) { + case "validation": + return PromiseReject( + new GPUPipelineError(err.value ?? "validation error", { + reason: "validation", + }), + ); + case "internal": + return PromiseReject( + new GPUPipelineError("internal error", { + reason: "validation", + }), + ); + } + } + + const renderPipeline = createGPURenderPipeline( + descriptor.label, + device, + rid, + ); + device.trackResource(renderPipeline); + return renderPipeline; } /** @@ -1626,7 +1774,7 @@ class GPUDevice extends EventTarget { webidl.requiredArguments(arguments.length, 1, prefix); filter = webidl.converters.GPUErrorFilter(filter, prefix, "Argument 1"); const device = assertDevice(this, prefix, "this"); - ArrayPrototypePush(device.errorScopeStack, { filter, operations: [] }); + ArrayPrototypePush(device.errorScopeStack, { filter, errors: [] }); } /** @@ -1647,12 +1795,7 @@ class GPUDevice extends EventTarget { "OperationError", ); } - const operations = SafePromiseAll(scope.operations); - return PromisePrototypeThen( - operations, - () => PromiseResolve(null), - (err) => PromiseResolve(err), - ); + return PromiseResolve(scope.errors[0] ?? null); } [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { @@ -1676,23 +1819,60 @@ class GPUDevice extends EventTarget { } GPUObjectBaseMixin("GPUDevice", GPUDevice); const GPUDevicePrototype = GPUDevice.prototype; +defineEventHandler(GPUDevice.prototype, "uncapturederror"); + +class GPUPipelineError extends DOMException { + #reason; + + constructor(message = "", options = {}) { + const prefix = "Failed to construct 'GPUPipelineError'"; + message = webidl.converters.DOMString(message, prefix, "Argument 1"); + options = webidl.converters.GPUPipelineErrorInit( + options, + prefix, + "Argument 2", + ); + super(message, "GPUPipelineError"); + + this.#reason = options.reason; + } + + get reason() { + webidl.assertBranded(this, GPUPipelineErrorPrototype); + return this.#reason; + } +} +const GPUPipelineErrorPrototype = GPUPipelineError.prototype; /** * @param {string | null} label * @param {InnerGPUDevice} device + * @param {number} rid * @returns {GPUQueue} */ -function createGPUQueue(label, device) { +function createGPUQueue(label, device, rid) { /** @type {GPUQueue} */ const queue = webidl.createBranded(GPUQueue); queue[_label] = label; queue[_device] = device; + queue[_rid] = rid; return queue; } class GPUQueue { /** @type {InnerGPUDevice} */ [_device]; + /** @type {number} */ + [_rid]; + + [_cleanup]() { + const rid = this[_rid]; + if (rid !== undefined) { + core.close(rid); + /** @type {number | undefined} */ + this[_rid] = undefined; + } + } constructor() { webidl.illegalConstructor(); @@ -1726,7 +1906,7 @@ class GPUQueue { return rid; }, ); - const { err } = op_webgpu_queue_submit(device.rid, commandBufferRids); + const { err } = op_webgpu_queue_submit(this[_rid], commandBufferRids); for (let i = 0; i < commandBuffers.length; ++i) { commandBuffers[i][_rid] = undefined; } @@ -1782,7 +1962,7 @@ class GPUQueue { } const { err } = op_webgpu_write_buffer( - device.rid, + this[_rid], bufferRid, bufferOffset, dataOffset, @@ -1833,7 +2013,7 @@ class GPUQueue { } const { err } = op_webgpu_write_texture( - device.rid, + this[_rid], { texture: textureRid, mipLevel: destination.mipLevel, @@ -2027,19 +2207,15 @@ class GPUBuffer { this[_mapMode] = mode; this[_state] = "pending"; - const promise = PromisePrototypeThen( - op_webgpu_buffer_get_map_async( - bufferRid, - device.rid, - mode, - offset, - rangeSize, - ), - ({ err }) => err, + const { err } = await op_webgpu_buffer_get_map_async( + bufferRid, + device.rid, + mode, + offset, + rangeSize, ); - device.pushErrorPromise(promise); - const err = await promise; if (err) { + device.pushError(err); throw new DOMException("validation error occurred", "OperationError"); } this[_state] = "mapped"; @@ -5136,6 +5312,7 @@ webidl.converters["GPUFeatureName"] = webidl.createEnumConverter( "texture-compression-astc", "rg11b10ufloat-renderable", "bgra8unorm-storage", + "float32-filterable", // extended from spec @@ -5174,6 +5351,27 @@ webidl.converters["GPUFeatureName"] = webidl.createEnumConverter( ], ); +// DICTIONARY: GPUPipelineErrorInit +webidl.converters["GPUPipelineErrorInit"] = webidl.createDictionaryConverter( + "GPUPipelineErrorInit", + [ + { + key: "reason", + converter: webidl.converters.GPUPipelineErrorReason, + required: true, + }, + ], +); + +// ENUM: GPUPipelineErrorReason +webidl.converters["GPUPipelineErrorReason"] = webidl.createEnumConverter( + "GPUPipelineErrorReason", + [ + "validation", + "internal", + ], +); + // TYPEDEF: GPUSize32 webidl.converters["GPUSize32"] = (V, opts) => webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }); @@ -5353,6 +5551,7 @@ webidl.converters["GPUTextureFormat"] = webidl.createEnumConverter( "bgra8unorm", "bgra8unorm-srgb", "rgb9e5ufloat", + "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", "rg32uint", @@ -5768,6 +5967,8 @@ webidl.converters["GPUStorageTextureAccess"] = webidl.createEnumConverter( "GPUStorageTextureAccess", [ "write-only", + "read-only", + "read-write", ], ); @@ -6027,7 +6228,6 @@ const dictMembersGPUProgrammableStage = [ { key: "entryPoint", converter: webidl.converters["USVString"], - required: true, }, { key: "constants", @@ -6110,6 +6310,7 @@ webidl.converters["GPUVertexFormat"] = webidl.createEnumConverter( "sint32x2", "sint32x3", "sint32x4", + "unorm10-10-10-2", ], ); @@ -7070,6 +7271,7 @@ webidl.converters["GPUErrorFilter"] = webidl.createEnumConverter( [ "out-of-memory", "validation", + "internal", ], ); @@ -7209,6 +7411,7 @@ export { GPUDevice, GPUDeviceLostInfo, GPUError, + GPUInternalError, GPUMapMode, GPUOutOfMemoryError, GPUPipelineLayout, @@ -7226,5 +7429,6 @@ export { GPUTexture, GPUTextureUsage, GPUTextureView, + GPUUncapturedErrorEvent, GPUValidationError, }; diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index d2fc37ee25..61a8095a7a 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -19,22 +19,30 @@ path = "lib.rs" deno_core.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } -wgpu-types = { workspace = true, features = ["trace", "replay", "serde"] } +wgpu-types = { workspace = true, features = ["serde"] } raw-window-handle = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core] workspace = true -features = ["trace", "replay", "serde", "strict_asserts", "wgsl", "gles"] +features = [ + "raw-window-handle", + "trace", + "replay", + "serde", + "strict_asserts", + "wgsl", + "gles", +] # We want the wgpu-core Metal backend on macOS and iOS. [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgpu-core] workspace = true features = ["metal"] -# We want the wgpu-core Direct3D backends on Windows. +# We want the wgpu-core Direct3D backend on Windows. [target.'cfg(windows)'.dependencies.wgpu-core] workspace = true -features = ["dx11", "dx12"] +features = ["dx12"] [target.'cfg(windows)'.dependencies.wgpu-hal] workspace = true diff --git a/ext/webgpu/LICENSE.md b/ext/webgpu/LICENSE.md index aec557f3a0..56753af367 100644 --- a/ext/webgpu/LICENSE.md +++ b/ext/webgpu/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright 2018-2023 the Deno authors +Copyright 2018-2024 the Deno authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/ext/webgpu/README.md b/ext/webgpu/README.md index f5ac0d0b5d..c419bfc60e 100644 --- a/ext/webgpu/README.md +++ b/ext/webgpu/README.md @@ -2,7 +2,7 @@ This op crate implements the WebGPU API as defined in https://gpuweb.github.io/gpuweb/ in Deno. The implementation targets the spec -draft as of October 4, 2023. The spec is still very much in flux. This op crate +draft as of March 31, 2024. The spec is still very much in flux. This extension tries to stay up to date with the spec, but is constrained by the features implemented in our GPU backend library [wgpu](https://github.com/gfx-rs/wgpu). @@ -19,7 +19,7 @@ running through our WPT runner. This will be used to validate implementation conformance. GitHub CI doesn't run with GPUs, so testing relies on software like DX WARP & -Vulkan lavapipe. Currently only using DX WARP works, so tests are only run on +Vulkan lavapipe. Currently, only using DX WARP works, so tests are only run on Windows. ## Links diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs index bdc71a9ef8..41708acc7f 100644 --- a/ext/webgpu/binding.rs +++ b/ext/webgpu/binding.rs @@ -21,8 +21,7 @@ impl Resource for WebGpuBindGroupLayout { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.bind_group_layout_drop(self.1)); + gfx_select!(self.1 => self.0.bind_group_layout_drop(self.1)); } } @@ -36,8 +35,7 @@ impl Resource for WebGpuBindGroup { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.bind_group_drop(self.1)); + gfx_select!(self.1 => self.0.bind_group_drop(self.1)); } } @@ -114,27 +112,11 @@ impl From for wgpu_types::TextureSampleType { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct GpuStorageTextureBindingLayout { - access: GpuStorageTextureAccess, + access: wgpu_types::StorageTextureAccess, format: wgpu_types::TextureFormat, view_dimension: wgpu_types::TextureViewDimension, } -#[derive(Deserialize)] -#[serde(rename_all = "kebab-case")] -enum GpuStorageTextureAccess { - WriteOnly, -} - -impl From for wgpu_types::StorageTextureAccess { - fn from(access: GpuStorageTextureAccess) -> Self { - match access { - GpuStorageTextureAccess::WriteOnly => { - wgpu_types::StorageTextureAccess::WriteOnly - } - } - } -} - #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct GpuBindGroupLayoutEntry { @@ -171,7 +153,7 @@ impl From for wgpu_types::BindingType { }, GpuBindingType::StorageTexture(storage_texture) => { wgpu_types::BindingType::StorageTexture { - access: storage_texture.access.into(), + access: storage_texture.access, format: storage_texture.format, view_dimension: storage_texture.view_dimension, } @@ -215,7 +197,7 @@ pub fn op_webgpu_create_bind_group_layout( gfx_put!(device => instance.device_create_bind_group_layout( device, &descriptor, - () + None ) => state, WebGpuBindGroupLayout) } @@ -251,7 +233,7 @@ pub fn op_webgpu_create_pipeline_layout( gfx_put!(device => instance.device_create_pipeline_layout( device, &descriptor, - () + None ) => state, super::pipeline::WebGpuPipelineLayout) } @@ -335,6 +317,6 @@ pub fn op_webgpu_create_bind_group( gfx_put!(device => instance.device_create_bind_group( device, &descriptor, - () + None ) => state, WebGpuBindGroup) } diff --git a/ext/webgpu/buffer.rs b/ext/webgpu/buffer.rs index 2866b29f77..2887f38120 100644 --- a/ext/webgpu/buffer.rs +++ b/ext/webgpu/buffer.rs @@ -26,8 +26,7 @@ impl Resource for WebGpuBuffer { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.buffer_drop(self.1, true)); + gfx_select!(self.1 => self.0.buffer_drop(self.1, true)); } } @@ -65,7 +64,7 @@ pub fn op_webgpu_create_buffer( gfx_put!(device => instance.device_create_buffer( device, &descriptor, - () + None ) => state, WebGpuBuffer) } @@ -100,14 +99,15 @@ pub async fn op_webgpu_buffer_get_map_async( // TODO(lucacasonato): error handling let maybe_err = gfx_select!(buffer => instance.buffer_map_async( buffer, - offset..(offset + size), + offset, + Some(size), wgpu_core::resource::BufferMapOperation { host: match mode { 1 => wgpu_core::device::HostMap::Read, 2 => wgpu_core::device::HostMap::Write, _ => unreachable!(), }, - callback: wgpu_core::resource::BufferMapCallback::from_rust(callback), + callback: Some(wgpu_core::resource::BufferMapCallback::from_rust(callback)), } )) .err(); @@ -124,7 +124,7 @@ pub async fn op_webgpu_buffer_get_map_async( { let state = state.borrow(); let instance = state.borrow::(); - gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::Wait)) + gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::wait())) .unwrap(); } tokio::time::sleep(Duration::from_millis(10)).await; diff --git a/ext/webgpu/bundle.rs b/ext/webgpu/bundle.rs index 89ac6c0eb4..57158271cc 100644 --- a/ext/webgpu/bundle.rs +++ b/ext/webgpu/bundle.rs @@ -32,8 +32,7 @@ impl Resource for WebGpuRenderBundle { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.render_bundle_drop(self.1)); + gfx_select!(self.1 => self.0.render_bundle_drop(self.1)); } } @@ -118,7 +117,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( &wgpu_core::command::RenderBundleDescriptor { label: Some(label), }, - () + None ) => state, WebGpuRenderBundle) } diff --git a/ext/webgpu/byow.rs b/ext/webgpu/byow.rs index 30824c52b6..8864e8d2bd 100644 --- a/ext/webgpu/byow.rs +++ b/ext/webgpu/byow.rs @@ -6,6 +6,8 @@ use deno_core::op2; use deno_core::OpState; use deno_core::ResourceId; use std::ffi::c_void; +#[cfg(any(target_os = "linux", target_os = "macos"))] +use std::ptr::NonNull; use crate::surface::WebGpuSurface; @@ -36,8 +38,10 @@ pub fn op_webgpu_surface_create( } let (win_handle, display_handle) = raw_window(system, p1, p2)?; - let surface = - instance.instance_create_surface(display_handle, win_handle, ()); + // SAFETY: see above comment + let surface = unsafe { + instance.instance_create_surface(display_handle, win_handle, None)? + }; let rid = state .resource_table @@ -53,22 +57,22 @@ type RawHandles = ( #[cfg(target_os = "macos")] fn raw_window( system: &str, - ns_window: *const c_void, + _ns_window: *const c_void, ns_view: *const c_void, ) -> Result { if system != "cocoa" { return Err(type_error("Invalid system on macOS")); } - let win_handle = { - let mut handle = raw_window_handle::AppKitWindowHandle::empty(); - handle.ns_window = ns_window as *mut c_void; - handle.ns_view = ns_view as *mut c_void; + let win_handle = raw_window_handle::RawWindowHandle::AppKit( + raw_window_handle::AppKitWindowHandle::new( + NonNull::new(ns_view as *mut c_void) + .ok_or(type_error("ns_view is null"))?, + ), + ); - raw_window_handle::RawWindowHandle::AppKit(handle) - }; let display_handle = raw_window_handle::RawDisplayHandle::AppKit( - raw_window_handle::AppKitDisplayHandle::empty(), + raw_window_handle::AppKitDisplayHandle::new(), ); Ok((win_handle, display_handle)) } @@ -85,17 +89,17 @@ fn raw_window( } let win_handle = { - use raw_window_handle::Win32WindowHandle; - - let mut handle = Win32WindowHandle::empty(); - handle.hwnd = window as *mut c_void; - handle.hinstance = hinstance as *mut c_void; + let mut handle = raw_window_handle::Win32WindowHandle::new( + std::num::NonZeroIsize::new(window as isize) + .ok_or(type_error("window is null"))?, + ); + handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize); raw_window_handle::RawWindowHandle::Win32(handle) }; let display_handle = - raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::empty()); + raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::new()); Ok((win_handle, display_handle)) } @@ -107,33 +111,30 @@ fn raw_window( ) -> Result { let (win_handle, display_handle); if system == "x11" { - win_handle = { - let mut handle = raw_window_handle::XlibWindowHandle::empty(); - handle.window = window as *mut c_void as _; + win_handle = raw_window_handle::RawWindowHandle::Xlib( + raw_window_handle::XlibWindowHandle::new(window as *mut c_void as _), + ); - raw_window_handle::RawWindowHandle::Xlib(handle) - }; - - display_handle = { - let mut handle = raw_window_handle::XlibDisplayHandle::empty(); - handle.display = display as *mut c_void; - - raw_window_handle::RawDisplayHandle::Xlib(handle) - }; + display_handle = raw_window_handle::RawDisplayHandle::Xlib( + raw_window_handle::XlibDisplayHandle::new( + NonNull::new(display as *mut c_void), + 0, + ), + ); } else if system == "wayland" { - win_handle = { - let mut handle = raw_window_handle::WaylandWindowHandle::empty(); - handle.surface = window as _; + win_handle = raw_window_handle::RawWindowHandle::Wayland( + raw_window_handle::WaylandWindowHandle::new( + NonNull::new(window as *mut c_void) + .ok_or(type_error("window is null"))?, + ), + ); - raw_window_handle::RawWindowHandle::Wayland(handle) - }; - - display_handle = { - let mut handle = raw_window_handle::WaylandDisplayHandle::empty(); - handle.display = display as _; - - raw_window_handle::RawDisplayHandle::Wayland(handle) - }; + display_handle = raw_window_handle::RawDisplayHandle::Wayland( + raw_window_handle::WaylandDisplayHandle::new( + NonNull::new(display as *mut c_void) + .ok_or(type_error("display is null"))?, + ), + ); } else { return Err(type_error("Invalid system on Linux")); } diff --git a/ext/webgpu/command_encoder.rs b/ext/webgpu/command_encoder.rs index 09ca6a2216..3d82b77d45 100644 --- a/ext/webgpu/command_encoder.rs +++ b/ext/webgpu/command_encoder.rs @@ -23,8 +23,7 @@ impl Resource for WebGpuCommandEncoder { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.command_encoder_drop(self.1)); + gfx_select!(self.1 => self.0.command_encoder_drop(self.1)); } } @@ -39,8 +38,7 @@ impl Resource for WebGpuCommandBuffer { fn close(self: Rc) { if let Some(id) = *self.1.borrow() { - let instance = &self.0; - gfx_select!(id => instance.command_buffer_drop(id)); + gfx_select!(id => self.0.command_buffer_drop(id)); } } } @@ -63,7 +61,7 @@ pub fn op_webgpu_create_command_encoder( gfx_put!(device => instance.device_create_command_encoder( device, &descriptor, - () + None ) => state, WebGpuCommandEncoder) } @@ -493,7 +491,7 @@ pub fn op_webgpu_command_encoder_clear_buffer( command_encoder, destination_resource.1, offset, - std::num::NonZeroU64::new(size) + Some(size) )) } diff --git a/ext/webgpu/compute_pass.rs b/ext/webgpu/compute_pass.rs index a2c740a0d4..17043c7671 100644 --- a/ext/webgpu/compute_pass.rs +++ b/ext/webgpu/compute_pass.rs @@ -34,7 +34,7 @@ pub fn op_webgpu_compute_pass_set_pipeline( .resource_table .get::(compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline( + wgpu_core::command::compute_commands::wgpu_compute_pass_set_pipeline( &mut compute_pass_resource.0.borrow_mut(), compute_pipeline_resource.1, ); @@ -55,7 +55,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups( .resource_table .get::(compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_workgroups( + wgpu_core::command::compute_commands::wgpu_compute_pass_dispatch_workgroups( &mut compute_pass_resource.0.borrow_mut(), x, y, @@ -80,7 +80,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups_indirect( .resource_table .get::(compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_workgroups_indirect( + wgpu_core::command::compute_commands::wgpu_compute_pass_dispatch_workgroups_indirect( &mut compute_pass_resource.0.borrow_mut(), buffer_resource.1, indirect_offset, @@ -142,17 +142,12 @@ pub fn op_webgpu_compute_pass_set_bind_group( let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group( - &mut compute_pass_resource.0.borrow_mut(), - index, - bind_group_resource.1, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } + wgpu_core::command::compute_commands::wgpu_compute_pass_set_bind_group( + &mut compute_pass_resource.0.borrow_mut(), + index, + bind_group_resource.1, + dynamic_offsets_data, + ); Ok(WebGpuResult::empty()) } @@ -168,16 +163,11 @@ pub fn op_webgpu_compute_pass_push_debug_group( .resource_table .get::(compute_pass_rid)?; - let label = std::ffi::CString::new(group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + wgpu_core::command::compute_commands::wgpu_compute_pass_push_debug_group( + &mut compute_pass_resource.0.borrow_mut(), + group_label, + 0, // wgpu#975 + ); Ok(WebGpuResult::empty()) } @@ -192,7 +182,7 @@ pub fn op_webgpu_compute_pass_pop_debug_group( .resource_table .get::(compute_pass_rid)?; - wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group( + wgpu_core::command::compute_commands::wgpu_compute_pass_pop_debug_group( &mut compute_pass_resource.0.borrow_mut(), ); @@ -210,16 +200,11 @@ pub fn op_webgpu_compute_pass_insert_debug_marker( .resource_table .get::(compute_pass_rid)?; - let label = std::ffi::CString::new(marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker( - &mut compute_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + wgpu_core::command::compute_commands::wgpu_compute_pass_insert_debug_marker( + &mut compute_pass_resource.0.borrow_mut(), + marker_label, + 0, // wgpu#975 + ); Ok(WebGpuResult::empty()) } diff --git a/ext/webgpu/error.rs b/ext/webgpu/error.rs index 5d8abb4a3c..5b55d506ad 100644 --- a/ext/webgpu/error.rs +++ b/ext/webgpu/error.rs @@ -1,4 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + use deno_core::error::AnyError; use deno_core::ResourceId; use serde::Serialize; @@ -89,6 +90,7 @@ pub enum WebGpuError { Lost, OutOfMemory, Validation(String), + Internal, } impl From for WebGpuError { @@ -106,9 +108,7 @@ impl From for WebGpuError { match err { DeviceError::Lost => WebGpuError::Lost, DeviceError::OutOfMemory => WebGpuError::OutOfMemory, - DeviceError::ResourceCreationFailed - | DeviceError::Invalid - | DeviceError::WrongDevice => WebGpuError::Validation(fmt_err(&err)), + _ => WebGpuError::Validation(fmt_err(&err)), } } } diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index 5c0dc79c29..eeaae2dd6c 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -24,25 +24,31 @@ pub const UNSTABLE_FEATURE_NAME: &str = "webgpu"; #[macro_use] mod macros { macro_rules! gfx_select { - ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { + ($id:expr => $p0:ident.$p1:tt.$method:ident $params:tt) => { + gfx_select!($id => {$p0.$p1}, $method $params) + }; + + ($id:expr => $p0:ident.$method:ident $params:tt) => { + gfx_select!($id => {$p0}, $method $params) + }; + + ($id:expr => {$($c:tt)*}, $method:ident $params:tt) => { match $id.backend() { #[cfg(any( all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")), feature = "vulkan-portability" ))] - wgpu_types::Backend::Vulkan => $global.$method::( $($param),* ), + wgpu_types::Backend::Vulkan => $($c)*.$method:: $params, #[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))] - wgpu_types::Backend::Metal => $global.$method::( $($param),* ), + wgpu_types::Backend::Metal => $($c)*.$method:: $params, #[cfg(all(not(target_arch = "wasm32"), windows))] - wgpu_types::Backend::Dx12 => $global.$method::( $($param),* ), - #[cfg(all(not(target_arch = "wasm32"), windows))] - wgpu_types::Backend::Dx11 => $global.$method::( $($param),* ), + wgpu_types::Backend::Dx12 => $($c)*.$method:: $params, #[cfg(any( all(unix, not(target_os = "macos"), not(target_os = "ios")), feature = "angle", target_arch = "wasm32" ))] - wgpu_types::Backend::Gl => $global.$method::( $($param),+ ), + wgpu_types::Backend::Gl => $($c)*.$method:: $params, other => panic!("Unexpected backend {:?}", other), } }; @@ -79,9 +85,7 @@ pub mod shader; pub mod surface; pub mod texture; -pub type Instance = std::sync::Arc< - wgpu_core::global::Global, ->; +pub type Instance = std::sync::Arc; struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId); impl Resource for WebGpuAdapter { @@ -90,8 +94,7 @@ impl Resource for WebGpuAdapter { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.adapter_drop(self.1)); + gfx_select!(self.1 => self.0.adapter_drop(self.1)); } } @@ -102,8 +105,7 @@ impl Resource for WebGpuDevice { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.device_drop(self.1)); + gfx_select!(self.1 => self.0.device_drop(self.1)); } } @@ -114,8 +116,7 @@ impl Resource for WebGpuQuerySet { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.query_set_drop(self.1)); + gfx_select!(self.1 => self.0.query_set_drop(self.1)); } } @@ -259,6 +260,9 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { if features.contains(wgpu_types::Features::BGRA8UNORM_STORAGE) { return_features.push("bgra8unorm-storage"); } + if features.contains(wgpu_types::Features::FLOAT32_FILTERABLE) { + return_features.push("float32-filterable"); + } // extended from spec @@ -367,27 +371,37 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { #[derive(Serialize)] #[serde(untagged)] -pub enum GpuAdapterDeviceOrErr { +pub enum GpuAdapterResOrErr { Error { err: String }, - Features(GpuAdapterDevice), + Features(GpuAdapterRes), } #[derive(Serialize)] #[serde(rename_all = "camelCase")] -pub struct GpuAdapterDevice { +pub struct GpuAdapterRes { rid: ResourceId, limits: wgpu_types::Limits, features: Vec<&'static str>, is_software: bool, } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GpuDeviceRes { + rid: ResourceId, + queue_rid: ResourceId, + limits: wgpu_types::Limits, + features: Vec<&'static str>, + is_software: bool, +} + #[op2] #[serde] pub fn op_webgpu_request_adapter( state: Rc>, #[serde] power_preference: Option, force_fallback_adapter: bool, -) -> Result { +) -> Result { let mut state = state.borrow_mut(); // TODO(bartlomieju): replace with `state.feature_checker.check_or_exit` @@ -406,7 +420,6 @@ pub fn op_webgpu_request_adapter( } else { state.put(std::sync::Arc::new(wgpu_core::global::Global::new( "webgpu", - wgpu_core::identity::IdentityManagerFactory, wgpu_types::InstanceDescriptor { backends, flags: wgpu_types::InstanceFlags::from_build_config(), @@ -424,13 +437,13 @@ pub fn op_webgpu_request_adapter( }; let res = instance.request_adapter( &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| ()), + wgpu_core::instance::AdapterInputs::Mask(backends, |_| None), ); let adapter = match res { Ok(adapter) => adapter, Err(err) => { - return Ok(GpuAdapterDeviceOrErr::Error { + return Ok(GpuAdapterResOrErr::Error { err: err.to_string(), }) } @@ -445,7 +458,7 @@ pub fn op_webgpu_request_adapter( let rid = state.resource_table.add(WebGpuAdapter(instance, adapter)); - Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice { + Ok(GpuAdapterResOrErr::Features(GpuAdapterRes { rid, features, limits: adapter_limits, @@ -502,6 +515,10 @@ impl From for wgpu_types::Features { wgpu_types::Features::BGRA8UNORM_STORAGE, required_features.0.contains("bgra8unorm-storage"), ); + features.set( + wgpu_types::Features::FLOAT32_FILTERABLE, + required_features.0.contains("float32-filterable"), + ); // extended from spec @@ -653,7 +670,7 @@ pub fn op_webgpu_request_device( #[string] label: String, #[serde] required_features: GpuRequiredFeatures, #[serde] required_limits: Option, -) -> Result { +) -> Result { let mut state = state.borrow_mut(); let adapter_resource = state.resource_table.get::(adapter_rid)?; @@ -662,15 +679,16 @@ pub fn op_webgpu_request_device( let descriptor = wgpu_types::DeviceDescriptor { label: Some(Cow::Owned(label)), - features: required_features.into(), - limits: required_limits.unwrap_or_default(), + required_features: required_features.into(), + required_limits: required_limits.unwrap_or_default(), }; - let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( + let (device, queue, maybe_err) = gfx_select!(adapter => instance.adapter_request_device( adapter, &descriptor, std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), - () + None, + None )); if let Some(err) = maybe_err { return Err(DomExceptionOperationError::new(&err.to_string()).into()); @@ -682,10 +700,15 @@ pub fn op_webgpu_request_device( let limits = gfx_select!(device => instance.device_limits(device))?; let instance = instance.clone(); + let instance2 = instance.clone(); let rid = state.resource_table.add(WebGpuDevice(instance, device)); + let queue_rid = state + .resource_table + .add(queue::WebGpuQueue(instance2, queue)); - Ok(GpuAdapterDevice { + Ok(GpuDeviceRes { rid, + queue_rid, features, limits, // TODO(lucacasonato): report correctly from wgpu @@ -770,6 +793,6 @@ pub fn op_webgpu_create_query_set( gfx_put!(device => instance.device_create_query_set( device, &descriptor, - () + None ) => state, WebGpuQuerySet) } diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs index 4e8f5f6f9b..a6b0cb8cec 100644 --- a/ext/webgpu/pipeline.rs +++ b/ext/webgpu/pipeline.rs @@ -8,6 +8,7 @@ use deno_core::ResourceId; use serde::Deserialize; use serde::Serialize; use std::borrow::Cow; +use std::collections::HashMap; use std::rc::Rc; use super::error::WebGpuError; @@ -25,8 +26,7 @@ impl Resource for WebGpuPipelineLayout { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.pipeline_layout_drop(self.1)); + gfx_select!(self.1 => self.0.pipeline_layout_drop(self.1)); } } @@ -40,8 +40,7 @@ impl Resource for WebGpuComputePipeline { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.compute_pipeline_drop(self.1)); + gfx_select!(self.1 => self.0.compute_pipeline_drop(self.1)); } } @@ -55,8 +54,7 @@ impl Resource for WebGpuRenderPipeline { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.render_pipeline_drop(self.1)); + gfx_select!(self.1 => self.0.render_pipeline_drop(self.1)); } } @@ -77,8 +75,8 @@ pub enum GPUPipelineLayoutOrGPUAutoLayoutMode { #[serde(rename_all = "camelCase")] pub struct GpuProgrammableStage { module: ResourceId, - entry_point: String, - // constants: HashMap + entry_point: Option, + constants: Option>, } #[op2] @@ -114,16 +112,17 @@ pub fn op_webgpu_create_compute_pipeline( layout: pipeline_layout, stage: wgpu_core::pipeline::ProgrammableStageDescriptor { module: compute_shader_module_resource.1, - entry_point: Cow::from(compute.entry_point), - // TODO(lucacasonato): support args.compute.constants + entry_point: compute.entry_point.map(Cow::from), + constants: Cow::Owned(compute.constants.unwrap_or_default()), + zero_initialize_workgroup_memory: true, }, }; let implicit_pipelines = match layout { GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; MAX_BIND_GROUPS], }) } }; @@ -131,7 +130,7 @@ pub fn op_webgpu_create_compute_pipeline( let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( device, &descriptor, - (), + None, implicit_pipelines )); @@ -163,7 +162,7 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( .get::(compute_pipeline_rid)?; let compute_pipeline = compute_pipeline_resource.1; - let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, ())); + let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, None)); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); @@ -285,7 +284,8 @@ impl<'a> From #[serde(rename_all = "camelCase")] struct GpuVertexState { module: ResourceId, - entry_point: String, + entry_point: Option, + constants: Option>, buffers: Vec>, } @@ -312,8 +312,8 @@ impl From for wgpu_types::MultisampleState { struct GpuFragmentState { targets: Vec>, module: u32, - entry_point: String, - // TODO(lucacasonato): constants + entry_point: Option, + constants: Option>, } #[derive(Deserialize)] @@ -364,9 +364,12 @@ pub fn op_webgpu_create_render_pipeline( Some(wgpu_core::pipeline::FragmentState { stage: wgpu_core::pipeline::ProgrammableStageDescriptor { module: fragment_shader_module_resource.1, - entry_point: Cow::from(fragment.entry_point), + entry_point: fragment.entry_point.map(Cow::from), + constants: Cow::Owned(fragment.constants.unwrap_or_default()), + // Required to be true for WebGPU + zero_initialize_workgroup_memory: true, }, - targets: Cow::from(fragment.targets), + targets: Cow::Owned(fragment.targets), }) } else { None @@ -386,7 +389,10 @@ pub fn op_webgpu_create_render_pipeline( vertex: wgpu_core::pipeline::VertexState { stage: wgpu_core::pipeline::ProgrammableStageDescriptor { module: vertex_shader_module_resource.1, - entry_point: Cow::Owned(args.vertex.entry_point), + entry_point: args.vertex.entry_point.map(Cow::Owned), + constants: Cow::Owned(args.vertex.constants.unwrap_or_default()), + // Required to be true for WebGPU + zero_initialize_workgroup_memory: true, }, buffers: Cow::Owned(vertex_buffers), }, @@ -401,8 +407,8 @@ pub fn op_webgpu_create_render_pipeline( GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: (), - group_ids: &[(); MAX_BIND_GROUPS], + root_id: None, + group_ids: &[None; MAX_BIND_GROUPS], }) } }; @@ -410,7 +416,7 @@ pub fn op_webgpu_create_render_pipeline( let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( device, &descriptor, - (), + None, implicit_pipelines )); @@ -434,7 +440,7 @@ pub fn op_webgpu_render_pipeline_get_bind_group_layout( .get::(render_pipeline_rid)?; let render_pipeline = render_pipeline_resource.1; - let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, ())); + let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, None)); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); diff --git a/ext/webgpu/queue.rs b/ext/webgpu/queue.rs index 289b143758..8c8bbec95e 100644 --- a/ext/webgpu/queue.rs +++ b/ext/webgpu/queue.rs @@ -1,16 +1,28 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::command_encoder::WebGpuCommandBuffer; +use crate::Instance; use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; +use std::borrow::Cow; +use std::rc::Rc; use super::error::WebGpuResult; -type WebGpuQueue = super::WebGpuDevice; +pub struct WebGpuQueue(pub Instance, pub wgpu_core::id::QueueId); +impl Resource for WebGpuQueue { + fn name(&self) -> Cow { + "webGPUQueue".into() + } + + fn close(self: Rc) { + gfx_select!(self.1 => self.0.queue_drop(self.1)); + } +} #[op2] #[serde] @@ -19,7 +31,7 @@ pub fn op_webgpu_queue_submit( #[smi] queue_rid: ResourceId, #[serde] command_buffers: Vec, ) -> Result { - let instance = state.borrow::(); + let instance = state.borrow::(); let queue_resource = state.resource_table.get::(queue_rid)?; let queue = queue_resource.1; @@ -73,7 +85,7 @@ pub fn op_webgpu_write_buffer( #[number] size: Option, #[buffer] buf: &[u8], ) -> Result { - let instance = state.borrow::(); + let instance = state.borrow::(); let buffer_resource = state .resource_table .get::(buffer)?; @@ -106,7 +118,7 @@ pub fn op_webgpu_write_texture( #[serde] size: wgpu_types::Extent3d, #[buffer] buf: &[u8], ) -> Result { - let instance = state.borrow::(); + let instance = state.borrow::(); let texture_resource = state .resource_table .get::(destination.texture)?; diff --git a/ext/webgpu/render_pass.rs b/ext/webgpu/render_pass.rs index ee57a9bfc1..c68be3d99a 100644 --- a/ext/webgpu/render_pass.rs +++ b/ext/webgpu/render_pass.rs @@ -43,7 +43,7 @@ pub fn op_webgpu_render_pass_set_viewport( .resource_table .get::(args.render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport( + wgpu_core::command::render_commands::wgpu_render_pass_set_viewport( &mut render_pass_resource.0.borrow_mut(), args.x, args.y, @@ -70,7 +70,7 @@ pub fn op_webgpu_render_pass_set_scissor_rect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect( + wgpu_core::command::render_commands::wgpu_render_pass_set_scissor_rect( &mut render_pass_resource.0.borrow_mut(), x, y, @@ -92,7 +92,7 @@ pub fn op_webgpu_render_pass_set_blend_constant( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant( + wgpu_core::command::render_commands::wgpu_render_pass_set_blend_constant( &mut render_pass_resource.0.borrow_mut(), &color, ); @@ -111,7 +111,7 @@ pub fn op_webgpu_render_pass_set_stencil_reference( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference( + wgpu_core::command::render_commands::wgpu_render_pass_set_stencil_reference( &mut render_pass_resource.0.borrow_mut(), reference, ); @@ -130,7 +130,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_begin_occlusion_query( + wgpu_core::command::render_commands::wgpu_render_pass_begin_occlusion_query( &mut render_pass_resource.0.borrow_mut(), query_index, ); @@ -148,7 +148,7 @@ pub fn op_webgpu_render_pass_end_occlusion_query( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_end_occlusion_query( + wgpu_core::command::render_commands::wgpu_render_pass_end_occlusion_query( &mut render_pass_resource.0.borrow_mut(), ); @@ -177,15 +177,10 @@ pub fn op_webgpu_render_pass_execute_bundles( .resource_table .get::(render_pass_rid)?; - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles( - &mut render_pass_resource.0.borrow_mut(), - bundles.as_ptr(), - bundles.len(), - ); - } + wgpu_core::command::render_commands::wgpu_render_pass_execute_bundles( + &mut render_pass_resource.0.borrow_mut(), + &bundles, + ); Ok(WebGpuResult::empty()) } @@ -240,17 +235,12 @@ pub fn op_webgpu_render_pass_set_bind_group( let dynamic_offsets_data: &[u32] = &dynamic_offsets_data[start..start + len]; - // SAFETY: the raw pointer and length are of the same slice, and that slice - // lives longer than the below function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group( - &mut render_pass_resource.0.borrow_mut(), - index, - bind_group_resource.1, - dynamic_offsets_data.as_ptr(), - dynamic_offsets_data.len(), - ); - } + wgpu_core::command::render_commands::wgpu_render_pass_set_bind_group( + &mut render_pass_resource.0.borrow_mut(), + index, + bind_group_resource.1, + dynamic_offsets_data, + ); Ok(WebGpuResult::empty()) } @@ -266,16 +256,11 @@ pub fn op_webgpu_render_pass_push_debug_group( .resource_table .get::(render_pass_rid)?; - let label = std::ffi::CString::new(group_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + wgpu_core::command::render_commands::wgpu_render_pass_push_debug_group( + &mut render_pass_resource.0.borrow_mut(), + group_label, + 0, // wgpu#975 + ); Ok(WebGpuResult::empty()) } @@ -290,7 +275,7 @@ pub fn op_webgpu_render_pass_pop_debug_group( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group( + wgpu_core::command::render_commands::wgpu_render_pass_pop_debug_group( &mut render_pass_resource.0.borrow_mut(), ); @@ -308,16 +293,11 @@ pub fn op_webgpu_render_pass_insert_debug_marker( .resource_table .get::(render_pass_rid)?; - let label = std::ffi::CString::new(marker_label).unwrap(); - // SAFETY: the string the raw pointer points to lives longer than the below - // function invocation. - unsafe { - wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker( - &mut render_pass_resource.0.borrow_mut(), - label.as_ptr(), - 0, // wgpu#975 - ); - } + wgpu_core::command::render_commands::wgpu_render_pass_insert_debug_marker( + &mut render_pass_resource.0.borrow_mut(), + marker_label, + 0, // wgpu#975 + ); Ok(WebGpuResult::empty()) } @@ -337,7 +317,7 @@ pub fn op_webgpu_render_pass_set_pipeline( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline( + wgpu_core::command::render_commands::wgpu_render_pass_set_pipeline( &mut render_pass_resource.0.borrow_mut(), render_pipeline_resource.1, ); @@ -407,7 +387,7 @@ pub fn op_webgpu_render_pass_set_vertex_buffer( None }; - wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer( + wgpu_core::command::render_commands::wgpu_render_pass_set_vertex_buffer( &mut render_pass_resource.0.borrow_mut(), slot, buffer_resource.1, @@ -432,7 +412,7 @@ pub fn op_webgpu_render_pass_draw( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw( + wgpu_core::command::render_commands::wgpu_render_pass_draw( &mut render_pass_resource.0.borrow_mut(), vertex_count, instance_count, @@ -458,7 +438,7 @@ pub fn op_webgpu_render_pass_draw_indexed( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed( + wgpu_core::command::render_commands::wgpu_render_pass_draw_indexed( &mut render_pass_resource.0.borrow_mut(), index_count, instance_count, @@ -485,7 +465,7 @@ pub fn op_webgpu_render_pass_draw_indirect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect( + wgpu_core::command::render_commands::wgpu_render_pass_draw_indirect( &mut render_pass_resource.0.borrow_mut(), buffer_resource.1, indirect_offset, @@ -509,7 +489,7 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect( .resource_table .get::(render_pass_rid)?; - wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect( + wgpu_core::command::render_commands::wgpu_render_pass_draw_indexed_indirect( &mut render_pass_resource.0.borrow_mut(), buffer_resource.1, indirect_offset, diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs index dcd8e1c702..27c36802e6 100644 --- a/ext/webgpu/sampler.rs +++ b/ext/webgpu/sampler.rs @@ -21,8 +21,7 @@ impl Resource for WebGpuSampler { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.sampler_drop(self.1)); + gfx_select!(self.1 => self.0.sampler_drop(self.1)); } } @@ -75,6 +74,6 @@ pub fn op_webgpu_create_sampler( gfx_put!(device => instance.device_create_sampler( device, &descriptor, - () + None ) => state, WebGpuSampler) } diff --git a/ext/webgpu/shader.rs b/ext/webgpu/shader.rs index 0ba478ee46..0b3991c5de 100644 --- a/ext/webgpu/shader.rs +++ b/ext/webgpu/shader.rs @@ -20,8 +20,7 @@ impl Resource for WebGpuShaderModule { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.shader_module_drop(self.1)); + gfx_select!(self.1 => self.0.shader_module_drop(self.1)); } } @@ -50,6 +49,6 @@ pub fn op_webgpu_create_shader_module( device, &descriptor, source, - () + None ) => state, WebGpuShaderModule) } diff --git a/ext/webgpu/surface.rs b/ext/webgpu/surface.rs index 1371c1fa48..1f6d2c87d2 100644 --- a/ext/webgpu/surface.rs +++ b/ext/webgpu/surface.rs @@ -60,6 +60,7 @@ pub fn op_webgpu_surface_configure( present_mode: args.present_mode.unwrap_or_default(), alpha_mode: args.alpha_mode, view_formats: args.view_formats, + desired_maximum_frame_latency: 2, }; let err = @@ -85,7 +86,7 @@ pub fn op_webgpu_surface_get_current_texture( let surface = surface_resource.1; let output = - gfx_select!(device => instance.surface_get_current_texture(surface, ()))?; + gfx_select!(device => instance.surface_get_current_texture(surface, None))?; match output.status { SurfaceStatus::Good | SurfaceStatus::Suboptimal => { diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs index 63dc7b090a..44edd1a887 100644 --- a/ext/webgpu/texture.rs +++ b/ext/webgpu/texture.rs @@ -39,8 +39,7 @@ impl Resource for WebGpuTextureView { } fn close(self: Rc) { - let instance = &self.0; - gfx_select!(self.1 => instance.texture_view_drop(self.1, true)).unwrap(); + gfx_select!(self.1 => self.0.texture_view_drop(self.1, true)).unwrap(); } } @@ -84,7 +83,7 @@ pub fn op_webgpu_create_texture( let (val, maybe_err) = gfx_select!(device => instance.device_create_texture( device, &descriptor, - () + None )); let rid = state.resource_table.add(WebGpuTexture { @@ -129,6 +128,6 @@ pub fn op_webgpu_create_texture_view( gfx_put!(texture => instance.texture_create_view( texture, &descriptor, - () + None ) => state, WebGpuTextureView) } diff --git a/ext/webgpu/webgpu.idl b/ext/webgpu/webgpu.idl index 0b6b04eb4e..07d9d60ec7 100644 --- a/ext/webgpu/webgpu.idl +++ b/ext/webgpu/webgpu.idl @@ -6,7 +6,7 @@ dictionary GPUObjectDescriptorBase { USVString label = ""; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUSupportedLimits { readonly attribute unsigned long maxTextureDimension1D; readonly attribute unsigned long maxTextureDimension2D; @@ -30,6 +30,8 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxVertexAttributes; readonly attribute unsigned long maxVertexBufferArrayStride; readonly attribute unsigned long maxInterStageShaderComponents; + readonly attribute unsigned long maxColorAttachments; + readonly attribute unsigned long maxColorAttachmentBytesPerSample; readonly attribute unsigned long maxComputeWorkgroupStorageSize; readonly attribute unsigned long maxComputeInvocationsPerWorkgroup; readonly attribute unsigned long maxComputeWorkgroupSizeX; @@ -38,12 +40,12 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxComputeWorkgroupsPerDimension; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUSupportedFeatures { readonly setlike; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUAdapterInfo { readonly attribute DOMString vendor; readonly attribute DOMString architecture; @@ -57,9 +59,10 @@ interface mixin NavigatorGPU { Navigator includes NavigatorGPU; WorkerNavigator includes NavigatorGPU; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPU { Promise requestAdapter(optional GPURequestAdapterOptions options = {}); + GPUTextureFormat getPreferredCanvasFormat(); }; dictionary GPURequestAdapterOptions { @@ -72,14 +75,14 @@ enum GPUPowerPreference { "high-performance", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUAdapter { [SameObject] readonly attribute GPUSupportedFeatures features; [SameObject] readonly attribute GPUSupportedLimits limits; readonly attribute boolean isFallbackAdapter; Promise requestDevice(optional GPUDeviceDescriptor descriptor = {}); - Promise requestAdapterInfo(optional sequence unmaskHints = []); + Promise requestAdapterInfo(); }; dictionary GPUDeviceDescriptor @@ -103,6 +106,7 @@ enum GPUFeatureName { "shader-f16", "rg11b10ufloat-renderable", "bgra8unorm-storage", + "float32-filterable", // extended from spec @@ -140,7 +144,7 @@ enum GPUFeatureName { "shader-early-depth-test", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUDevice : EventTarget { [SameObject] readonly attribute GPUSupportedFeatures features; [SameObject] readonly attribute GPUSupportedLimits limits; @@ -170,7 +174,7 @@ interface GPUDevice : EventTarget { }; GPUDevice includes GPUObjectBase; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUBuffer { readonly attribute GPUSize64Out size; readonly attribute GPUFlagsConstant usage; @@ -199,7 +203,7 @@ dictionary GPUBufferDescriptor }; typedef [EnforceRange] unsigned long GPUBufferUsageFlags; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] namespace GPUBufferUsage { const GPUFlagsConstant MAP_READ = 0x0001; const GPUFlagsConstant MAP_WRITE = 0x0002; @@ -214,13 +218,13 @@ namespace GPUBufferUsage { }; typedef [EnforceRange] unsigned long GPUMapModeFlags; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] namespace GPUMapMode { const GPUFlagsConstant READ = 0x0001; const GPUFlagsConstant WRITE = 0x0002; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUTexture { GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {}); @@ -255,7 +259,7 @@ enum GPUTextureDimension { }; typedef [EnforceRange] unsigned long GPUTextureUsageFlags; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] namespace GPUTextureUsage { const GPUFlagsConstant COPY_SRC = 0x01; const GPUFlagsConstant COPY_DST = 0x02; @@ -264,7 +268,7 @@ namespace GPUTextureUsage { const GPUFlagsConstant RENDER_ATTACHMENT = 0x10; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUTextureView { }; GPUTextureView includes GPUObjectBase; @@ -327,6 +331,7 @@ enum GPUTextureFormat { "bgra8unorm-srgb", // Packed 32-bit formats "rgb9e5ufloat", + "rgb10a2uint", "rgb10a2unorm", "rg11b10ufloat", @@ -415,7 +420,7 @@ enum GPUTextureFormat { "astc-12x12-unorm-srgb", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUSampler { }; GPUSampler includes GPUObjectBase; @@ -461,7 +466,7 @@ enum GPUCompareFunction { "always", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUBindGroupLayout { }; GPUBindGroupLayout includes GPUObjectBase; @@ -482,7 +487,7 @@ dictionary GPUBindGroupLayoutEntry { }; typedef [EnforceRange] unsigned long GPUShaderStageFlags; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] namespace GPUShaderStage { const GPUFlagsConstant VERTEX = 0x1; const GPUFlagsConstant FRAGMENT = 0x2; @@ -527,6 +532,8 @@ dictionary GPUTextureBindingLayout { enum GPUStorageTextureAccess { "write-only", + "read-only", + "read-write", }; dictionary GPUStorageTextureBindingLayout { @@ -535,7 +542,7 @@ dictionary GPUStorageTextureBindingLayout { GPUTextureViewDimension viewDimension = "2d"; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUBindGroup { }; GPUBindGroup includes GPUObjectBase; @@ -559,7 +566,7 @@ dictionary GPUBufferBinding { GPUSize64 size; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUPipelineLayout { }; GPUPipelineLayout includes GPUObjectBase; @@ -569,7 +576,7 @@ dictionary GPUPipelineLayoutDescriptor required sequence bindGroupLayouts; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUShaderModule { }; GPUShaderModule includes GPUObjectBase; @@ -585,7 +592,7 @@ enum GPUCompilationMessageType { "info", }; -[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] +[Exposed=(Window, Worker), Serializable, SecureContext] interface GPUCompilationMessage { readonly attribute DOMString message; readonly attribute GPUCompilationMessageType type; @@ -595,11 +602,26 @@ interface GPUCompilationMessage { readonly attribute unsigned long long length; }; -[Exposed=(Window, DedicatedWorker), Serializable, SecureContext] +[Exposed=(Window, Worker), Serializable, SecureContext] interface GPUCompilationInfo { readonly attribute FrozenArray messages; }; +[Exposed=(Window, Worker), SecureContext, Serializable] +interface GPUPipelineError : DOMException { + constructor(optional DOMString message = "", GPUPipelineErrorInit options); + readonly attribute GPUPipelineErrorReason reason; +}; + +dictionary GPUPipelineErrorInit { + required GPUPipelineErrorReason reason; +}; + +enum GPUPipelineErrorReason { + "validation", + "internal", +}; + enum GPUAutoLayoutMode { "auto", }; @@ -615,13 +637,13 @@ interface mixin GPUPipelineBase { dictionary GPUProgrammableStage { required GPUShaderModule module; - required USVString entryPoint; + USVString entryPoint; record constants; }; -typedef double GPUPipelineConstantValue; // May represent WGSL’s bool, f32, i32, u32, and f16 if enabled. +typedef double GPUPipelineConstantValue; // May represent WGSL's bool, f32, i32, u32, and f16 if enabled. -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUComputePipeline { }; GPUComputePipeline includes GPUObjectBase; @@ -632,7 +654,7 @@ dictionary GPUComputePipelineDescriptor required GPUProgrammableStage compute; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPURenderPipeline { }; GPURenderPipeline includes GPUObjectBase; @@ -700,7 +722,7 @@ dictionary GPUBlendState { }; typedef [EnforceRange] unsigned long GPUColorWriteFlags; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] namespace GPUColorWrite { const GPUFlagsConstant RED = 0x1; const GPUFlagsConstant GREEN = 0x2; @@ -810,6 +832,7 @@ enum GPUVertexFormat { "sint32x2", "sint32x3", "sint32x4", + "unorm10-10-10-2", }; enum GPUVertexStepMode { @@ -853,7 +876,7 @@ dictionary GPUImageCopyTexture { GPUTextureAspect aspect = "all"; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUCommandBuffer { }; GPUCommandBuffer includes GPUObjectBase; @@ -865,7 +888,7 @@ dictionary GPUCommandBufferDescriptor interface mixin GPUCommandsMixin { }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUCommandEncoder { GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); @@ -932,7 +955,7 @@ interface mixin GPUDebugCommandsMixin { undefined insertDebugMarker(USVString markerLabel); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUComputePassEncoder { undefined setPipeline(GPUComputePipeline pipeline); undefined dispatchWorkgroups(GPUSize32 workgroupCountX, optional GPUSize32 workgroupCountY = 1, optional GPUSize32 workgroupCountZ = 1); @@ -956,7 +979,7 @@ dictionary GPUComputePassDescriptor GPUComputePassTimestampWrites timestampWrites; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPURenderPassEncoder { undefined setViewport(float x, float y, float width, float height, @@ -1051,7 +1074,7 @@ interface mixin GPURenderCommandsMixin { undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPURenderBundle { }; GPURenderBundle includes GPUObjectBase; @@ -1060,7 +1083,7 @@ dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase { }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPURenderBundleEncoder { GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {}); }; @@ -1076,7 +1099,7 @@ dictionary GPURenderBundleEncoderDescriptor boolean stencilReadOnly = false; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUQueue { undefined submit(sequence commandBuffers); @@ -1097,7 +1120,7 @@ interface GPUQueue { }; GPUQueue includes GPUObjectBase; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUQuerySet { undefined destroy(); @@ -1117,7 +1140,7 @@ enum GPUQueryType { "timestamp", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUCanvasContext { readonly attribute (HTMLCanvasElement or OffscreenCanvas) canvas; @@ -1145,7 +1168,7 @@ enum GPUDeviceLostReason { "destroyed", }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUDeviceLostInfo { readonly attribute GPUDeviceLostReason reason; readonly attribute DOMString message; @@ -1155,26 +1178,33 @@ partial interface GPUDevice { readonly attribute Promise lost; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUError { readonly attribute DOMString message; }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUValidationError : GPUError { constructor(DOMString message); }; -[Exposed=(Window, DedicatedWorker), SecureContext] +[Exposed=(Window, Worker), SecureContext] interface GPUOutOfMemoryError : GPUError { constructor(DOMString message); }; +[Exposed=(Window, Worker), SecureContext] +interface GPUInternalError + : GPUError { + constructor(DOMString message); +}; + enum GPUErrorFilter { "validation", "out-of-memory", + "internal", }; partial interface GPUDevice { @@ -1182,8 +1212,21 @@ partial interface GPUDevice { Promise popErrorScope(); }; +[Exposed=(Window, Worker), SecureContext] +interface GPUUncapturedErrorEvent : Event { + constructor( + DOMString type, + GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict + ); + [SameObject] readonly attribute GPUError error; +}; + +dictionary GPUUncapturedErrorEventInit : EventInit { + required GPUError error; +}; + partial interface GPUDevice { - [Exposed=(Window, DedicatedWorker)] + [Exposed=(Window, Worker)] attribute EventHandler onuncapturederror; }; diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index 7bac0192da..57e771f744 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -5145,7 +5145,7 @@ fn lsp_jsr_auto_import_completion() { json!({ "triggerKind": 1 }), ); assert!(!list.is_incomplete); - assert_eq!(list.items.len(), 264); + assert_eq!(list.items.len(), 267); let item = list.items.iter().find(|i| i.label == "add").unwrap(); assert_eq!(&item.label, "add"); assert_eq!( @@ -5225,7 +5225,7 @@ fn lsp_jsr_auto_import_completion_import_map() { json!({ "triggerKind": 1 }), ); assert!(!list.is_incomplete); - assert_eq!(list.items.len(), 264); + assert_eq!(list.items.len(), 267); let item = list.items.iter().find(|i| i.label == "add").unwrap(); assert_eq!(&item.label, "add"); assert_eq!(json!(&item.label_details), json!({ "description": "add" })); diff --git a/tools/wgpu_sync.js b/tools/wgpu_sync.js index 4efb9c6b82..5844c68a21 100755 --- a/tools/wgpu_sync.js +++ b/tools/wgpu_sync.js @@ -3,9 +3,9 @@ import { join, ROOT_PATH } from "./util.js"; -const COMMIT = "49b7ec97c164bac9ee877f45cdd806fbefecc5a4"; +const COMMIT = "4521502da69bcf4f92c8350042c268573ef216d4"; const REPO = "gfx-rs/wgpu"; -const V_WGPU = "0.18"; +const V_WGPU = "0.20"; const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu"); async function bash(subcmd, opts = {}) {