diff --git a/.deny.toml b/.deny.toml index efcee7579eb..e4ea5c6d163 100644 --- a/.deny.toml +++ b/.deny.toml @@ -8,6 +8,10 @@ skip-tree = [ { name = "rustc_version", version = "0.2.3" }, { name = "sourcemap", version = "7.1.1" }, { name = "miniz_oxide", version = "0.7.4" }, + + # introduced by Deno, to be investigated + { name = "deno_core", version = "0.321.0" }, + { name = "deno_permissions", version = "0.39.0" }, ] skip = [ # Strum uses an old version diff --git a/Cargo.lock b/Cargo.lock index b7ea17b9b54..6281711aa29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -306,15 +306,50 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec 0.6.3", +] + [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit-vec" version = "0.8.0" @@ -337,6 +372,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block" version = "0.1.6" @@ -449,6 +496,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -503,6 +559,17 @@ dependencies = [ "half", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.23" @@ -610,12 +677,6 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "013b6c2c3a14d678f38cd23994b02da3a1a1b6a5d1eedddfe63a5a5f11b13a81" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cooked-waker" version = "5.0.0" @@ -786,33 +847,34 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.143.0" +version = "0.179.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f770d8deb0eb0bfd596d242d9eaef5312ef57f0130964cb53c7f6a8107d13be" +checksum = "2e09f2bbb2d842329b602da25dbab5cd4a342f9a8adcb7c02509fc322f796e79" dependencies = [ "deno_core", ] [[package]] name = "deno_core" -version = "0.272.0" +version = "0.321.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07093891f2af763023614cfe2d1ce5f9ce5a7920c4fcf2f00911bd0d93083523" +checksum = "cd2a54cda74cdc187d5fc2d23370a45cf09f912caf566dd1cd24a50157d809c7" dependencies = [ "anyhow", "bincode", - "bit-set", - "bit-vec", + "bit-set 0.5.3", + "bit-vec 0.6.3", "bytes", "cooked-waker", "deno_core_icudata", "deno_ops", "deno_unsync", "futures", + "indexmap", "libc", - "log", "memoffset", "parking_lot", + "percent-encoding", "pin-project", "serde", "serde_json", @@ -823,76 +885,122 @@ dependencies = [ "tokio", "url", "v8", + "wasm_dep_analyzer", ] [[package]] name = "deno_core_icudata" -version = "0.0.73" +version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_ops" -version = "0.148.0" +version = "0.197.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc73fc07ad26e71715d5a726d1dd228587c0d121a591b1931a0fcf958a2ec3b" +checksum = "37a8825d92301cf445727c43f17fee2a20fcdf4370004339965156ae7c56c97e" dependencies = [ "proc-macro-rules", "proc-macro2", "quote", + "stringcase", "strum", "strum_macros", "syn", "thiserror", ] +[[package]] +name = "deno_path_util" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff25f6e08e7a0214bbacdd6f7195c7f1ebcd850c87a624e4ff06326b68b42d99" +dependencies = [ + "percent-encoding", + "thiserror", + "url", +] + +[[package]] +name = "deno_permissions" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e822f98185ab3ddf06104b2407681e0008af52361af32f1cd171b7eda5aa59" +dependencies = [ + "deno_core", + "deno_path_util", + "deno_terminal", + "fqdn", + "libc", + "log", + "once_cell", + "percent-encoding", + "serde", + "thiserror", + "which 4.4.2", + "winapi", +] + +[[package]] +name = "deno_terminal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daef12499e89ee99e51ad6000a91f600d3937fb028ad4918af76810c5bc9e0d5" +dependencies = [ + "once_cell", + "termcolor", +] + [[package]] name = "deno_unsync" -version = "0.3.10" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c8b95582c2023dbb66fccc37421b374026f5915fa507d437cb566904db9a3a" +checksum = "d774fd83f26b24f0805a6ab8b26834a0d06ceac0db517b769b1e4633c96a2057" dependencies = [ + "futures", "parking_lot", "tokio", ] [[package]] name = "deno_url" -version = "0.143.0" +version = "0.179.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d9e6ffd6a7157bfd3cf1385c59232e49587c9bbb898e64010f7f082242a203" +checksum = "ad9a108794e505f2b07665e19ff336c1bcba6adcf7182c90c1d3a6c741d7fcd0" dependencies = [ "deno_core", - "serde", + "thiserror", "urlpattern", ] [[package]] name = "deno_web" -version = "0.174.0" +version = "0.210.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708666b5b346e6880c1372006615814db7fc5ef36bd1785f0b0e4f8617082999" +checksum = "7679087bcc41f7ae3385f8c12d43bc81cfc54cb9b1ef73983d20f5e39fa4e0da" dependencies = [ "async-trait", "base64-simd 0.8.0", "bytes", "deno_core", + "deno_permissions", "encoding_rs", "flate2", "futures", "serde", + "thiserror", "tokio", "uuid", - "windows-sys 0.48.0", ] [[package]] name = "deno_webgpu" -version = "0.118.0" +version = "0.146.0" dependencies = [ "deno_core", "raw-window-handle 0.6.2", "serde", + "thiserror", "tokio", "wgpu-core", "wgpu-types", @@ -900,9 +1008,9 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.143.0" +version = "0.179.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddad93aa68e3c3c2d36976cd401af27a6ce750c23060e02401daf240f2acbe2" +checksum = "5b55d845e3d64f8de7eff67aaa4b6fe1b23bbc2efe967c984f8c64c8dd85fad4" dependencies = [ "deno_core", ] @@ -918,19 +1026,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn", -] - [[package]] name = "diff" version = "0.1.13" @@ -1152,6 +1247,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fqdn" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb540cf7bc4fe6df9d8f7f0c974cfd0dce8ed4e9e8884e73433b503ee78b4e7d" + [[package]] name = "fslock" version = "0.2.1" @@ -1162,6 +1263,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.31" @@ -2010,6 +2117,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -2046,7 +2159,7 @@ version = "23.0.0" dependencies = [ "arbitrary", "arrayvec", - "bit-set", + "bit-set 0.8.0", "bitflags 2.6.0", "cfg_aliases 0.2.1", "codespan-reporting", @@ -2157,6 +2270,16 @@ dependencies = [ "rand_xorshift", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2528,6 +2651,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -2593,6 +2726,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -2762,16 +2901,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver 1.0.23", + "semver", ] [[package]] @@ -2842,12 +2972,6 @@ dependencies = [ "semver-parser", ] -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - [[package]] name = "semver-parser" version = "0.7.0" @@ -2898,11 +3022,10 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.181.0" +version = "0.230.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd25bb66a20a1a405fb3733aaaf8a8a77a14fd55c8f5fd9db2a2e95bbd7eeab9" +checksum = "b5a783242d2af51d6955cc04bf2b64adb643ab588b61e9573c908a69dabf8c2f" dependencies = [ - "bytes", "num-bigint", "serde", "smallvec", @@ -3019,15 +3142,17 @@ dependencies = [ [[package]] name = "sourcemap" -version = "7.1.1" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7768edd06c02535e0d50653968f46e1e0d3aa54742190d35dd9466f59de9c71" +checksum = "208d40b9e8cad9f93613778ea295ed8f3c2b1824217c6cfc7219d3f6f45b96d4" dependencies = [ "base64-simd 0.7.0", + "bitvec", "data-encoding", "debugid", "if_chain", - "rustc_version 0.2.3", + "rustc-hash", + "rustc_version", "serde", "serde_json", "unicode-id-start", @@ -3079,6 +3204,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "stringcase" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04028eeb851ed08af6aba5caa29f2d59a13ed168cee4d6bd753aeefcf1d636b0" + [[package]] name = "strsim" version = "0.11.1" @@ -3129,6 +3260,12 @@ dependencies = [ "syn", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-triple" version = "0.1.3" @@ -3477,11 +3614,10 @@ dependencies = [ [[package]] name = "urlpattern" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" dependencies = [ - "derive_more", "regex", "serde", "unic-ucd-ident", @@ -3518,17 +3654,19 @@ dependencies = [ [[package]] name = "v8" -version = "0.89.0" +version = "130.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe2197fbef82c98f7953d13568a961d4e1c663793b5caf3c74455a13918cdf33" +checksum = "2ee0be58935708fa4d7efb970c6cf9f2d9511d24ee24246481a65b6ee167348d" dependencies = [ + "bindgen", "bitflags 2.6.0", "fslock", "gzip-header", "home", "miniz_oxide 0.7.4", "once_cell", - "which", + "paste", + "which 6.0.3", ] [[package]] @@ -3659,6 +3797,15 @@ dependencies = [ "syn", ] +[[package]] +name = "wasm_dep_analyzer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8" +dependencies = [ + "thiserror", +] + [[package]] name = "wayland-backend" version = "0.3.7" @@ -3834,7 +3981,7 @@ name = "wgpu-core" version = "23.0.1" dependencies = [ "arrayvec", - "bit-vec", + "bit-vec 0.8.0", "bitflags 2.6.0", "bytemuck", "cfg_aliases 0.2.1", @@ -3893,7 +4040,7 @@ dependencies = [ "android_system_properties", "arrayvec", "ash", - "bit-set", + "bit-set 0.8.0", "bitflags 2.6.0", "block", "bytemuck", @@ -4009,15 +4156,26 @@ dependencies = [ [[package]] name = "which" -version = "5.0.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", "home", "once_cell", "rustix", - "windows-sys 0.48.0", +] + +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", ] [[package]] @@ -4387,6 +4545,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "write16" version = "1.0.0" @@ -4399,6 +4563,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11-dl" version = "2.21.0" diff --git a/Cargo.toml b/Cargo.toml index af9f81fcb3d..93858f94190 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -178,12 +178,12 @@ web-sys = "0.3.74" web-time = "0.2.4" # deno dependencies -deno_console = "0.143.0" -deno_core = "0.272.0" -deno_url = "0.143.0" -deno_web = "0.174.0" -deno_webidl = "0.143.0" -deno_webgpu = { version = "0.118.0", path = "./deno_webgpu" } +deno_console = "0.179.0" +deno_core = "0.321.0" +deno_url = "0.179.0" +deno_web = "0.210.0" +deno_webidl = "0.179.0" +deno_webgpu = { version = "0.146.0", path = "./deno_webgpu" } tokio = "1.41.1" termcolor = "1.4.1" diff --git a/cts_runner/src/main.rs b/cts_runner/src/main.rs index fe8c1cf8187..1899c122c15 100644 --- a/cts_runner/src/main.rs +++ b/cts_runner/src/main.rs @@ -21,6 +21,78 @@ mod native { use termcolor::ColorSpec; use termcolor::WriteColor; + // temporary + fn get_webgpu_error_class(e: &deno_webgpu::InitError) -> &'static str { + match e { + deno_webgpu::InitError::Resource(e) => { + deno_core::error::get_custom_error_class(e).unwrap_or("Error") + } + deno_webgpu::InitError::RequestDevice(_) => "DOMExceptionOperationError", + } + } + + fn get_webgpu_buffer_error_class(e: &deno_webgpu::buffer::BufferError) -> &'static str { + match e { + deno_webgpu::buffer::BufferError::Resource(e) => { + deno_core::error::get_custom_error_class(e).unwrap_or("Error") + } + deno_webgpu::buffer::BufferError::InvalidUsage => "TypeError", + deno_webgpu::buffer::BufferError::Access(_) => "DOMExceptionOperationError", + deno_webgpu::buffer::BufferError::Canceled(_) => "Error", + } + } + + fn get_webgpu_bundle_error_class(e: &deno_webgpu::bundle::BundleError) -> &'static str { + match e { + deno_webgpu::bundle::BundleError::Resource(e) => { + deno_core::error::get_custom_error_class(e).unwrap_or("Error") + } + deno_webgpu::bundle::BundleError::InvalidSize => "TypeError", + } + } + + fn get_webgpu_byow_error_class(e: &deno_webgpu::byow::ByowError) -> &'static str { + match e { + deno_webgpu::byow::ByowError::WebGPUNotInitiated => "TypeError", + deno_webgpu::byow::ByowError::InvalidParameters => "TypeError", + deno_webgpu::byow::ByowError::CreateSurface(_) => "Error", + deno_webgpu::byow::ByowError::InvalidSystem => "TypeError", + #[cfg(any( + target_os = "windows", + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd" + ))] + deno_webgpu::byow::ByowError::NullWindow => "TypeError", + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + deno_webgpu::byow::ByowError::NullDisplay => "TypeError", + #[cfg(target_os = "macos")] + deno_webgpu::byow::ByowError::NSViewDisplay => "TypeError", + } + } + + fn get_webgpu_render_pass_error_class( + e: &deno_webgpu::render_pass::RenderPassError, + ) -> &'static str { + match e { + deno_webgpu::render_pass::RenderPassError::Resource(e) => { + deno_core::error::get_custom_error_class(e).unwrap_or("Error") + } + deno_webgpu::render_pass::RenderPassError::InvalidSize => "TypeError", + deno_webgpu::render_pass::RenderPassError::RenderPass(_) => "Error", + } + } + + fn get_webgpu_surface_error_class(e: &deno_webgpu::surface::SurfaceError) -> &'static str { + match e { + deno_webgpu::surface::SurfaceError::Resource(e) => { + deno_core::error::get_custom_error_class(e).unwrap_or("Error") + } + deno_webgpu::surface::SurfaceError::Surface(_) => "Error", + deno_webgpu::surface::SurfaceError::InvalidStatus => "Error", + } + } + pub async fn run() -> Result<(), AnyError> { let mut args_iter = env::args(); let _ = args_iter.next(); @@ -112,7 +184,30 @@ mod native { fn get_error_class_name(e: &AnyError) -> &'static str { deno_core::error::get_custom_error_class(e) - .or_else(|| deno_webgpu::error::get_error_class_name(e)) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_error_class) + }) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_buffer_error_class) + }) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_bundle_error_class) + }) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_byow_error_class) + }) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_render_pass_error_class) + }) + .or_else(|| { + e.downcast_ref::() + .map(get_webgpu_surface_error_class) + }) .unwrap_or_else(|| { panic!("Error '{e}' contains boxed error of unsupported type: {e:#}"); }) diff --git a/deno_webgpu/01_webgpu.js b/deno_webgpu/01_webgpu.js index f79d0ecd4fb..0222391713a 100644 --- a/deno_webgpu/01_webgpu.js +++ b/deno_webgpu/01_webgpu.js @@ -98,6 +98,11 @@ const { ArrayPrototypePush, DataViewPrototypeGetBuffer, Error, + Number, + NumberPOSITIVE_INFINITY, + NumberMAX_SAFE_INTEGER, + NumberNEGATIVE_INFINITY, + NumberMIN_SAFE_INTEGER, MathMax, ObjectDefineProperty, ObjectHasOwn, @@ -137,6 +142,8 @@ const _mappingRange = Symbol("[[mapping_range]]"); const _mappedRanges = Symbol("[[mapped_ranges]]"); const _mapMode = Symbol("[[map_mode]]"); const _adapter = Symbol("[[adapter]]"); +const _adapterInfo = Symbol("[[adapterInfo]]"); +const _invalid = Symbol("[[invalid]]"); const _cleanup = Symbol("[[cleanup]]"); const _vendor = Symbol("[[vendor]]"); const _architecture = Symbol("[[architecture]]"); @@ -173,7 +180,7 @@ function assertDevice(self, prefix, context) { const deviceRid = device?.rid; if (deviceRid === undefined) { throw new DOMException( - `${prefix}: ${context} references an invalid or destroyed device.`, + `${prefix}: ${context} references an invalid or destroyed device`, "OperationError", ); } @@ -190,7 +197,7 @@ function assertResource(self, prefix, context) { const rid = self[_rid]; if (rid === undefined) { throw new DOMException( - `${prefix}: ${context} an invalid or destroyed resource.`, + `${prefix}: ${context} an invalid or destroyed resource`, "OperationError", ); } @@ -337,7 +344,7 @@ class GPU { * @param {GPURequestAdapterOptions} options */ // deno-lint-ignore require-await - async requestAdapter(options = {}) { + async requestAdapter(options = { __proto__: null }) { webidl.assertBranded(this, GPUPrototype); options = webidl.converters.GPURequestAdapterOptions( options, @@ -396,11 +403,11 @@ function createGPUAdapter(inner) { return adapter; } -const _invalid = Symbol("[[invalid]]"); class GPUAdapter { /** @type {InnerGPUAdapter} */ [_adapter]; - /** @type {bool} */ + [_adapterInfo]; + /** @type {boolean} */ [_invalid]; /** @returns {GPUSupportedFeatures} */ @@ -416,7 +423,7 @@ class GPUAdapter { /** @returns {boolean} */ get isFallbackAdapter() { webidl.assertBranded(this, GPUAdapterPrototype); - return this[_adapter].isFallbackAdapter; + return this[_adapter].isFallback; } constructor() { @@ -428,7 +435,7 @@ class GPUAdapter { * @returns {Promise} */ // deno-lint-ignore require-await - async requestDevice(descriptor = {}) { + async requestDevice(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUAdapterPrototype); const prefix = "Failed to execute 'requestDevice' on 'GPUAdapter'"; descriptor = webidl.converters.GPUDeviceDescriptor( @@ -443,7 +450,7 @@ class GPUAdapter { !SetPrototypeHas(this[_adapter].features[webidl.setlikeInner], feature) ) { throw new TypeError( - `${prefix}: requiredFeatures must be a subset of the adapter features.`, + `${prefix}: requiredFeatures must be a subset of the adapter features`, ); } } @@ -481,11 +488,15 @@ class GPUAdapter { } /** - * @returns {Promise} + * @returns {GPUAdapterInfo} */ - requestAdapterInfo() { + get info() { webidl.assertBranded(this, GPUAdapterPrototype); + if (this[_adapterInfo] !== undefined) { + return this[_adapterInfo]; + } + if (this[_invalid]) { throw new TypeError( "The adapter cannot be reused, as it has been invalidated by a device creation", @@ -504,7 +515,8 @@ class GPUAdapter { adapterInfo[_architecture] = architecture; adapterInfo[_device] = device; adapterInfo[_description] = description; - return PromiseResolve(adapterInfo); + this[_adapterInfo] = adapterInfo; + return adapterInfo; } [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { @@ -515,6 +527,7 @@ class GPUAdapter { keys: [ "features", "limits", + "info", "isFallbackAdapter", ], }), @@ -582,6 +595,18 @@ function createGPUSupportedLimits(limits) { return adapterFeatures; } +function normalizeLimit(limit) { + if (typeof limit === "bigint") { + limit = Number(limit); + if (limit === NumberPOSITIVE_INFINITY) { + limit = NumberMAX_SAFE_INTEGER; + } else if (limit === NumberNEGATIVE_INFINITY) { + limit = NumberMIN_SAFE_INTEGER; + } + } + return limit; +} + /** * @typedef InnerAdapterLimits * @property {number} maxTextureDimension1D @@ -621,123 +646,127 @@ class GPUSupportedLimits { get maxTextureDimension1D() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxTextureDimension1D; + return normalizeLimit(this[_limits].maxTextureDimension1D); } get maxTextureDimension2D() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxTextureDimension2D; + return normalizeLimit(this[_limits].maxTextureDimension2D); } get maxTextureDimension3D() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxTextureDimension3D; + return normalizeLimit(this[_limits].maxTextureDimension3D); } get maxTextureArrayLayers() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxTextureArrayLayers; + return normalizeLimit(this[_limits].maxTextureArrayLayers); } get maxBindGroups() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxBindGroups; + return normalizeLimit(this[_limits].maxBindGroups); } get maxBindingsPerBindGroup() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxBindingsPerBindGroup; + return normalizeLimit(this[_limits].maxBindingsPerBindGroup); } get maxBufferSize() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxBufferSize; + return normalizeLimit(this[_limits].maxBufferSize); } get maxDynamicUniformBuffersPerPipelineLayout() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxDynamicUniformBuffersPerPipelineLayout; + return normalizeLimit( + this[_limits].maxDynamicUniformBuffersPerPipelineLayout, + ); } get maxDynamicStorageBuffersPerPipelineLayout() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxDynamicStorageBuffersPerPipelineLayout; + return normalizeLimit( + this[_limits].maxDynamicStorageBuffersPerPipelineLayout, + ); } get maxSampledTexturesPerShaderStage() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxSampledTexturesPerShaderStage; + return normalizeLimit(this[_limits].maxSampledTexturesPerShaderStage); } get maxSamplersPerShaderStage() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxSamplersPerShaderStage; + return normalizeLimit(this[_limits].maxSamplersPerShaderStage); } get maxStorageBuffersPerShaderStage() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxStorageBuffersPerShaderStage; + return normalizeLimit(this[_limits].maxStorageBuffersPerShaderStage); } get maxStorageTexturesPerShaderStage() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxStorageTexturesPerShaderStage; + return normalizeLimit(this[_limits].maxStorageTexturesPerShaderStage); } get maxUniformBuffersPerShaderStage() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxUniformBuffersPerShaderStage; + return normalizeLimit(this[_limits].maxUniformBuffersPerShaderStage); } get maxUniformBufferBindingSize() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxUniformBufferBindingSize; + return normalizeLimit(this[_limits].maxUniformBufferBindingSize); } get maxStorageBufferBindingSize() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxStorageBufferBindingSize; + return normalizeLimit(this[_limits].maxStorageBufferBindingSize); } get minUniformBufferOffsetAlignment() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].minUniformBufferOffsetAlignment; + return normalizeLimit(this[_limits].minUniformBufferOffsetAlignment); } get minStorageBufferOffsetAlignment() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].minStorageBufferOffsetAlignment; + return normalizeLimit(this[_limits].minStorageBufferOffsetAlignment); } get maxVertexBuffers() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxVertexBuffers; + return normalizeLimit(this[_limits].maxVertexBuffers); } get maxVertexAttributes() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxVertexAttributes; + return normalizeLimit(this[_limits].maxVertexAttributes); } get maxVertexBufferArrayStride() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxVertexBufferArrayStride; + return normalizeLimit(this[_limits].maxVertexBufferArrayStride); } get maxInterStageShaderComponents() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxInterStageShaderComponents; + return normalizeLimit(this[_limits].maxInterStageShaderComponents); } get maxColorAttachments() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxColorAttachments; + return normalizeLimit(this[_limits].maxColorAttachments); } get maxColorAttachmentBytesPerSample() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxColorAttachmentBytesPerSample; + return normalizeLimit(this[_limits].maxColorAttachmentBytesPerSample); } get maxComputeWorkgroupStorageSize() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeWorkgroupStorageSize; + return normalizeLimit(this[_limits].maxComputeWorkgroupStorageSize); } get maxComputeInvocationsPerWorkgroup() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeInvocationsPerWorkgroup; + return normalizeLimit(this[_limits].maxComputeInvocationsPerWorkgroup); } get maxComputeWorkgroupSizeX() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeWorkgroupSizeX; + return normalizeLimit(this[_limits].maxComputeWorkgroupSizeX); } get maxComputeWorkgroupSizeY() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeWorkgroupSizeY; + return normalizeLimit(this[_limits].maxComputeWorkgroupSizeY); } get maxComputeWorkgroupSizeZ() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeWorkgroupSizeZ; + return normalizeLimit(this[_limits].maxComputeWorkgroupSizeZ); } get maxComputeWorkgroupsPerDimension() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); - return this[_limits].maxComputeWorkgroupsPerDimension; + return normalizeLimit(this[_limits].maxComputeWorkgroupsPerDimension); } [SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) { @@ -875,6 +904,7 @@ const GPUDeviceLostInfoPrototype = GPUDeviceLostInfo.prototype; function GPUObjectBaseMixin(name, type) { type.prototype[_label] = null; ObjectDefineProperty(type.prototype, "label", { + __proto__: null, /** * @return {string | null} */ @@ -977,7 +1007,7 @@ class InnerGPUDevice { ); break; case "out-of-memory": - constructedError = new GPUOutOfMemoryError(); + constructedError = new GPUOutOfMemoryError("not enough memory left"); break; case "internal": constructedError = new GPUInternalError(); @@ -1153,7 +1183,7 @@ class GPUDevice extends EventTarget { * @param {GPUSamplerDescriptor} descriptor * @returns {GPUSampler} */ - createSampler(descriptor = {}) { + createSampler(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUDevicePrototype); const prefix = "Failed to execute 'createSampler' on 'GPUDevice'"; descriptor = webidl.converters.GPUSamplerDescriptor( @@ -1434,6 +1464,7 @@ class GPUDevice extends EventTarget { fragment = { module, entryPoint: descriptor.fragment.entryPoint, + constants: descriptor.fragment.constants, targets: descriptor.fragment.targets, }; } @@ -1445,6 +1476,7 @@ class GPUDevice extends EventTarget { vertex: { module, entryPoint: descriptor.vertex.entryPoint, + constants: descriptor.vertex.constants, buffers: descriptor.vertex.buffers, }, primitive: descriptor.primitive, @@ -1557,6 +1589,7 @@ class GPUDevice extends EventTarget { fragment = { module, entryPoint: descriptor.fragment.entryPoint, + constants: descriptor.fragment.constants, targets: descriptor.fragment.targets, }; } @@ -1568,6 +1601,7 @@ class GPUDevice extends EventTarget { vertex: { module, entryPoint: descriptor.vertex.entryPoint, + constants: descriptor.vertex.constants, buffers: descriptor.vertex.buffers, }, primitive: descriptor.primitive, @@ -1599,14 +1633,14 @@ class GPUDevice extends EventTarget { rid, ); device.trackResource(renderPipeline); - return renderPipeline; + return PromiseResolve(renderPipeline); } /** * @param {GPUCommandEncoderDescriptor} descriptor * @returns {GPUCommandEncoder} */ - createCommandEncoder(descriptor = {}) { + createCommandEncoder(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUDevicePrototype); const prefix = "Failed to execute 'createCommandEncoder' on 'GPUDevice'"; descriptor = webidl.converters.GPUCommandEncoderDescriptor( @@ -1723,12 +1757,12 @@ class GPUDevice extends EventTarget { const prefix = "Failed to execute 'popErrorScope' on 'GPUDevice'"; const device = assertDevice(this, prefix, "this"); if (device.isLost) { - throw new DOMException("Device has been lost.", "OperationError"); + 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.", + "There are no error scopes on the error scope stack", "OperationError", ); } @@ -1761,7 +1795,7 @@ defineEventHandler(GPUDevice.prototype, "uncapturederror"); class GPUPipelineError extends DOMException { #reason; - constructor(message = "", options = {}) { + constructor(message = "", options = { __proto__: null }) { const prefix = "Failed to construct 'GPUPipelineError'"; message = webidl.converters.DOMString(message, prefix, "Argument 1"); options = webidl.converters.GPUPipelineErrorInit( @@ -2084,25 +2118,25 @@ class GPUBuffer { } if ((offset % 8) !== 0) { throw new DOMException( - `${prefix}: offset must be a multiple of 8.`, + `${prefix}: offset must be a multiple of 8, received ${offset}`, "OperationError", ); } if ((rangeSize % 4) !== 0) { throw new DOMException( - `${prefix}: rangeSize must be a multiple of 4.`, + `${prefix}: rangeSize must be a multiple of 4, received ${rangeSize}`, "OperationError", ); } if ((offset + rangeSize) > this[_size]) { throw new DOMException( - `${prefix}: offset + rangeSize must be less than or equal to buffer size.`, + `${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.`, + `${prefix}: GPUBuffer is not currently unmapped`, "OperationError", ); } @@ -2110,19 +2144,19 @@ class GPUBuffer { 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.`, + `${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.`, + `${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.`, + `${prefix}: WRITE map mode not valid because buffer does not have MAP_WRITE usage`, "OperationError", ); } @@ -2169,7 +2203,7 @@ class GPUBuffer { const mappedRanges = this[_mappedRanges]; if (!mappedRanges) { - throw new DOMException(`${prefix}: invalid state.`, "OperationError"); + throw new DOMException(`${prefix}: invalid state`, "OperationError"); } for (let i = 0; i < mappedRanges.length; ++i) { const { 0: buffer, 1: _rid, 2: start } = mappedRanges[i]; @@ -2180,7 +2214,7 @@ class GPUBuffer { (end >= offset && end < (offset + rangeSize)) ) { throw new DOMException( - `${prefix}: requested buffer overlaps with another mapped range.`, + `${prefix}: requested buffer overlaps with another mapped range`, "OperationError", ); } @@ -2206,14 +2240,14 @@ class GPUBuffer { const bufferRid = assertResource(this, prefix, "this"); if (this[_state] === "unmapped" || this[_state] === "destroyed") { throw new DOMException( - `${prefix}: buffer is not ready to be unmapped.`, + `${prefix}: buffer is not ready to be unmapped`, "OperationError", ); } if (this[_state] === "pending") { // TODO(lucacasonato): this is not spec compliant. throw new DOMException( - `${prefix}: can not unmap while mapping. This is a Deno limitation.`, + `${prefix}: can not unmap while mapping, this is a Deno limitation`, "OperationError", ); } else if ( @@ -2227,7 +2261,7 @@ class GPUBuffer { const mapMode = this[_mapMode]; if (mapMode === undefined) { throw new DOMException( - `${prefix}: invalid state.`, + `${prefix}: invalid state`, "OperationError", ); } @@ -2238,7 +2272,7 @@ class GPUBuffer { const mappedRanges = this[_mappedRanges]; if (!mappedRanges) { - throw new DOMException(`${prefix}: invalid state.`, "OperationError"); + throw new DOMException(`${prefix}: invalid state`, "OperationError"); } for (let i = 0; i < mappedRanges.length; ++i) { const { 0: buffer, 1: mappedRid } = mappedRanges[i]; @@ -2403,7 +2437,7 @@ class GPUTexture { /** * @param {GPUTextureViewDescriptor} descriptor */ - createView(descriptor = {}) { + createView(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUTexturePrototype); const prefix = "Failed to execute 'createView' on 'GPUTexture'"; webidl.requiredArguments(arguments.length, 0, prefix); @@ -3183,7 +3217,7 @@ class GPUCommandEncoder { /** * @param {GPUComputePassDescriptor} descriptor */ - beginComputePass(descriptor = {}) { + beginComputePass(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUCommandEncoderPrototype); const prefix = "Failed to execute 'beginComputePass' on 'GPUCommandEncoder'"; @@ -3577,7 +3611,7 @@ class GPUCommandEncoder { * @param {GPUCommandBufferDescriptor} descriptor * @returns {GPUCommandBuffer} */ - finish(descriptor = {}) { + finish(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPUCommandEncoderPrototype); const prefix = "Failed to execute 'finish' on 'GPUCommandEncoder'"; descriptor = webidl.converters.GPUCommandBufferDescriptor( @@ -4544,7 +4578,7 @@ class GPURenderBundleEncoder { /** * @param {GPURenderBundleDescriptor} descriptor */ - finish(descriptor = {}) { + finish(descriptor = { __proto__: null }) { webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'finish' on 'GPURenderBundleEncoder'"; descriptor = webidl.converters.GPURenderBundleDescriptor( @@ -5271,7 +5305,7 @@ webidl.converters["GPUExtent3D"] = (V, opts) => { if (V.length < min || V.length > max) { throw webidl.makeException( TypeError, - `A sequence of number used as a GPUExtent3D must have between ${min} and ${max} elements.`, + `A sequence of number used as a GPUExtent3D must have between ${min} and ${max} elements, received ${V.length} elements`, opts, ); } @@ -5281,7 +5315,7 @@ webidl.converters["GPUExtent3D"] = (V, opts) => { } throw webidl.makeException( TypeError, - "can not be converted to sequence or GPUExtent3DDict.", + "can not be converted to sequence or GPUExtent3DDict", opts, ); }; @@ -6379,6 +6413,10 @@ webidl.converters["GPUBlendFactor"] = webidl.createEnumConverter( "src-alpha-saturated", "constant", "one-minus-constant", + "src1", + "one-minus-src1", + "src1-alpha", + "one-minus-src1-alpha", ], ); @@ -6615,7 +6653,7 @@ webidl.converters["GPUOrigin3D"] = (V, opts) => { if (V.length > length) { throw webidl.makeException( TypeError, - `A sequence of number used as a GPUOrigin3D must have at most ${length} elements.`, + `A sequence of number used as a GPUOrigin3D must have at most ${length} elements, received ${V.length} elements`, opts, ); } @@ -6625,7 +6663,7 @@ webidl.converters["GPUOrigin3D"] = (V, opts) => { } throw webidl.makeException( TypeError, - "can not be converted to sequence or GPUOrigin3DDict.", + "can not be converted to sequence or GPUOrigin3DDict", opts, ); }; @@ -6692,7 +6730,7 @@ webidl.converters["GPUOrigin2D"] = (V, opts) => { if (V.length > length) { throw webidl.makeException( TypeError, - `A sequence of number used as a GPUOrigin2D must have at most ${length} elements.`, + `A sequence of number used as a GPUOrigin2D must have at most ${length} elements`, opts, ); } @@ -6713,6 +6751,12 @@ webidl.converters.GPUComputePassEncoder = webidl.createInterfaceConverter( GPUComputePassEncoder.prototype, ); +// INTERFACE: GPUQuerySet +webidl.converters.GPUQuerySet = webidl.createInterfaceConverter( + "GPUQuerySet", + GPUQuerySet.prototype, +); + // DICTIONARY: GPUComputePassTimestampWrites webidl.converters["GPUComputePassTimestampWrites"] = webidl .createDictionaryConverter( @@ -6786,7 +6830,7 @@ webidl.converters["GPUColor"] = (V, opts) => { if (V.length !== length) { throw webidl.makeException( TypeError, - `A sequence of number used as a GPUColor must have exactly ${length} elements.`, + `A sequence of number used as a GPUColor must have exactly ${length} elements, received ${V.length} elements`, opts, ); } @@ -6796,7 +6840,7 @@ webidl.converters["GPUColor"] = (V, opts) => { } throw webidl.makeException( TypeError, - "can not be converted to sequence or GPUColorDict.", + "can not be converted to sequence or GPUColorDict", opts, ); }; @@ -6885,12 +6929,6 @@ webidl.converters["GPURenderPassDepthStencilAttachment"] = webidl dictMembersGPURenderPassDepthStencilAttachment, ); -// INTERFACE: GPUQuerySet -webidl.converters.GPUQuerySet = webidl.createInterfaceConverter( - "GPUQuerySet", - GPUQuerySet.prototype, -); - // DICTIONARY: GPURenderPassTimestampWrites webidl.converters["GPURenderPassTimestampWrites"] = webidl .createDictionaryConverter( @@ -7165,16 +7203,6 @@ const dictMembersGPUCanvasConfiguration = [ key: "presentMode", converter: webidl.converters["GPUPresentMode"], }, - { - key: "width", - converter: webidl.converters["long"], - required: true, - }, - { - key: "height", - converter: webidl.converters["long"], - required: true, - }, { key: "viewFormats", converter: webidl.createSequenceConverter( diff --git a/deno_webgpu/02_surface.js b/deno_webgpu/02_surface.js index f35f745af41..1861b59b77a 100644 --- a/deno_webgpu/02_surface.js +++ b/deno_webgpu/02_surface.js @@ -29,6 +29,8 @@ const _configuration = Symbol("[[configuration]]"); const _canvas = Symbol("[[canvas]]"); const _currentTexture = Symbol("[[currentTexture]]"); const _present = Symbol("[[present]]"); +const _dim = Symbol("[[dimensions]]"); + class GPUCanvasContext { /** @type {number} */ [_surfaceRid]; @@ -36,6 +38,7 @@ class GPUCanvasContext { [_canvas]; /** @type {GPUTexture | undefined} */ [_currentTexture]; + [_dim]; get canvas() { webidl.assertBranded(this, GPUCanvasContextPrototype); @@ -69,8 +72,8 @@ class GPUCanvasContext { format: configuration.format, viewFormats: configuration.viewFormats, usage: configuration.usage, - width: configuration.width, - height: configuration.height, + width: this[_dim].width, + height: this[_dim].height, alphaMode: configuration.alphaMode, }); @@ -92,7 +95,7 @@ class GPUCanvasContext { "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'"; if (this[_configuration] === null) { - throw new DOMException("context is not configured.", "InvalidStateError"); + throw new DOMException("Context is not configured", "InvalidStateError"); } const { createGPUTexture, assertDevice } = loadWebGPU(); @@ -163,6 +166,7 @@ function createCanvasContext(options) { const canvasContext = webidl.createBranded(GPUCanvasContext); canvasContext[_surfaceRid] = options.surfaceRid; canvasContext[_canvas] = options.canvas; + canvasContext[_dim] = { width: options.width, height: options.height }; return canvasContext; } @@ -172,16 +176,34 @@ function createCanvasContext(options) { class UnsafeWindowSurface { #ctx; #surfaceRid; + #options; + + constructor(options) { + if (typeof options !== "object") { + throw new TypeError("options must be provided."); + } + if ( + typeof options.width !== "number" || typeof options.height !== "number" + ) { + throw new TypeError("width and height must be provided."); + } - constructor(system, win, display) { - this.#surfaceRid = op_webgpu_surface_create(system, win, display); + this.#surfaceRid = op_webgpu_surface_create( + options.system, + options.windowHandle, + options.displayHandle, + ); + this.#options = options; } getContext(context) { if (context !== "webgpu") { - throw new TypeError("Only 'webgpu' context is supported."); + throw new TypeError("Only 'webgpu' context is supported"); } - this.#ctx = createCanvasContext({ surfaceRid: this.#surfaceRid }); + this.#ctx = createCanvasContext({ + surfaceRid: this.#surfaceRid, + ...this.#options, + }); return this.#ctx; } diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index ba72507dd7d..af1a3ed686a 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webgpu" -version = "0.118.0" +version = "0.146.0" authors = ["the Deno authors"] edition.workspace = true license = "MIT" @@ -19,8 +19,9 @@ path = "lib.rs" deno_core.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } -wgpu-types = { workspace = true, features = ["serde"] } +wgt = { workspace = true, package = "wgpu-types", features = ["serde"] } raw-window-handle = { workspace = true } +thiserror.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core] workspace = true diff --git a/deno_webgpu/binding.rs b/deno_webgpu/binding.rs index f1f3a80d359..f82e0656ca7 100644 --- a/deno_webgpu/binding.rs +++ b/deno_webgpu/binding.rs @@ -1,5 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use super::error::WebGpuResult; +use super::wgpu_types; use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; @@ -9,8 +11,6 @@ use serde::Deserialize; use std::borrow::Cow; use std::rc::Rc; -use super::error::WebGpuResult; - pub(crate) struct WebGpuBindGroupLayout( pub(crate) crate::Instance, pub(crate) wgpu_core::id::BindGroupLayoutId, diff --git a/deno_webgpu/buffer.rs b/deno_webgpu/buffer.rs index 460a8cf2330..0a422f8f6e7 100644 --- a/deno_webgpu/buffer.rs +++ b/deno_webgpu/buffer.rs @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; +use super::error::WebGpuResult; +use super::wgpu_types; use deno_core::futures::channel::oneshot; use deno_core::op2; use deno_core::OpState; @@ -14,8 +14,17 @@ use std::rc::Rc; use std::time::Duration; use wgpu_core::resource::BufferAccessResult; -use super::error::DomExceptionOperationError; -use super::error::WebGpuResult; +#[derive(Debug, thiserror::Error)] +pub enum BufferError { + #[error(transparent)] + Resource(deno_core::error::AnyError), + #[error("usage is not valid")] + InvalidUsage, + #[error(transparent)] + Access(#[from] wgpu_core::resource::BufferAccessError), + #[error(transparent)] + Canceled(#[from] oneshot::Canceled), +} pub(crate) struct WebGpuBuffer( pub(crate) super::Instance, @@ -47,18 +56,18 @@ pub fn op_webgpu_create_buffer( #[number] size: u64, usage: u32, mapped_at_creation: bool, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid)?; + .get::(device_rid) + .map_err(BufferError::Resource)?; let device = device_resource.1; let descriptor = wgpu_core::resource::BufferDescriptor { label: Some(label), size, - usage: wgpu_types::BufferUsages::from_bits(usage) - .ok_or_else(|| type_error("usage is not valid"))?, + usage: wgpu_types::BufferUsages::from_bits(usage).ok_or(BufferError::InvalidUsage)?, mapped_at_creation, }; @@ -78,18 +87,22 @@ pub async fn op_webgpu_buffer_get_map_async( mode: u32, #[number] offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let (sender, receiver) = oneshot::channel::(); let device; { let state_ = state.borrow(); let instance = state_.borrow::(); - let buffer_resource = state_.resource_table.get::(buffer_rid)?; + let buffer_resource = state_ + .resource_table + .get::(buffer_rid) + .map_err(BufferError::Resource)?; let buffer = buffer_resource.1; let device_resource = state_ .resource_table - .get::(device_rid)?; + .get::(device_rid) + .map_err(BufferError::Resource)?; device = device_resource.1; let callback = Box::new(move |status| { @@ -131,14 +144,14 @@ pub async fn op_webgpu_buffer_get_map_async( } tokio::time::sleep(Duration::from_millis(10)).await; } - Ok::<(), AnyError>(()) + Ok::<(), BufferError>(()) }; let receiver_fut = async move { receiver.await??; let mut done = done_.borrow_mut(); *done = true; - Ok::<(), AnyError>(()) + Ok::<(), BufferError>(()) }; tokio::try_join!(device_poll_fut, receiver_fut)?; @@ -154,14 +167,17 @@ pub fn op_webgpu_buffer_get_mapped_range( #[number] offset: u64, #[number] size: Option, #[buffer] buf: &mut [u8], -) -> Result { +) -> Result { let instance = state.borrow::(); - let buffer_resource = state.resource_table.get::(buffer_rid)?; + let buffer_resource = state + .resource_table + .get::(buffer_rid) + .map_err(BufferError::Resource)?; let buffer = buffer_resource.1; let (slice_pointer, range_size) = instance .buffer_get_mapped_range(buffer, offset, size) - .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; + .map_err(BufferError::Access)?; // SAFETY: guarantee to be safe from wgpu let slice = @@ -182,12 +198,16 @@ pub fn op_webgpu_buffer_unmap( #[smi] buffer_rid: ResourceId, #[smi] mapped_rid: ResourceId, #[buffer] buf: Option<&[u8]>, -) -> Result { +) -> Result { let mapped_resource = state .resource_table - .take::(mapped_rid)?; + .take::(mapped_rid) + .map_err(BufferError::Resource)?; let instance = state.borrow::(); - let buffer_resource = state.resource_table.get::(buffer_rid)?; + let buffer_resource = state + .resource_table + .get::(buffer_rid) + .map_err(BufferError::Resource)?; let buffer = buffer_resource.1; if let Some(buf) = buf { diff --git a/deno_webgpu/bundle.rs b/deno_webgpu/bundle.rs index 58d179051b5..d612a6d6ce4 100644 --- a/deno_webgpu/bundle.rs +++ b/deno_webgpu/bundle.rs @@ -1,7 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; +use super::wgpu_types; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -11,6 +10,14 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; +#[derive(Debug, thiserror::Error)] +pub enum BundleError { + #[error(transparent)] + Resource(deno_core::error::AnyError), + #[error("size must be larger than 0")] + InvalidSize, +} + use super::error::WebGpuResult; struct WebGpuRenderBundleEncoder(RefCell); @@ -51,7 +58,7 @@ pub struct CreateRenderBundleEncoderArgs { pub fn op_webgpu_create_render_bundle_encoder( state: &mut OpState, #[serde] args: CreateRenderBundleEncoderArgs, -) -> Result { +) -> Result { let device_resource = state .resource_table .get::(args.device_rid)?; @@ -97,7 +104,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .take::(render_bundle_encoder_rid)?; @@ -127,7 +134,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table .get::(bind_group)?; @@ -165,7 +172,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .get::(render_bundle_encoder_rid)?; @@ -188,7 +195,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( pub fn op_webgpu_render_bundle_encoder_pop_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .get::(render_bundle_encoder_rid)?; @@ -206,7 +213,7 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .get::(render_bundle_encoder_rid)?; @@ -230,7 +237,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[smi] pipeline: ResourceId, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table .get::(pipeline)?; @@ -255,16 +262,16 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( #[serde] index_format: wgpu_types::IndexFormat, #[number] offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table - .get::(buffer)?; + .get::(buffer) + .map_err(BundleError::Resource)?; let render_bundle_encoder_resource = state .resource_table - .get::(render_bundle_encoder_rid)?; - let size = Some( - std::num::NonZeroU64::new(size).ok_or_else(|| type_error("size must be larger than 0"))?, - ); + .get::(render_bundle_encoder_rid) + .map_err(BundleError::Resource)?; + let size = Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?); render_bundle_encoder_resource .0 @@ -283,18 +290,17 @@ pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( #[smi] buffer: ResourceId, #[number] offset: u64, #[number] size: Option, -) -> Result { +) -> Result { let buffer_resource = state .resource_table - .get::(buffer)?; + .get::(buffer) + .map_err(BundleError::Resource)?; let render_bundle_encoder_resource = state .resource_table - .get::(render_bundle_encoder_rid)?; + .get::(render_bundle_encoder_rid) + .map_err(BundleError::Resource)?; let size = if let Some(size) = size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) + Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?) } else { None }; @@ -319,7 +325,7 @@ pub fn op_webgpu_render_bundle_encoder_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .get::(render_bundle_encoder_rid)?; @@ -345,7 +351,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table .get::(render_bundle_encoder_rid)?; @@ -369,7 +375,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indirect( #[smi] render_bundle_encoder_rid: ResourceId, #[smi] indirect_buffer: ResourceId, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/deno_webgpu/byow.rs b/deno_webgpu/byow.rs index 49944ea1e7b..17182f0128a 100644 --- a/deno_webgpu/byow.rs +++ b/deno_webgpu/byow.rs @@ -1,16 +1,52 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; use deno_core::ResourceId; use std::ffi::c_void; -#[cfg(any(target_os = "linux", target_os = "macos"))] +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "openbsd" +))] use std::ptr::NonNull; use crate::surface::WebGpuSurface; +#[derive(Debug, thiserror::Error)] +pub enum ByowError { + #[error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")] + WebGPUNotInitiated, + #[error("Invalid parameters")] + InvalidParameters, + #[error(transparent)] + CreateSurface(wgpu_core::instance::CreateSurfaceError), + #[cfg(target_os = "windows")] + #[error("Invalid system on Windows")] + InvalidSystem, + #[cfg(target_os = "macos")] + #[error("Invalid system on macOS")] + InvalidSystem, + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[error("Invalid system on Linux/BSD")] + InvalidSystem, + #[cfg(any( + target_os = "windows", + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd" + ))] + #[error("window is null")] + NullWindow, + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] + #[error("display is null")] + NullDisplay, + #[cfg(target_os = "macos")] + #[error("ns_view is null")] + NSViewDisplay, +} + #[op2(fast)] #[smi] pub fn op_webgpu_surface_create( @@ -18,8 +54,10 @@ pub fn op_webgpu_surface_create( #[string] system: &str, p1: *const c_void, p2: *const c_void, -) -> Result { - let instance = state.borrow::(); +) -> Result { + let instance = state + .try_borrow::() + .ok_or(ByowError::WebGPUNotInitiated)?; // Security note: // // The `p1` and `p2` parameters are pointers to platform-specific window @@ -34,12 +72,16 @@ pub fn op_webgpu_surface_create( // // - Only FFI can export v8::External to user code. if p1.is_null() { - return Err(type_error("Invalid parameters")); + return Err(ByowError::InvalidParameters); } let (win_handle, display_handle) = raw_window(system, p1, p2)?; // SAFETY: see above comment - let surface = unsafe { instance.instance_create_surface(display_handle, win_handle, None)? }; + let surface = unsafe { + instance + .instance_create_surface(display_handle, win_handle, None) + .map_err(ByowError::CreateSurface)? + }; let rid = state .resource_table @@ -57,14 +99,14 @@ fn raw_window( system: &str, _ns_window: *const c_void, ns_view: *const c_void, -) -> Result { +) -> Result { if system != "cocoa" { - return Err(type_error("Invalid system on macOS")); + return Err(ByowError::InvalidSystem); } 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"))?, + NonNull::new(ns_view as *mut c_void).ok_or(ByowError::NSViewDisplay)?, )); let display_handle = @@ -77,15 +119,15 @@ fn raw_window( system: &str, window: *const c_void, hinstance: *const c_void, -) -> Result { +) -> Result { use raw_window_handle::WindowsDisplayHandle; if system != "win32" { - return Err(type_error("Invalid system on Windows")); + return Err(ByowError::InvalidSystem); } let win_handle = { let mut handle = raw_window_handle::Win32WindowHandle::new( - std::num::NonZeroIsize::new(window as isize).ok_or(type_error("window is null"))?, + std::num::NonZeroIsize::new(window as isize).ok_or(ByowError::NullWindow)?, ); handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize); @@ -96,12 +138,12 @@ fn raw_window( Ok((win_handle, display_handle)) } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] fn raw_window( system: &str, window: *const c_void, display: *const c_void, -) -> Result { +) -> Result { let (win_handle, display_handle); if system == "x11" { win_handle = raw_window_handle::RawWindowHandle::Xlib( @@ -114,18 +156,33 @@ fn raw_window( } else if system == "wayland" { 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"))?, + NonNull::new(window as *mut c_void).ok_or(ByowError::NullWindow)?, ), ); 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"))?, + NonNull::new(display as *mut c_void).ok_or(ByowError::NullDisplay)?, ), ); } else { - return Err(type_error("Invalid system on Linux")); + return Err(ByowError::InvalidSystem); } Ok((win_handle, display_handle)) } + +#[cfg(not(any( + target_os = "macos", + target_os = "windows", + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd", +)))] +fn raw_window( + _system: &str, + _window: *const c_void, + _display: *const c_void, +) -> Result { + Err(deno_core::error::type_error("Unsupported platform")) +} diff --git a/deno_webgpu/command_encoder.rs b/deno_webgpu/command_encoder.rs index 8df5d58bf11..104afa7a3ce 100644 --- a/deno_webgpu/command_encoder.rs +++ b/deno_webgpu/command_encoder.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use super::wgpu_types; use crate::WebGpuQuerySet; use deno_core::error::AnyError; use deno_core::op2; @@ -79,7 +80,7 @@ pub struct GpuRenderPassColorAttachment { #[serde(rename_all = "camelCase")] pub struct GpuRenderPassDepthStencilAttachment { view: ResourceId, - depth_clear_value: f32, + depth_clear_value: Option, depth_load_op: Option, depth_store_op: Option, depth_read_only: bool, @@ -157,7 +158,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass( depth: wgpu_core::command::PassChannel { load_op: attachment.depth_load_op, store_op: attachment.depth_store_op, - clear_value: Some(attachment.depth_clear_value), + clear_value: Some(attachment.depth_clear_value.unwrap_or(0.0)), read_only: attachment.depth_read_only, }, stencil: wgpu_core::command::PassChannel { diff --git a/deno_webgpu/error.rs b/deno_webgpu/error.rs index caea7d9d818..8af30f62de6 100644 --- a/deno_webgpu/error.rs +++ b/deno_webgpu/error.rs @@ -1,11 +1,9 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; use deno_core::ResourceId; use serde::Serialize; use std::convert::From; use std::error::Error; -use std::fmt; use std::fmt::Write; use wgpu_core::binding_model::CreateBindGroupError; use wgpu_core::binding_model::CreateBindGroupLayoutError; @@ -68,7 +66,6 @@ pub struct WebGpuResult { } impl WebGpuResult { - #[must_use] pub fn rid(rid: ResourceId) -> Self { Self { rid: Some(rid), @@ -76,7 +73,6 @@ impl WebGpuResult { } } - #[must_use] pub fn rid_err>(rid: ResourceId, err: Option) -> Self { Self { rid: Some(rid), @@ -84,7 +80,6 @@ impl WebGpuResult { } } - #[must_use] pub fn maybe_err>(err: Option) -> Self { Self { rid: None, @@ -92,7 +87,6 @@ impl WebGpuResult { } } - #[must_use] pub fn empty() -> Self { Self { rid: None, @@ -304,31 +298,3 @@ impl From for WebGpuError { WebGpuError::Validation(fmt_err(&err)) } } - -#[derive(Debug)] -pub struct DomExceptionOperationError { - pub msg: String, -} - -impl DomExceptionOperationError { - #[must_use] - pub fn new(msg: &str) -> Self { - DomExceptionOperationError { - msg: msg.to_string(), - } - } -} - -impl fmt::Display for DomExceptionOperationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(&self.msg) - } -} - -impl std::error::Error for DomExceptionOperationError {} - -#[must_use] -pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { - e.downcast_ref::() - .map(|_| "DOMExceptionOperationError") -} diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index e31812e25f2..854a3d32a7c 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -2,7 +2,6 @@ #![cfg(not(target_arch = "wasm32"))] #![warn(unsafe_op_in_unsafe_fn)] -use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -14,9 +13,8 @@ use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; pub use wgpu_core; -pub use wgpu_types; +pub use wgt as wgpu_types; -use error::DomExceptionOperationError; use error::WebGpuResult; pub const UNSTABLE_FEATURE_NAME: &str = "webgpu"; @@ -54,6 +52,14 @@ pub mod shader; pub mod surface; pub mod texture; +#[derive(Debug, thiserror::Error)] +pub enum InitError { + #[error(transparent)] + Resource(deno_core::error::AnyError), + #[error(transparent)] + RequestDevice(wgpu_core::instance::RequestDeviceError), +} + pub type Instance = std::sync::Arc; struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId); @@ -235,6 +241,9 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { if features.contains(wgpu_types::Features::FLOAT32_FILTERABLE) { return_features.push("float32-filterable"); } + if features.contains(wgpu_types::Features::DUAL_SOURCE_BLENDING) { + return_features.push("dual-source-blending"); + } // extended from spec @@ -349,7 +358,7 @@ pub struct GpuAdapterRes { rid: ResourceId, limits: wgpu_types::Limits, features: Vec<&'static str>, - is_software: bool, + is_fallback: bool, } #[derive(Serialize)] @@ -359,7 +368,6 @@ pub struct GpuDeviceRes { queue_rid: ResourceId, limits: wgpu_types::Limits, features: Vec<&'static str>, - is_software: bool, } #[op2] @@ -368,15 +376,9 @@ pub fn op_webgpu_request_adapter( state: Rc>, #[serde] power_preference: Option, force_fallback_adapter: bool, -) -> Result { +) -> GpuAdapterResOrErr { let mut state = state.borrow_mut(); - // TODO(bartlomieju): replace with `state.feature_checker.check_or_exit` - // once we phase out `check_or_exit_with_legacy_fallback` - state - .feature_checker - .check_or_exit_with_legacy_fallback(UNSTABLE_FEATURE_NAME, "navigator.gpu.requestAdapter"); - let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else( |_| wgpu_types::Backends::all(), |s| wgpu_core::instance::parse_backends_from_comma_list(&s), @@ -406,9 +408,9 @@ pub fn op_webgpu_request_adapter( let adapter = match res { Ok(adapter) => adapter, Err(err) => { - return Ok(GpuAdapterResOrErr::Error { + return GpuAdapterResOrErr::Error { err: err.to_string(), - }) + } } }; let adapter_features = instance.adapter_features(adapter); @@ -419,12 +421,13 @@ pub fn op_webgpu_request_adapter( let rid = state.resource_table.add(WebGpuAdapter(instance, adapter)); - Ok(GpuAdapterResOrErr::Features(GpuAdapterRes { + GpuAdapterResOrErr::Features(GpuAdapterRes { rid, features, limits: adapter_limits, - is_software: false, - })) + // TODO(lucacasonato): report correctly from wgpu + is_fallback: false, + }) } #[derive(Deserialize)] @@ -486,6 +489,10 @@ impl From for wgpu_types::Features { wgpu_types::Features::FLOAT32_FILTERABLE, required_features.0.contains("float32-filterable"), ); + features.set( + wgpu_types::Features::DUAL_SOURCE_BLENDING, + required_features.0.contains("dual-source-blending"), + ); // extended from spec @@ -633,9 +640,12 @@ 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.take::(adapter_rid)?; + let adapter_resource = state + .resource_table + .take::(adapter_rid) + .map_err(InitError::Resource)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -658,7 +668,7 @@ pub fn op_webgpu_request_device( ); adapter_resource.close(); - let (device, queue) = res.map_err(|err| DomExceptionOperationError::new(&err.to_string()))?; + let (device, queue) = res.map_err(InitError::RequestDevice)?; let device_features = instance.device_features(device); let features = deserialize_features(&device_features); @@ -676,8 +686,6 @@ pub fn op_webgpu_request_device( queue_rid, features, limits, - // TODO(lucacasonato): report correctly from wgpu - is_software: false, }) } @@ -695,9 +703,9 @@ pub struct GPUAdapterInfo { pub fn op_webgpu_request_adapter_info( state: Rc>, #[smi] adapter_rid: ResourceId, -) -> Result { - let mut state = state.borrow_mut(); - let adapter_resource = state.resource_table.take::(adapter_rid)?; +) -> Result { + let state = state.borrow_mut(); + let adapter_resource = state.resource_table.get::(adapter_rid)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -743,7 +751,7 @@ impl From for wgpu_types::QueryType { pub fn op_webgpu_create_query_set( state: &mut OpState, #[serde] args: CreateQuerySetArgs, -) -> Result { +) -> Result { let device_resource = state.resource_table.get::(args.device_rid)?; let device = device_resource.1; let instance = state.borrow::(); diff --git a/deno_webgpu/pipeline.rs b/deno_webgpu/pipeline.rs index 0ab3c40262c..910211e7094 100644 --- a/deno_webgpu/pipeline.rs +++ b/deno_webgpu/pipeline.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use super::wgpu_types; use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; diff --git a/deno_webgpu/queue.rs b/deno_webgpu/queue.rs index a2e7d6a500e..808185f17ef 100644 --- a/deno_webgpu/queue.rs +++ b/deno_webgpu/queue.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use super::wgpu_types; use crate::command_encoder::WebGpuCommandBuffer; use crate::Instance; use deno_core::error::AnyError; diff --git a/deno_webgpu/render_pass.rs b/deno_webgpu/render_pass.rs index 4929fbbe908..e5bd3cfd575 100644 --- a/deno_webgpu/render_pass.rs +++ b/deno_webgpu/render_pass.rs @@ -1,7 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; +use super::wgpu_types; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -12,6 +11,16 @@ use std::cell::RefCell; use super::error::WebGpuResult; +#[derive(Debug, thiserror::Error)] +pub enum RenderPassError { + #[error(transparent)] + Resource(deno_core::error::AnyError), + #[error("size must be larger than 0")] + InvalidSize, + #[error(transparent)] + RenderPass(#[from] wgpu_core::command::RenderPassError), +} + pub(crate) struct WebGpuRenderPass(pub(crate) RefCell); impl Resource for WebGpuRenderPass { fn name(&self) -> Cow { @@ -36,7 +45,7 @@ pub struct RenderPassSetViewportArgs { pub fn op_webgpu_render_pass_set_viewport( state: &mut OpState, #[serde] args: RenderPassSetViewportArgs, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(args.render_pass_rid)?; @@ -65,7 +74,7 @@ pub fn op_webgpu_render_pass_set_scissor_rect( y: u32, width: u32, height: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -89,7 +98,7 @@ pub fn op_webgpu_render_pass_set_blend_constant( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] color: wgpu_types::Color, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -107,7 +116,7 @@ pub fn op_webgpu_render_pass_set_stencil_reference( state: &mut OpState, #[smi] render_pass_rid: ResourceId, reference: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -125,7 +134,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, query_index: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -142,7 +151,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( pub fn op_webgpu_render_pass_end_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -160,7 +169,7 @@ pub fn op_webgpu_render_pass_execute_bundles( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] bundles: Vec, -) -> Result { +) -> Result { let bundles = bundles .iter() .map(|rid| { @@ -169,7 +178,7 @@ pub fn op_webgpu_render_pass_execute_bundles( .get::(*rid)?; Ok(render_bundle_resource.1) }) - .collect::, AnyError>>()?; + .collect::, deno_core::error::AnyError>>()?; let render_pass_resource = state .resource_table @@ -187,7 +196,7 @@ pub fn op_webgpu_render_pass_execute_bundles( pub fn op_webgpu_render_pass_end( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .take::(render_pass_rid)?; @@ -209,7 +218,7 @@ pub fn op_webgpu_render_pass_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table .get::(bind_group)?; @@ -244,7 +253,7 @@ pub fn op_webgpu_render_pass_push_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -265,7 +274,7 @@ pub fn op_webgpu_render_pass_push_debug_group( pub fn op_webgpu_render_pass_pop_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -283,7 +292,7 @@ pub fn op_webgpu_render_pass_insert_debug_marker( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -305,7 +314,7 @@ pub fn op_webgpu_render_pass_set_pipeline( state: &mut OpState, #[smi] render_pass_rid: ResourceId, pipeline: u32, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table .get::(pipeline)?; @@ -332,19 +341,18 @@ pub fn op_webgpu_render_pass_set_index_buffer( #[serde] index_format: wgpu_types::IndexFormat, #[number] offset: u64, #[number] size: Option, -) -> Result { +) -> Result { let buffer_resource = state .resource_table - .get::(buffer)?; + .get::(buffer) + .map_err(RenderPassError::Resource)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid)?; + .get::(render_pass_rid) + .map_err(RenderPassError::Resource)?; let size = if let Some(size) = size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) + Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) } else { None }; @@ -371,19 +379,18 @@ pub fn op_webgpu_render_pass_set_vertex_buffer( buffer: u32, #[number] offset: u64, #[number] size: Option, -) -> Result { +) -> Result { let buffer_resource = state .resource_table - .get::(buffer)?; + .get::(buffer) + .map_err(RenderPassError::Resource)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid)?; + .get::(render_pass_rid) + .map_err(RenderPassError::Resource)?; let size = if let Some(size) = size { - Some( - std::num::NonZeroU64::new(size) - .ok_or_else(|| type_error("size must be larger than 0"))?, - ) + Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) } else { None }; @@ -410,7 +417,7 @@ pub fn op_webgpu_render_pass_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -438,7 +445,7 @@ pub fn op_webgpu_render_pass_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -464,7 +471,7 @@ pub fn op_webgpu_render_pass_draw_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; @@ -490,7 +497,7 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/deno_webgpu/sampler.rs b/deno_webgpu/sampler.rs index 59b6f4e3025..31b8ce2a241 100644 --- a/deno_webgpu/sampler.rs +++ b/deno_webgpu/sampler.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use super::wgpu_types; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -47,7 +47,7 @@ pub struct CreateSamplerArgs { pub fn op_webgpu_create_sampler( state: &mut OpState, #[serde] args: CreateSamplerArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/deno_webgpu/shader.rs b/deno_webgpu/shader.rs index a8c79cd4d72..f09d89c63d8 100644 --- a/deno_webgpu/shader.rs +++ b/deno_webgpu/shader.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use super::wgpu_types; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -31,7 +31,7 @@ pub fn op_webgpu_create_shader_module( #[smi] device_rid: ResourceId, #[string] label: Cow, #[string] code: Cow, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/deno_webgpu/surface.rs b/deno_webgpu/surface.rs index ca5e795aa08..c90d5e3acad 100644 --- a/deno_webgpu/surface.rs +++ b/deno_webgpu/surface.rs @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use super::wgpu_types; use super::WebGpuResult; -use deno_core::error::AnyError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -9,7 +9,16 @@ use deno_core::ResourceId; use serde::Deserialize; use std::borrow::Cow; use std::rc::Rc; -use wgpu_types::SurfaceStatus; + +#[derive(Debug, thiserror::Error)] +pub enum SurfaceError { + #[error(transparent)] + Resource(deno_core::error::AnyError), + #[error("Invalid Surface Status")] + InvalidStatus, + #[error(transparent)] + Surface(wgpu_core::present::SurfaceError), +} pub struct WebGpuSurface(pub crate::Instance, pub wgpu_core::id::SurfaceId); impl Resource for WebGpuSurface { @@ -41,7 +50,7 @@ pub struct SurfaceConfigureArgs { pub fn op_webgpu_surface_configure( state: &mut OpState, #[serde] args: SurfaceConfigureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -74,15 +83,20 @@ pub fn op_webgpu_surface_get_current_texture( state: &mut OpState, #[smi] _device_rid: ResourceId, #[smi] surface_rid: ResourceId, -) -> Result { +) -> Result { let instance = state.borrow::(); - let surface_resource = state.resource_table.get::(surface_rid)?; + let surface_resource = state + .resource_table + .get::(surface_rid) + .map_err(SurfaceError::Resource)?; let surface = surface_resource.1; - let output = instance.surface_get_current_texture(surface, None)?; + let output = instance + .surface_get_current_texture(surface, None) + .map_err(SurfaceError::Surface)?; match output.status { - SurfaceStatus::Good | SurfaceStatus::Suboptimal => { + wgpu_types::SurfaceStatus::Good | wgpu_types::SurfaceStatus::Suboptimal => { let id = output.texture_id.unwrap(); let rid = state.resource_table.add(crate::texture::WebGpuTexture { instance: instance.clone(), @@ -90,7 +104,7 @@ pub fn op_webgpu_surface_get_current_texture( }); Ok(WebGpuResult::rid(rid)) } - _ => Err(AnyError::msg("Invalid Surface Status")), + _ => Err(SurfaceError::InvalidStatus), } } @@ -99,12 +113,17 @@ pub fn op_webgpu_surface_present( state: &mut OpState, #[smi] _device_rid: ResourceId, #[smi] surface_rid: ResourceId, -) -> Result<(), AnyError> { +) -> Result<(), SurfaceError> { let instance = state.borrow::(); - let surface_resource = state.resource_table.get::(surface_rid)?; + let surface_resource = state + .resource_table + .get::(surface_rid) + .map_err(SurfaceError::Resource)?; let surface = surface_resource.1; - instance.surface_present(surface)?; + instance + .surface_present(surface) + .map_err(SurfaceError::Surface)?; Ok(()) } diff --git a/deno_webgpu/texture.rs b/deno_webgpu/texture.rs index 0f78d077449..5a312595868 100644 --- a/deno_webgpu/texture.rs +++ b/deno_webgpu/texture.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use super::wgpu_types; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -59,7 +59,7 @@ pub struct CreateTextureArgs { pub fn op_webgpu_create_texture( state: &mut OpState, #[serde] args: CreateTextureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -103,7 +103,7 @@ pub struct CreateTextureViewArgs { pub fn op_webgpu_create_texture_view( state: &mut OpState, #[serde] args: CreateTextureViewArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let texture_resource = state .resource_table diff --git a/deno_webgpu/webgpu.idl b/deno_webgpu/webgpu.idl index 60b5a4259d8..bdff4e4e275 100644 --- a/deno_webgpu/webgpu.idl +++ b/deno_webgpu/webgpu.idl @@ -78,11 +78,11 @@ enum GPUPowerPreference { [Exposed=(Window, Worker), SecureContext] interface GPUAdapter { [SameObject] readonly attribute GPUSupportedFeatures features; + [SameObject] readonly attribute GPUAdapterInfo info; [SameObject] readonly attribute GPUSupportedLimits limits; readonly attribute boolean isFallbackAdapter; Promise requestDevice(optional GPUDeviceDescriptor descriptor = {}); - Promise requestAdapterInfo(); }; dictionary GPUDeviceDescriptor @@ -92,22 +92,19 @@ dictionary GPUDeviceDescriptor }; enum GPUFeatureName { - // api "depth-clip-control", - // texture formats "depth32float-stencil8", "texture-compression-bc", "texture-compression-bc-sliced-3d", "texture-compression-etc2", "texture-compression-astc", - // api "timestamp-query", "indirect-first-instance", - // shader "shader-f16", "rg11b10ufloat-renderable", "bgra8unorm-storage", "float32-filterable", + "dual-source-blending", // extended from spec @@ -752,6 +749,10 @@ enum GPUBlendFactor { "src-alpha-saturated", "constant", "one-minus-constant", + "src1", + "one-minus-src1", + "src1-alpha", + "one-minus-src1-alpha", }; enum GPUBlendOperation { @@ -1109,13 +1110,13 @@ interface GPUQueue { undefined writeBuffer( GPUBuffer buffer, GPUSize64 bufferOffset, - [AllowShared] BufferSource data, + AllowSharedBufferSource data, optional GPUSize64 dataOffset = 0, optional GPUSize64 size); undefined writeTexture( GPUTexelCopyTextureInfo destination, - [AllowShared] BufferSource data, + AllowSharedBufferSource data, GPUTexelCopyBufferLayout dataLayout, GPUExtent3D size); };