mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: WebGPU API (#7977)
Co-authored-by: Luca Casonato <lucacasonato@yahoo.com>
This commit is contained in:
parent
dbdbe7a1cf
commit
7cd14f97c9
42 changed files with 15302 additions and 1 deletions
557
Cargo.lock
generated
557
Cargo.lock
generated
|
@ -16,6 +16,12 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
|
@ -73,6 +79,15 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ast_node"
|
||||
version = "0.7.1"
|
||||
|
@ -180,6 +195,21 @@ version = "0.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
|
@ -198,6 +228,12 @@ dependencies = [
|
|||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
|
@ -257,6 +293,9 @@ name = "cc"
|
|||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -270,6 +309,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.19"
|
||||
|
@ -298,6 +343,55 @@ dependencies = [
|
|||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copyless"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "core-graphics-types"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpuid-bool"
|
||||
version = "0.1.2"
|
||||
|
@ -343,6 +437,17 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a60cceb22c7c53035f8980524fdc7f17cf49681a3c154e6757d30afbec6ec4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libloading",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
|
@ -538,6 +643,7 @@ dependencies = [
|
|||
"deno_crypto",
|
||||
"deno_fetch",
|
||||
"deno_web",
|
||||
"deno_webgpu",
|
||||
"deno_websocket",
|
||||
"dlopen",
|
||||
"encoding_rs",
|
||||
|
@ -579,6 +685,17 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_webgpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"serde",
|
||||
"tokio",
|
||||
"wgpu-core",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deno_websocket"
|
||||
version = "0.5.0"
|
||||
|
@ -840,6 +957,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.0"
|
||||
|
@ -1059,6 +1191,205 @@ dependencies = [
|
|||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-auxil"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7b33ecf067f2117668d91c9b0f2e5f223ebd1ffec314caa2f3de27bb580186d"
|
||||
dependencies = [
|
||||
"fxhash",
|
||||
"gfx-hal",
|
||||
"spirv_cross",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx11"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f851d03c2e8f117e3702bf41201a4fafa447d5cb1276d5375870ae7573d069dd"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"libloading",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"spirv_cross",
|
||||
"thunderdome",
|
||||
"winapi 0.3.9",
|
||||
"wio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx12"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36dc6ba2b7647e2c2b27b8f74ff5ccdd53c703776588eee5b1de515fdcbd6bc9"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"d3d12",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"spirv_cross",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-empty"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f07ef26a65954cfdd7b4c587f485100d1bb3b0bd6a51b02d817d6c87cca7a91"
|
||||
dependencies = [
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-gl"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17fd85420547bceb851fadb90f196f168abfc252d57528bd2d749db0d18b75f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"glow",
|
||||
"js-sys",
|
||||
"khronos-egl",
|
||||
"libloading",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"raw-window-handle",
|
||||
"spirv_cross",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-metal"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dc54b456ece69ef49f8893269ebf24ac70969ed34ba2719c3f3abcc8fbff14e"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"copyless",
|
||||
"foreign-types",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"spirv_cross",
|
||||
"storage-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-vulkan"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dabe88b1a5c91e0f969b441cc57e70364858066e4ba937deeb62065654ef9bd9"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ash",
|
||||
"byteorder",
|
||||
"core-graphics-types",
|
||||
"gfx-hal",
|
||||
"inplace_it",
|
||||
"log",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-hal"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1d9cc8d3b573dda62d0baca4f02e0209786e22c562caff001d77c389008781d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"naga",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "072136d2c3783f3a92f131acb227bc806d3886278e2a4dc1e9990ec89ef9e70b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-alloc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7724b9aef57ea36d70faf54e0ee6265f86e41de16bed8333efdeab5b00e16b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-alloc-types",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-alloc-types"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-descriptor"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a70f1e87a3840ed6a3e99e02c2b861e4dbdf26f0d07e38f42ea5aff46cfce2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-descriptor-types",
|
||||
"hashbrown",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-descriptor-types"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.0"
|
||||
|
@ -1084,6 +1415,9 @@ name = "hashbrown"
|
|||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -1246,6 +1580,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inplace_it"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
|
||||
|
||||
[[package]]
|
||||
name = "input_buffer"
|
||||
version = "0.4.0"
|
||||
|
@ -1301,6 +1641,15 @@ version = "0.4.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.47"
|
||||
|
@ -1326,6 +1675,16 @@ dependencies = [
|
|||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos-egl"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8020ff3b84f9ac87461216ad0501bc09b33c1cbe17404d8ea405160fd164bab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1351,6 +1710,16 @@ version = "0.2.86"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
|
@ -1435,6 +1804,15 @@ dependencies = [
|
|||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
|
@ -1453,6 +1831,20 @@ version = "2.3.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4598d719460ade24c7d91f335daf055bf2a7eec030728ce751814c50cdd6a26c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"foreign-types",
|
||||
"log",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
|
@ -1492,6 +1884,23 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8f30d7036f137a2f64fd7d53b70a91545d3f09e030b77b3816ff7bd4cf3f789"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"fxhash",
|
||||
"log",
|
||||
"num-traits",
|
||||
"petgraph",
|
||||
"serde",
|
||||
"spirv_headers",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
|
@ -1600,6 +2009,25 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
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]]
|
||||
name = "once_cell"
|
||||
version = "1.5.2"
|
||||
|
@ -2012,6 +2440,21 @@ dependencies = [
|
|||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "range-alloc"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
|
@ -2128,6 +2571,17 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"bitflags",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
|
@ -2349,6 +2803,12 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c46a3482db8f247956e464d783693ece164ca056e6e67563ee5505bdb86452cd"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
|
@ -2388,6 +2848,27 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spirv_cross"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06db6bd7b6518f761593783e2896eefe55e90455efc5f44511078ce0426ed418"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv_headers"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f5b132530b1ac069df335577e3581765995cba5a13995cdbbdbc8fb057c532c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -2400,6 +2881,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "storage-map"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418bb14643aa55a7841d5303f72cf512cfb323b8cc221d51580500a1ca75206c"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.1"
|
||||
|
@ -2925,6 +3415,12 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thunderdome"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7572415bd688d401c52f6e36f4c8e805b9ae1622619303b9fa835d531db0acae"
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
|
@ -3087,9 +3583,21 @@ checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43f080ea7e4107844ef4766459426fa2d5c1ada2e47edba05dc7fa99d9629f47"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.17"
|
||||
|
@ -3468,6 +3976,46 @@ dependencies = [
|
|||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c89fa2cc5d72236461ac09c5be967012663e29cb62f1a972654cbf35e49dffa8"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg_aliases",
|
||||
"copyless",
|
||||
"fxhash",
|
||||
"gfx-backend-dx11",
|
||||
"gfx-backend-dx12",
|
||||
"gfx-backend-empty",
|
||||
"gfx-backend-gl",
|
||||
"gfx-backend-metal",
|
||||
"gfx-backend-vulkan",
|
||||
"gfx-hal",
|
||||
"gpu-alloc",
|
||||
"gpu-descriptor",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"ron",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72fa9ba80626278fd87351555c363378d08122d7601e58319be3d6fa85a87747"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.0.2"
|
||||
|
@ -3554,6 +4102,15 @@ dependencies = [
|
|||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wio"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
|
|
|
@ -11,6 +11,7 @@ use deno_core::RuntimeOptions;
|
|||
use deno_runtime::deno_crypto;
|
||||
use deno_runtime::deno_fetch;
|
||||
use deno_runtime::deno_web;
|
||||
use deno_runtime::deno_webgpu;
|
||||
use deno_runtime::deno_websocket;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
|
@ -62,6 +63,7 @@ fn create_compiler_snapshot(
|
|||
let mut op_crate_libs = HashMap::new();
|
||||
op_crate_libs.insert("deno.web", deno_web::get_declaration());
|
||||
op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration());
|
||||
op_crate_libs.insert("deno.webgpu", deno_webgpu::get_declaration());
|
||||
op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration());
|
||||
op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration());
|
||||
|
||||
|
@ -260,6 +262,10 @@ fn main() {
|
|||
"cargo:rustc-env=DENO_FETCH_LIB_PATH={}",
|
||||
deno_fetch::get_declaration().display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}",
|
||||
deno_webgpu::get_declaration().display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}",
|
||||
deno_websocket::get_declaration().display()
|
||||
|
|
7
cli/dts/lib.deno.window.d.ts
vendored
7
cli/dts/lib.deno.window.d.ts
vendored
|
@ -3,6 +3,7 @@
|
|||
/// <reference no-default-lib="true" />
|
||||
/// <reference lib="deno.ns" />
|
||||
/// <reference lib="deno.shared_globals" />
|
||||
/// <reference lib="deno.webgpu" />
|
||||
/// <reference lib="esnext" />
|
||||
|
||||
declare class Window extends EventTarget {
|
||||
|
@ -17,12 +18,18 @@ declare class Window extends EventTarget {
|
|||
confirm: (message?: string) => boolean;
|
||||
prompt: (message?: string, defaultValue?: string) => string | null;
|
||||
Deno: typeof Deno;
|
||||
navigator: Navigator;
|
||||
}
|
||||
|
||||
declare var window: Window & typeof globalThis;
|
||||
declare var self: Window & typeof globalThis;
|
||||
declare var onload: ((this: Window, ev: Event) => any) | null;
|
||||
declare var onunload: ((this: Window, ev: Event) => any) | null;
|
||||
declare var navigator: Navigator;
|
||||
|
||||
declare interface Navigator {
|
||||
readonly gpu: GPU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the given message and waits for the enter key pressed.
|
||||
|
|
8
cli/dts/lib.deno.worker.d.ts
vendored
8
cli/dts/lib.deno.worker.d.ts
vendored
|
@ -3,6 +3,7 @@
|
|||
/// <reference no-default-lib="true" />
|
||||
/// <reference lib="deno.ns" />
|
||||
/// <reference lib="deno.shared_globals" />
|
||||
/// <reference lib="deno.webgpu" />
|
||||
/// <reference lib="esnext" />
|
||||
|
||||
declare class WorkerGlobalScope {
|
||||
|
@ -29,6 +30,13 @@ declare class WorkerGlobalScope {
|
|||
close: () => void;
|
||||
postMessage: (message: any) => void;
|
||||
Deno: typeof Deno;
|
||||
navigator: WorkerNavigator;
|
||||
}
|
||||
|
||||
declare var navigator: WorkerNavigator;
|
||||
|
||||
declare interface WorkerNavigator {
|
||||
readonly gpu: GPU;
|
||||
}
|
||||
|
||||
declare class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
|
||||
|
|
|
@ -234,6 +234,7 @@ static ENV_VARIABLES_HELP: &str = r#"ENVIRONMENT VARIABLES:
|
|||
DENO_DIR Set the cache directory
|
||||
DENO_INSTALL_ROOT Set deno install's output directory
|
||||
(defaults to $HOME/.deno/bin)
|
||||
DENO_WEBGPU_TRACE Directory to use for wgpu traces
|
||||
HTTP_PROXY Proxy address for HTTP requests
|
||||
(module downloads, fetch)
|
||||
HTTPS_PROXY Proxy address for HTTPS requests
|
||||
|
|
|
@ -278,10 +278,11 @@ fn print_cache_info(
|
|||
|
||||
pub fn get_types(unstable: bool) -> String {
|
||||
let mut types = format!(
|
||||
"{}\n{}\n{}\n{}\n{}\n{}",
|
||||
"{}\n{}\n{}\n{}\n{}\n{}\n{}",
|
||||
crate::tsc::DENO_NS_LIB,
|
||||
crate::tsc::DENO_WEB_LIB,
|
||||
crate::tsc::DENO_FETCH_LIB,
|
||||
crate::tsc::DENO_WEBGPU_LIB,
|
||||
crate::tsc::DENO_WEBSOCKET_LIB,
|
||||
crate::tsc::SHARED_GLOBALS_LIB,
|
||||
crate::tsc::WINDOW_LIB,
|
||||
|
@ -1022,6 +1023,8 @@ fn init_logger(maybe_level: Option<Level>) {
|
|||
)
|
||||
// https://github.com/denoland/deno/issues/6641
|
||||
.filter_module("rustyline", LevelFilter::Off)
|
||||
// wgpu backend crates (gfx_backend), have a lot of useless INFO and WARN logs
|
||||
.filter_module("gfx", LevelFilter::Error)
|
||||
.format(|buf, record| {
|
||||
let mut target = record.target().to_string();
|
||||
if let Some(line_no) = record.line() {
|
||||
|
|
|
@ -76,3 +76,4 @@ import "./write_text_file_test.ts";
|
|||
import "./performance_test.ts";
|
||||
import "./version_test.ts";
|
||||
import "./websocket_test.ts";
|
||||
import "./webgpu_test.ts";
|
||||
|
|
225
cli/tests/unit/webgpu_test.ts
Normal file
225
cli/tests/unit/webgpu_test.ts
Normal file
|
@ -0,0 +1,225 @@
|
|||
// TODO(lucacasonato): remove when GPUBufferUsage and friends are added to dlint
|
||||
// deno-lint-ignore-file no-undef
|
||||
|
||||
import { assert, assertEquals, unitTest } from "./test_util.ts";
|
||||
|
||||
let isCI: boolean;
|
||||
try {
|
||||
isCI = (Deno.env.get("CI")?.length ?? 0) > 0;
|
||||
} catch {
|
||||
isCI = true;
|
||||
}
|
||||
|
||||
// Skip this test on linux CI, because the vulkan emulator is not good enough
|
||||
// yet, and skip on macOS because these do not have virtual GPUs.
|
||||
unitTest({
|
||||
perms: { read: true, env: true },
|
||||
ignore: (Deno.build.os === "linux" || Deno.build.os === "darwin") && isCI,
|
||||
}, async function webgpuComputePass() {
|
||||
const adapter = await navigator.gpu.requestAdapter();
|
||||
assert(adapter);
|
||||
|
||||
const numbers = [1, 4, 3, 295];
|
||||
|
||||
const device = await adapter.requestDevice();
|
||||
assert(device);
|
||||
|
||||
const shaderCode = await Deno.readTextFile(
|
||||
"cli/tests/webgpu_computepass_shader.wgsl",
|
||||
);
|
||||
|
||||
const shaderModule = device.createShaderModule({
|
||||
code: shaderCode,
|
||||
});
|
||||
|
||||
const size = new Uint32Array(numbers).byteLength;
|
||||
|
||||
const stagingBuffer = device.createBuffer({
|
||||
size: size,
|
||||
usage: 1 | 8,
|
||||
});
|
||||
|
||||
const storageBuffer = device.createBuffer({
|
||||
label: "Storage Buffer",
|
||||
size: size,
|
||||
usage: 0x80 | 8 | 4,
|
||||
mappedAtCreation: true,
|
||||
});
|
||||
|
||||
const buf = new Uint32Array(storageBuffer.getMappedRange());
|
||||
|
||||
buf.set(numbers);
|
||||
|
||||
storageBuffer.unmap();
|
||||
|
||||
const bindGroupLayout = device.createBindGroupLayout({
|
||||
entries: [
|
||||
{
|
||||
binding: 0,
|
||||
visibility: 4,
|
||||
buffer: {
|
||||
type: "storage",
|
||||
minBindingSize: 4,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const bindGroup = device.createBindGroup({
|
||||
layout: bindGroupLayout,
|
||||
entries: [
|
||||
{
|
||||
binding: 0,
|
||||
resource: {
|
||||
buffer: storageBuffer,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const pipelineLayout = device.createPipelineLayout({
|
||||
bindGroupLayouts: [bindGroupLayout],
|
||||
});
|
||||
|
||||
const computePipeline = device.createComputePipeline({
|
||||
layout: pipelineLayout,
|
||||
compute: {
|
||||
module: shaderModule,
|
||||
entryPoint: "main",
|
||||
},
|
||||
});
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
|
||||
const computePass = encoder.beginComputePass();
|
||||
computePass.setPipeline(computePipeline);
|
||||
computePass.setBindGroup(0, bindGroup);
|
||||
computePass.insertDebugMarker("compute collatz iterations");
|
||||
computePass.dispatch(numbers.length);
|
||||
computePass.endPass();
|
||||
|
||||
encoder.copyBufferToBuffer(storageBuffer, 0, stagingBuffer, 0, size);
|
||||
|
||||
device.queue.submit([encoder.finish()]);
|
||||
|
||||
await stagingBuffer.mapAsync(1);
|
||||
|
||||
const data = stagingBuffer.getMappedRange();
|
||||
|
||||
assertEquals(new Uint32Array(data), new Uint32Array([0, 2, 7, 55]));
|
||||
|
||||
stagingBuffer.unmap();
|
||||
|
||||
device.destroy();
|
||||
|
||||
// TODO(lucacasonato): webgpu spec should add a explicit destroy method for
|
||||
// adapters.
|
||||
const resources = Object.keys(Deno.resources());
|
||||
Deno.close(Number(resources[resources.length - 1]));
|
||||
});
|
||||
|
||||
// Skip this test on linux CI, because the vulkan emulator is not good enough
|
||||
// yet, and skip on macOS because these do not have virtual GPUs.
|
||||
unitTest({
|
||||
perms: { read: true, env: true },
|
||||
ignore: (Deno.build.os === "linux" || Deno.build.os === "darwin") && isCI,
|
||||
}, async function webgpuHelloTriangle() {
|
||||
const adapter = await navigator.gpu.requestAdapter();
|
||||
assert(adapter);
|
||||
|
||||
const device = await adapter.requestDevice();
|
||||
assert(device);
|
||||
|
||||
const shaderCode = await Deno.readTextFile(
|
||||
"cli/tests/webgpu_hellotriangle_shader.wgsl",
|
||||
);
|
||||
|
||||
const shaderModule = device.createShaderModule({
|
||||
code: shaderCode,
|
||||
});
|
||||
|
||||
const pipelineLayout = device.createPipelineLayout({
|
||||
bindGroupLayouts: [],
|
||||
});
|
||||
|
||||
const renderPipeline = device.createRenderPipeline({
|
||||
layout: pipelineLayout,
|
||||
vertex: {
|
||||
module: shaderModule,
|
||||
entryPoint: "vs_main",
|
||||
},
|
||||
fragment: {
|
||||
module: shaderModule,
|
||||
entryPoint: "fs_main",
|
||||
targets: [
|
||||
{
|
||||
format: "rgba8unorm-srgb",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const dimensions = {
|
||||
width: 200,
|
||||
height: 200,
|
||||
};
|
||||
const unpaddedBytesPerRow = dimensions.width * 4;
|
||||
const align = 256;
|
||||
const paddedBytesPerRowPadding = (align - unpaddedBytesPerRow % align) %
|
||||
align;
|
||||
const paddedBytesPerRow = unpaddedBytesPerRow + paddedBytesPerRowPadding;
|
||||
|
||||
const outputBuffer = device.createBuffer({
|
||||
label: "Capture",
|
||||
size: paddedBytesPerRow * dimensions.height,
|
||||
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
const texture = device.createTexture({
|
||||
label: "Capture",
|
||||
size: dimensions,
|
||||
format: "rgba8unorm-srgb",
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
|
||||
});
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
const renderPass = encoder.beginRenderPass({
|
||||
colorAttachments: [
|
||||
{
|
||||
view: texture.createView(),
|
||||
storeOp: "store",
|
||||
loadValue: [0, 1, 0, 1],
|
||||
},
|
||||
],
|
||||
});
|
||||
renderPass.setPipeline(renderPipeline);
|
||||
renderPass.draw(3, 1);
|
||||
renderPass.endPass();
|
||||
|
||||
encoder.copyTextureToBuffer(
|
||||
{
|
||||
texture,
|
||||
},
|
||||
{
|
||||
buffer: outputBuffer,
|
||||
bytesPerRow: paddedBytesPerRow,
|
||||
rowsPerImage: 0,
|
||||
},
|
||||
dimensions,
|
||||
);
|
||||
|
||||
device.queue.submit([encoder.finish()]);
|
||||
|
||||
await outputBuffer.mapAsync(1);
|
||||
const data = new Uint8Array(outputBuffer.getMappedRange());
|
||||
|
||||
assertEquals(data, await Deno.readFile("cli/tests/webgpu_hellotriangle.out"));
|
||||
|
||||
outputBuffer.unmap();
|
||||
|
||||
device.destroy();
|
||||
|
||||
// TODO(lucacasonato): webgpu spec should add a explicit destroy method for
|
||||
// adapters.
|
||||
const resources = Object.keys(Deno.resources());
|
||||
Deno.close(Number(resources[resources.length - 1]));
|
||||
});
|
39
cli/tests/webgpu_computepass_shader.wgsl
Normal file
39
cli/tests/webgpu_computepass_shader.wgsl
Normal file
|
@ -0,0 +1,39 @@
|
|||
[[builtin(global_invocation_id)]]
|
||||
var global_id: vec3<u32>;
|
||||
|
||||
[[block]]
|
||||
struct PrimeIndices {
|
||||
data: [[stride(4)]] array<u32>;
|
||||
}; // this is used as both input and output for convenience
|
||||
|
||||
[[group(0), binding(0)]]
|
||||
var<storage> v_indices: [[access(read_write)]] PrimeIndices;
|
||||
|
||||
// The Collatz Conjecture states that for any integer n:
|
||||
// If n is even, n = n/2
|
||||
// If n is odd, n = 3n+1
|
||||
// And repeat this process for each new n, you will always eventually reach 1.
|
||||
// Though the conjecture has not been proven, no counterexample has ever been found.
|
||||
// This function returns how many times this recurrence needs to be applied to reach 1.
|
||||
fn collatz_iterations(n_base: u32) -> u32{
|
||||
var n: u32 = n_base;
|
||||
var i: u32 = 0u;
|
||||
loop {
|
||||
if (n <= 1u) {
|
||||
break;
|
||||
}
|
||||
if (n % 2u == 0u) {
|
||||
n = n / 2u;
|
||||
}
|
||||
else {
|
||||
n = 3u * n + 1u;
|
||||
}
|
||||
i = i + 1u;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
[[stage(compute), workgroup_size(1)]]
|
||||
fn main() {
|
||||
v_indices.data[global_id.x] = collatz_iterations(v_indices.data[global_id.x]);
|
||||
}
|
BIN
cli/tests/webgpu_hellotriangle.out
Normal file
BIN
cli/tests/webgpu_hellotriangle.out
Normal file
Binary file not shown.
19
cli/tests/webgpu_hellotriangle_shader.wgsl
Normal file
19
cli/tests/webgpu_hellotriangle_shader.wgsl
Normal file
|
@ -0,0 +1,19 @@
|
|||
[[builtin(vertex_index)]]
|
||||
var<in> in_vertex_index: u32;
|
||||
[[builtin(position)]]
|
||||
var<out> out_pos: vec4<f32>;
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn vs_main() {
|
||||
var x: f32 = f32(i32(in_vertex_index) - 1);
|
||||
var y: f32 = f32(i32(in_vertex_index & 1) * 2 - 1);
|
||||
out_pos = vec4<f32>(x, y, 0.0, 1.0);
|
||||
}
|
||||
|
||||
[[location(0)]]
|
||||
var<out> out_color: vec4<f32>;
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main() {
|
||||
out_color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
|
@ -31,6 +31,7 @@ use std::sync::Mutex;
|
|||
pub static DENO_NS_LIB: &str = include_str!("dts/lib.deno.ns.d.ts");
|
||||
pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH"));
|
||||
pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH"));
|
||||
pub static DENO_WEBGPU_LIB: &str = include_str!(env!("DENO_WEBGPU_LIB_PATH"));
|
||||
pub static DENO_WEBSOCKET_LIB: &str =
|
||||
include_str!(env!("DENO_WEBSOCKET_LIB_PATH"));
|
||||
pub static SHARED_GLOBALS_LIB: &str =
|
||||
|
|
|
@ -1204,6 +1204,7 @@
|
|||
window.removeEventListener = EventTarget.prototype.removeEventListener;
|
||||
window.__bootstrap = (window.__bootstrap || {});
|
||||
window.__bootstrap.eventTarget = {
|
||||
EventTarget,
|
||||
setEventTargetData,
|
||||
};
|
||||
window.__bootstrap.event = {
|
||||
|
|
4
op_crates/web/internal.d.ts
vendored
4
op_crates/web/internal.d.ts
vendored
|
@ -270,6 +270,10 @@ declare namespace globalThis {
|
|||
): (v: any, opts: ValueConverterOpts) => any;
|
||||
}
|
||||
|
||||
declare var eventTarget: {
|
||||
EventTarget: typeof EventTarget;
|
||||
};
|
||||
|
||||
declare var url: {
|
||||
URLSearchParams: typeof URLSearchParams;
|
||||
};
|
||||
|
|
5048
op_crates/webgpu/01_webgpu.js
Normal file
5048
op_crates/webgpu/01_webgpu.js
Normal file
File diff suppressed because it is too large
Load diff
1800
op_crates/webgpu/02_idl_types.js
Normal file
1800
op_crates/webgpu/02_idl_types.js
Normal file
File diff suppressed because it is too large
Load diff
21
op_crates/webgpu/Cargo.toml
Normal file
21
op_crates/webgpu/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
[package]
|
||||
name = "deno_webgpu"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
description = "provides webgpu Web API to deno_core"
|
||||
authors = ["the Deno authors"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/denoland/deno"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.79.0", path = "../../core" }
|
||||
tokio = { version = "1.1.1", features = ["full"] }
|
||||
serde = { version = "1.0.123", features = ["derive"] }
|
||||
wgpu-core = { version = "0.7.0", features = ["trace"] }
|
||||
wgpu-types = "0.7.0"
|
35
op_crates/webgpu/README.md
Normal file
35
op_crates/webgpu/README.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
# deno_webgpu
|
||||
|
||||
This op crate implements the WebGPU API as defined in
|
||||
https://gpuweb.github.io/gpuweb/ in Deno. The implementation targets the spec
|
||||
draft as of February 22, 2021. The spec is still very much in flux. This op
|
||||
crate tries to stay up to date with the spec, but is constrained by the features
|
||||
implemented in our GPU backend library [wgpu](https://github.com/gfx-rs/wgpu).
|
||||
|
||||
The spec is still very bare bones, and is still missing many details. As the
|
||||
spec becomes more concrete, we will implement to follow the spec more closely.
|
||||
|
||||
In addition, setting the `DENO_WEBGPU_TRACE` environmental variable will output
|
||||
a
|
||||
[wgpu trace](https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications#tracing-infrastructure)
|
||||
to the specified directory.
|
||||
|
||||
For testing this op crate will make use of the WebGPU conformance tests suite,
|
||||
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
|
||||
Windows.
|
||||
|
||||
## Links
|
||||
|
||||
Specification: https://gpuweb.github.io/gpuweb/
|
||||
|
||||
Design documents: https://github.com/gpuweb/gpuweb/tree/main/design
|
||||
|
||||
Conformance tests suite: https://github.com/gpuweb/cts
|
||||
|
||||
WebGPU examples for Deno: https://github.com/crowlKats/webgpu-examples
|
||||
|
||||
wgpu-users matrix channel: https://matrix.to/#/#wgpu-users:matrix.org
|
362
op_crates/webgpu/binding.rs
Normal file
362
op_crates/webgpu/binding.rs
Normal file
|
@ -0,0 +1,362 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUBindGroupLayout(
|
||||
pub(crate) wgpu_core::id::BindGroupLayoutId,
|
||||
);
|
||||
impl Resource for WebGPUBindGroupLayout {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUBindGroupLayout".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPUBindGroup(pub(crate) wgpu_core::id::BindGroupId);
|
||||
impl Resource for WebGPUBindGroup {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUBindGroup".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUBufferBindingLayout {
|
||||
#[serde(rename = "type")]
|
||||
kind: Option<String>,
|
||||
has_dynamic_offset: Option<bool>,
|
||||
min_binding_size: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUSamplerBindingLayout {
|
||||
#[serde(rename = "type")]
|
||||
kind: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUTextureBindingLayout {
|
||||
sample_type: Option<String>,
|
||||
view_dimension: Option<String>,
|
||||
multisampled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUStorageTextureBindingLayout {
|
||||
access: String,
|
||||
format: String,
|
||||
view_dimension: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUBindGroupLayoutEntry {
|
||||
binding: u32,
|
||||
visibility: u32,
|
||||
buffer: Option<GPUBufferBindingLayout>,
|
||||
sampler: Option<GPUSamplerBindingLayout>,
|
||||
texture: Option<GPUTextureBindingLayout>,
|
||||
storage_texture: Option<GPUStorageTextureBindingLayout>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateBindGroupLayoutArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
entries: Vec<GPUBindGroupLayoutEntry>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_bind_group_layout(
|
||||
state: &mut OpState,
|
||||
args: CreateBindGroupLayoutArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
for entry in &args.entries {
|
||||
entries.push(wgpu_types::BindGroupLayoutEntry {
|
||||
binding: entry.binding,
|
||||
visibility: wgpu_types::ShaderStage::from_bits(entry.visibility).unwrap(),
|
||||
ty: if let Some(buffer) = &entry.buffer {
|
||||
wgpu_types::BindingType::Buffer {
|
||||
ty: match &buffer.kind {
|
||||
Some(kind) => match kind.as_str() {
|
||||
"uniform" => wgpu_types::BufferBindingType::Uniform,
|
||||
"storage" => {
|
||||
wgpu_types::BufferBindingType::Storage { read_only: false }
|
||||
}
|
||||
"read-only-storage" => {
|
||||
wgpu_types::BufferBindingType::Storage { read_only: true }
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::BufferBindingType::Uniform,
|
||||
},
|
||||
has_dynamic_offset: buffer.has_dynamic_offset.unwrap_or(false),
|
||||
min_binding_size: if let Some(min_binding_size) =
|
||||
buffer.min_binding_size
|
||||
{
|
||||
std::num::NonZeroU64::new(min_binding_size)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
} else if let Some(sampler) = &entry.sampler {
|
||||
match &sampler.kind {
|
||||
Some(kind) => match kind.as_str() {
|
||||
"filtering" => wgpu_types::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: false,
|
||||
},
|
||||
"non-filtering" => wgpu_types::BindingType::Sampler {
|
||||
filtering: false,
|
||||
comparison: false,
|
||||
},
|
||||
"comparison" => wgpu_types::BindingType::Sampler {
|
||||
filtering: false,
|
||||
comparison: true,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: false,
|
||||
},
|
||||
}
|
||||
} else if let Some(texture) = &entry.texture {
|
||||
wgpu_types::BindingType::Texture {
|
||||
sample_type: match &texture.sample_type {
|
||||
Some(sample_type) => match sample_type.as_str() {
|
||||
"float" => {
|
||||
wgpu_types::TextureSampleType::Float { filterable: true }
|
||||
}
|
||||
"unfilterable-float" => {
|
||||
wgpu_types::TextureSampleType::Float { filterable: false }
|
||||
}
|
||||
"depth" => wgpu_types::TextureSampleType::Depth,
|
||||
"sint" => wgpu_types::TextureSampleType::Sint,
|
||||
"uint" => wgpu_types::TextureSampleType::Uint,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
view_dimension: match &texture.view_dimension {
|
||||
Some(view_dimension) => {
|
||||
super::texture::serialize_dimension(view_dimension)
|
||||
}
|
||||
None => wgpu_types::TextureViewDimension::D2,
|
||||
},
|
||||
multisampled: texture.multisampled.unwrap_or(false),
|
||||
}
|
||||
} else if let Some(storage_texture) = &entry.storage_texture {
|
||||
wgpu_types::BindingType::StorageTexture {
|
||||
access: match storage_texture.access.as_str() {
|
||||
"read-only" => wgpu_types::StorageTextureAccess::ReadOnly,
|
||||
"write-only" => wgpu_types::StorageTextureAccess::WriteOnly,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
format: super::texture::serialize_texture_format(
|
||||
&storage_texture.format,
|
||||
)?,
|
||||
view_dimension: match &storage_texture.view_dimension {
|
||||
Some(view_dimension) => {
|
||||
super::texture::serialize_dimension(view_dimension)
|
||||
}
|
||||
None => wgpu_types::TextureViewDimension::D2,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
count: None, // native-only
|
||||
});
|
||||
}
|
||||
|
||||
let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
entries: Cow::from(entries),
|
||||
};
|
||||
|
||||
let (bind_group_layout, maybe_err) = gfx_select!(device => instance.device_create_bind_group_layout(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPUBindGroupLayout(bind_group_layout));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreatePipelineLayoutArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
bind_group_layouts: Vec<u32>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_pipeline_layout(
|
||||
state: &mut OpState,
|
||||
args: CreatePipelineLayoutArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let mut bind_group_layouts = vec![];
|
||||
|
||||
for rid in &args.bind_group_layouts {
|
||||
let bind_group_layout = state
|
||||
.resource_table
|
||||
.get::<WebGPUBindGroupLayout>(*rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
bind_group_layouts.push(bind_group_layout.0);
|
||||
}
|
||||
|
||||
let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
bind_group_layouts: Cow::from(bind_group_layouts),
|
||||
push_constant_ranges: Default::default(),
|
||||
};
|
||||
|
||||
let (pipeline_layout, maybe_err) = gfx_select!(device => instance.device_create_pipeline_layout(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(super::pipeline::WebGPUPipelineLayout(pipeline_layout));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUBindGroupEntry {
|
||||
binding: u32,
|
||||
kind: String,
|
||||
resource: u32,
|
||||
offset: Option<u64>,
|
||||
size: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateBindGroupArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
layout: u32,
|
||||
entries: Vec<GPUBindGroupEntry>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_bind_group(
|
||||
state: &mut OpState,
|
||||
args: CreateBindGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
for entry in &args.entries {
|
||||
let e = wgpu_core::binding_model::BindGroupEntry {
|
||||
binding: entry.binding,
|
||||
resource: match entry.kind.as_str() {
|
||||
"GPUSampler" => {
|
||||
let sampler_resource = state
|
||||
.resource_table
|
||||
.get::<super::sampler::WebGPUSampler>(entry.resource)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
wgpu_core::binding_model::BindingResource::Sampler(sampler_resource.0)
|
||||
}
|
||||
"GPUTextureView" => {
|
||||
let texture_view_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTextureView>(entry.resource)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
wgpu_core::binding_model::BindingResource::TextureView(
|
||||
texture_view_resource.0,
|
||||
)
|
||||
}
|
||||
"GPUBufferBinding" => {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(entry.resource)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
wgpu_core::binding_model::BindingResource::Buffer(
|
||||
wgpu_core::binding_model::BufferBinding {
|
||||
buffer_id: buffer_resource.0,
|
||||
offset: entry.offset.unwrap_or(0),
|
||||
size: std::num::NonZeroU64::new(entry.size.unwrap_or(0)),
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
entries.push(e);
|
||||
}
|
||||
|
||||
let bind_group_layout = state
|
||||
.resource_table
|
||||
.get::<WebGPUBindGroupLayout>(args.layout)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let descriptor = wgpu_core::binding_model::BindGroupDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
layout: bind_group_layout.0,
|
||||
entries: Cow::from(entries),
|
||||
};
|
||||
|
||||
let (bind_group, maybe_err) = gfx_select!(device => instance.device_create_bind_group(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUBindGroup(bind_group));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
243
op_crates/webgpu/buffer.rs
Normal file
243
op_crates/webgpu/buffer.rs
Normal file
|
@ -0,0 +1,243 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::channel::oneshot;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{BufVec, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::error::DOMExceptionOperationError;
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUBuffer(pub(crate) wgpu_core::id::BufferId);
|
||||
impl Resource for WebGPUBuffer {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUBuffer".into()
|
||||
}
|
||||
}
|
||||
|
||||
struct WebGPUBufferMapped(*mut u8, usize);
|
||||
impl Resource for WebGPUBufferMapped {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUBufferMapped".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateBufferArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
size: u64,
|
||||
usage: u32,
|
||||
mapped_at_creation: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_buffer(
|
||||
state: &mut OpState,
|
||||
args: CreateBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let descriptor = wgpu_core::resource::BufferDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
size: args.size,
|
||||
usage: wgpu_types::BufferUsage::from_bits(args.usage).unwrap(),
|
||||
mapped_at_creation: args.mapped_at_creation.unwrap_or(false),
|
||||
};
|
||||
|
||||
let (buffer, maybe_err) = gfx_select!(device => instance.device_create_buffer(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUBuffer(buffer));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BufferGetMapAsyncArgs {
|
||||
buffer_rid: u32,
|
||||
device_rid: u32,
|
||||
mode: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub async fn op_webgpu_buffer_get_map_async(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
args: BufferGetMapAsyncArgs,
|
||||
_bufs: BufVec,
|
||||
) -> Result<Value, AnyError> {
|
||||
let (sender, receiver) = oneshot::channel::<Result<(), AnyError>>();
|
||||
|
||||
let device;
|
||||
{
|
||||
let state_ = state.borrow();
|
||||
let instance = state_.borrow::<super::Instance>();
|
||||
let buffer_resource = state_
|
||||
.resource_table
|
||||
.get::<WebGPUBuffer>(args.buffer_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let buffer = buffer_resource.0;
|
||||
let device_resource = state_
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
device = device_resource.0;
|
||||
|
||||
let boxed_sender = Box::new(sender);
|
||||
let sender_ptr = Box::into_raw(boxed_sender) as *mut u8;
|
||||
|
||||
extern "C" fn buffer_map_future_wrapper(
|
||||
status: wgpu_core::resource::BufferMapAsyncStatus,
|
||||
user_data: *mut u8,
|
||||
) {
|
||||
let sender_ptr = user_data as *mut oneshot::Sender<Result<(), AnyError>>;
|
||||
let boxed_sender = unsafe { Box::from_raw(sender_ptr) };
|
||||
boxed_sender
|
||||
.send(match status {
|
||||
wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()),
|
||||
_ => unreachable!(), // TODO
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// TODO(lucacasonato): error handling
|
||||
gfx_select!(buffer => instance.buffer_map_async(
|
||||
buffer,
|
||||
args.offset..(args.offset + args.size),
|
||||
wgpu_core::resource::BufferMapOperation {
|
||||
host: match args.mode {
|
||||
1 => wgpu_core::device::HostMap::Read,
|
||||
2 => wgpu_core::device::HostMap::Write,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
callback: buffer_map_future_wrapper,
|
||||
user_data: sender_ptr,
|
||||
}
|
||||
))?;
|
||||
}
|
||||
|
||||
let done = Rc::new(RefCell::new(false));
|
||||
let done_ = done.clone();
|
||||
let device_poll_fut = async move {
|
||||
while !*done.borrow() {
|
||||
{
|
||||
let state = state.borrow();
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
gfx_select!(device => instance.device_poll(device, false)).unwrap()
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
Ok::<(), AnyError>(())
|
||||
};
|
||||
|
||||
let receiver_fut = async move {
|
||||
receiver.await??;
|
||||
let mut done = done_.borrow_mut();
|
||||
*done = true;
|
||||
Ok::<(), AnyError>(())
|
||||
};
|
||||
|
||||
tokio::try_join!(device_poll_fut, receiver_fut)?;
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BufferGetMappedRangeArgs {
|
||||
buffer_rid: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_buffer_get_mapped_range(
|
||||
state: &mut OpState,
|
||||
args: BufferGetMappedRangeArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUBuffer>(args.buffer_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let buffer = buffer_resource.0;
|
||||
|
||||
let slice_pointer = gfx_select!(buffer => instance.buffer_get_mapped_range(
|
||||
buffer,
|
||||
args.offset,
|
||||
std::num::NonZeroU64::new(args.size)
|
||||
))
|
||||
.map_err(|e| DOMExceptionOperationError::new(&e.to_string()))?;
|
||||
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts_mut(slice_pointer, args.size as usize)
|
||||
};
|
||||
zero_copy[0].copy_from_slice(slice);
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPUBufferMapped(slice_pointer, args.size as usize));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BufferUnmapArgs {
|
||||
buffer_rid: u32,
|
||||
mapped_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_buffer_unmap(
|
||||
state: &mut OpState,
|
||||
args: BufferUnmapArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let mapped_resource = state
|
||||
.resource_table
|
||||
.take::<WebGPUBufferMapped>(args.mapped_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUBuffer>(args.buffer_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let buffer = buffer_resource.0;
|
||||
|
||||
let slice_pointer = mapped_resource.0;
|
||||
let size = mapped_resource.1;
|
||||
|
||||
if let Some(buffer) = zero_copy.get(0) {
|
||||
let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) };
|
||||
slice.copy_from_slice(&buffer);
|
||||
}
|
||||
|
||||
let maybe_err = gfx_select!(buffer => instance.buffer_unmap(buffer)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
465
op_crates/webgpu/bundle.rs
Normal file
465
op_crates/webgpu/bundle.rs
Normal file
|
@ -0,0 +1,465 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
use super::texture::serialize_texture_format;
|
||||
|
||||
struct WebGPURenderBundleEncoder(
|
||||
RefCell<wgpu_core::command::RenderBundleEncoder>,
|
||||
);
|
||||
impl Resource for WebGPURenderBundleEncoder {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPURenderBundleEncoder".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPURenderBundle(pub(crate) wgpu_core::id::RenderBundleId);
|
||||
impl Resource for WebGPURenderBundle {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPURenderBundle".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateRenderBundleEncoderArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
color_formats: Vec<String>,
|
||||
depth_stencil_format: Option<String>,
|
||||
sample_count: Option<u32>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_render_bundle_encoder(
|
||||
state: &mut OpState,
|
||||
args: CreateRenderBundleEncoderArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let mut color_formats = vec![];
|
||||
|
||||
for format in &args.color_formats {
|
||||
color_formats.push(serialize_texture_format(format)?);
|
||||
}
|
||||
|
||||
let descriptor = wgpu_core::command::RenderBundleEncoderDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
color_formats: Cow::from(color_formats),
|
||||
depth_stencil_format: args
|
||||
.depth_stencil_format
|
||||
.map(|s| serialize_texture_format(&s))
|
||||
.transpose()?,
|
||||
sample_count: args.sample_count.unwrap_or(1),
|
||||
};
|
||||
|
||||
let res =
|
||||
wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None);
|
||||
let (render_bundle_encoder, maybe_err) = match res {
|
||||
Ok(encoder) => (encoder, None),
|
||||
Err(e) => (
|
||||
wgpu_core::command::RenderBundleEncoder::dummy(device),
|
||||
Some(e),
|
||||
),
|
||||
};
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPURenderBundleEncoder(RefCell::new(
|
||||
render_bundle_encoder,
|
||||
)));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from),
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderFinishArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
label: Option<String>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_finish(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderFinishArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.take::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder = Rc::try_unwrap(render_bundle_encoder_resource)
|
||||
.ok()
|
||||
.expect("unwrapping render_bundle_encoder_resource should succeed")
|
||||
.0
|
||||
.into_inner();
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
|
||||
let (render_bundle, maybe_err) = gfx_select!(render_bundle_encoder.parent() => instance.render_bundle_encoder_finish(
|
||||
render_bundle_encoder,
|
||||
&wgpu_core::command::RenderBundleDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
},
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPURenderBundle(render_bundle));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderSetBindGroupArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
index: u32,
|
||||
bind_group: u32,
|
||||
dynamic_offsets_data: Option<Vec<u32>>,
|
||||
dynamic_offsets_data_start: usize,
|
||||
dynamic_offsets_data_length: usize,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_set_bind_group(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderSetBindGroupArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let bind_group_resource = state
|
||||
.resource_table
|
||||
.get::<super::binding::WebGPUBindGroup>(args.bind_group)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
// I know this might look like it can be easily deduplicated, but it can not
|
||||
// be due to the lifetime of the args.dynamic_offsets_data slice. Because we
|
||||
// need to use a raw pointer here the slice can be freed before the pointer
|
||||
// is used in wgpu_render_pass_set_bind_group. See
|
||||
// https://matrix.to/#/!XFRnMvAfptAHthwBCx:matrix.org/$HgrlhD-Me1DwsGb8UdMu2Hqubgks8s7ILwWRwigOUAg
|
||||
match args.dynamic_offsets_data {
|
||||
Some(data) => unsafe {
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
args.index,
|
||||
bind_group_resource.0,
|
||||
data.as_slice().as_ptr(),
|
||||
args.dynamic_offsets_data_length,
|
||||
);
|
||||
},
|
||||
None => {
|
||||
let (prefix, data, suffix) = unsafe { zero_copy[0].align_to::<u32>() };
|
||||
assert!(prefix.is_empty());
|
||||
assert!(suffix.is_empty());
|
||||
unsafe {
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
args.index,
|
||||
bind_group_resource.0,
|
||||
data[args.dynamic_offsets_data_start..].as_ptr(),
|
||||
args.dynamic_offsets_data_length,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderPushDebugGroupArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
group_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_push_debug_group(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderPushDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.group_label).unwrap();
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderPopDebugGroupArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_pop_debug_group(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderPopDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderInsertDebugMarkerArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
marker_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_insert_debug_marker(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderInsertDebugMarkerArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.marker_label).unwrap();
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderSetPipelineArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
pipeline: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_set_pipeline(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderSetPipelineArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pipeline_resource = state
|
||||
.resource_table
|
||||
.get::<super::pipeline::WebGPURenderPipeline>(args.pipeline)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
render_pipeline_resource.0,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderSetIndexBufferArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
buffer: u32,
|
||||
index_format: String,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_set_index_buffer(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderSetIndexBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
render_bundle_encoder_resource
|
||||
.0
|
||||
.borrow_mut()
|
||||
.set_index_buffer(
|
||||
buffer_resource.0,
|
||||
super::pipeline::serialize_index_format(args.index_format),
|
||||
args.offset,
|
||||
std::num::NonZeroU64::new(args.size),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderSetVertexBufferArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
slot: u32,
|
||||
buffer: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderSetVertexBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
args.slot,
|
||||
buffer_resource.0,
|
||||
args.offset,
|
||||
std::num::NonZeroU64::new(args.size),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderDrawArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_draw(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderDrawArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
args.vertex_count,
|
||||
args.instance_count,
|
||||
args.first_vertex,
|
||||
args.first_instance,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderDrawIndexedArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_draw_indexed(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderDrawIndexedArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
args.index_count,
|
||||
args.instance_count,
|
||||
args.first_index,
|
||||
args.base_vertex,
|
||||
args.first_instance,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderBundleEncoderDrawIndirectArgs {
|
||||
render_bundle_encoder_rid: u32,
|
||||
indirect_buffer: u32,
|
||||
indirect_offset: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_bundle_encoder_draw_indirect(
|
||||
state: &mut OpState,
|
||||
args: RenderBundleEncoderDrawIndirectArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.indirect_buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_bundle_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderBundleEncoder>(args.render_bundle_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect(
|
||||
&mut render_bundle_encoder_resource.0.borrow_mut(),
|
||||
buffer_resource.0,
|
||||
args.indirect_offset,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
734
op_crates/webgpu/command_encoder.rs
Normal file
734
op_crates/webgpu/command_encoder.rs
Normal file
|
@ -0,0 +1,734 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUCommandEncoder(
|
||||
pub(crate) wgpu_core::id::CommandEncoderId,
|
||||
);
|
||||
impl Resource for WebGPUCommandEncoder {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUCommandEncoder".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPUCommandBuffer(
|
||||
pub(crate) wgpu_core::id::CommandBufferId,
|
||||
);
|
||||
impl Resource for WebGPUCommandBuffer {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUCommandBuffer".into()
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_store_op(store_op: String) -> wgpu_core::command::StoreOp {
|
||||
match store_op.as_str() {
|
||||
"store" => wgpu_core::command::StoreOp::Store,
|
||||
"clear" => wgpu_core::command::StoreOp::Clear,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateCommandEncoderArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
_measure_execution_time: Option<bool>, // not yet implemented
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_command_encoder(
|
||||
state: &mut OpState,
|
||||
args: CreateCommandEncoderArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let descriptor = wgpu_types::CommandEncoderDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
};
|
||||
|
||||
let (command_encoder, maybe_err) = gfx_select!(device => instance.device_create_command_encoder(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPUCommandEncoder(command_encoder));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from),
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPURenderPassColorAttachment {
|
||||
view: u32,
|
||||
resolve_target: Option<u32>,
|
||||
load_op: String,
|
||||
load_value: Option<super::render_pass::GPUColor>,
|
||||
store_op: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPURenderPassDepthStencilAttachment {
|
||||
view: u32,
|
||||
depth_load_op: String,
|
||||
depth_load_value: Option<f32>,
|
||||
depth_store_op: String,
|
||||
depth_read_only: Option<bool>,
|
||||
stencil_load_op: String,
|
||||
stencil_load_value: Option<u32>,
|
||||
stencil_store_op: String,
|
||||
stencil_read_only: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderBeginRenderPassArgs {
|
||||
command_encoder_rid: u32,
|
||||
label: Option<String>,
|
||||
color_attachments: Vec<GPURenderPassColorAttachment>,
|
||||
depth_stencil_attachment: Option<GPURenderPassDepthStencilAttachment>,
|
||||
_occlusion_query_set: Option<u32>, // not yet implemented
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_begin_render_pass(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderBeginRenderPassArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let mut color_attachments = vec![];
|
||||
|
||||
for color_attachment in args.color_attachments {
|
||||
let texture_view_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTextureView>(color_attachment.view)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let attachment = wgpu_core::command::ColorAttachmentDescriptor {
|
||||
attachment: texture_view_resource.0,
|
||||
resolve_target: color_attachment
|
||||
.resolve_target
|
||||
.map(|rid| {
|
||||
state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTextureView>(rid)
|
||||
.ok_or_else(bad_resource_id)
|
||||
})
|
||||
.transpose()?
|
||||
.map(|texture| texture.0),
|
||||
channel: match color_attachment.load_op.as_str() {
|
||||
"load" => wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Load,
|
||||
store_op: color_attachment
|
||||
.store_op
|
||||
.map_or(wgpu_core::command::StoreOp::Store, serialize_store_op),
|
||||
clear_value: Default::default(),
|
||||
read_only: false,
|
||||
},
|
||||
"clear" => {
|
||||
let color = color_attachment.load_value.unwrap();
|
||||
wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Clear,
|
||||
store_op: color_attachment
|
||||
.store_op
|
||||
.map_or(wgpu_core::command::StoreOp::Store, serialize_store_op),
|
||||
clear_value: wgpu_types::Color {
|
||||
r: color.r,
|
||||
g: color.g,
|
||||
b: color.b,
|
||||
a: color.a,
|
||||
},
|
||||
read_only: false,
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
|
||||
color_attachments.push(attachment)
|
||||
}
|
||||
|
||||
let mut depth_stencil_attachment = None;
|
||||
|
||||
if let Some(attachment) = args.depth_stencil_attachment {
|
||||
let texture_view_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTextureView>(attachment.view)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
depth_stencil_attachment =
|
||||
Some(wgpu_core::command::DepthStencilAttachmentDescriptor {
|
||||
attachment: texture_view_resource.0,
|
||||
depth: match attachment.depth_load_op.as_str() {
|
||||
"load" => wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Load,
|
||||
store_op: serialize_store_op(attachment.depth_store_op),
|
||||
clear_value: 0.0,
|
||||
read_only: attachment.depth_read_only.unwrap_or(false),
|
||||
},
|
||||
"clear" => wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Clear,
|
||||
store_op: serialize_store_op(attachment.depth_store_op),
|
||||
clear_value: attachment.depth_load_value.unwrap(),
|
||||
read_only: attachment.depth_read_only.unwrap_or(false),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
stencil: match attachment.stencil_load_op.as_str() {
|
||||
"load" => wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Load,
|
||||
store_op: serialize_store_op(attachment.stencil_store_op),
|
||||
clear_value: 0,
|
||||
read_only: attachment.stencil_read_only.unwrap_or(false),
|
||||
},
|
||||
"clear" => wgpu_core::command::PassChannel {
|
||||
load_op: wgpu_core::command::LoadOp::Clear,
|
||||
store_op: serialize_store_op(attachment.stencil_store_op),
|
||||
clear_value: attachment.stencil_load_value.unwrap(),
|
||||
read_only: attachment.stencil_read_only.unwrap_or(false),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let descriptor = wgpu_core::command::RenderPassDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
color_attachments: Cow::from(color_attachments),
|
||||
depth_stencil_attachment: depth_stencil_attachment.as_ref(),
|
||||
};
|
||||
|
||||
let render_pass = wgpu_core::command::RenderPass::new(
|
||||
command_encoder_resource.0,
|
||||
&descriptor,
|
||||
);
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(super::render_pass::WebGPURenderPass(RefCell::new(
|
||||
render_pass,
|
||||
)));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderBeginComputePassArgs {
|
||||
command_encoder_rid: u32,
|
||||
label: Option<String>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_begin_compute_pass(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderBeginComputePassArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let descriptor = wgpu_core::command::ComputePassDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
};
|
||||
|
||||
let compute_pass = wgpu_core::command::ComputePass::new(
|
||||
command_encoder_resource.0,
|
||||
&descriptor,
|
||||
);
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(super::compute_pass::WebGPUComputePass(RefCell::new(
|
||||
compute_pass,
|
||||
)));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderCopyBufferToBufferArgs {
|
||||
command_encoder_rid: u32,
|
||||
source: u32,
|
||||
source_offset: u64,
|
||||
destination: u32,
|
||||
destination_offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_copy_buffer_to_buffer(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderCopyBufferToBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let source_buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.source)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let source_buffer = source_buffer_resource.0;
|
||||
let destination_buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.destination)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let destination_buffer = destination_buffer_resource.0;
|
||||
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_copy_buffer_to_buffer(
|
||||
command_encoder,
|
||||
source_buffer,
|
||||
args.source_offset,
|
||||
destination_buffer,
|
||||
args.destination_offset,
|
||||
args.size
|
||||
)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPUImageCopyBuffer {
|
||||
buffer: u32,
|
||||
offset: Option<u64>,
|
||||
bytes_per_row: Option<u32>,
|
||||
rows_per_image: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPUOrigin3D {
|
||||
pub x: Option<u32>,
|
||||
pub y: Option<u32>,
|
||||
pub z: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPUImageCopyTexture {
|
||||
pub texture: u32,
|
||||
pub mip_level: Option<u32>,
|
||||
pub origin: Option<GPUOrigin3D>,
|
||||
pub _aspect: Option<String>, // not yet implemented
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderCopyBufferToTextureArgs {
|
||||
command_encoder_rid: u32,
|
||||
source: GPUImageCopyBuffer,
|
||||
destination: GPUImageCopyTexture,
|
||||
copy_size: super::texture::GPUExtent3D,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_copy_buffer_to_texture(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderCopyBufferToTextureArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let source_buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.source.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let destination_texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTexture>(args.destination.texture)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let source = wgpu_core::command::BufferCopyView {
|
||||
buffer: source_buffer_resource.0,
|
||||
layout: wgpu_types::TextureDataLayout {
|
||||
offset: args.source.offset.unwrap_or(0),
|
||||
bytes_per_row: args.source.bytes_per_row.unwrap_or(0),
|
||||
rows_per_image: args.source.rows_per_image.unwrap_or(0),
|
||||
},
|
||||
};
|
||||
let destination = wgpu_core::command::TextureCopyView {
|
||||
texture: destination_texture_resource.0,
|
||||
mip_level: args.destination.mip_level.unwrap_or(0),
|
||||
origin: args
|
||||
.destination
|
||||
.origin
|
||||
.map_or(Default::default(), |origin| wgpu_types::Origin3d {
|
||||
x: origin.x.unwrap_or(0),
|
||||
y: origin.y.unwrap_or(0),
|
||||
z: origin.z.unwrap_or(0),
|
||||
}),
|
||||
};
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_copy_buffer_to_texture(
|
||||
command_encoder,
|
||||
&source,
|
||||
&destination,
|
||||
&wgpu_types::Extent3d {
|
||||
width: args.copy_size.width.unwrap_or(1),
|
||||
height: args.copy_size.height.unwrap_or(1),
|
||||
depth: args.copy_size.depth.unwrap_or(1),
|
||||
}
|
||||
)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderCopyTextureToBufferArgs {
|
||||
command_encoder_rid: u32,
|
||||
source: GPUImageCopyTexture,
|
||||
destination: GPUImageCopyBuffer,
|
||||
copy_size: super::texture::GPUExtent3D,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_copy_texture_to_buffer(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderCopyTextureToBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let source_texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTexture>(args.source.texture)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let destination_buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.destination.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let source = wgpu_core::command::TextureCopyView {
|
||||
texture: source_texture_resource.0,
|
||||
mip_level: args.source.mip_level.unwrap_or(0),
|
||||
origin: args.source.origin.map_or(Default::default(), |origin| {
|
||||
wgpu_types::Origin3d {
|
||||
x: origin.x.unwrap_or(0),
|
||||
y: origin.y.unwrap_or(0),
|
||||
z: origin.z.unwrap_or(0),
|
||||
}
|
||||
}),
|
||||
};
|
||||
let destination = wgpu_core::command::BufferCopyView {
|
||||
buffer: destination_buffer_resource.0,
|
||||
layout: wgpu_types::TextureDataLayout {
|
||||
offset: args.destination.offset.unwrap_or(0),
|
||||
bytes_per_row: args.destination.bytes_per_row.unwrap_or(0),
|
||||
rows_per_image: args.destination.rows_per_image.unwrap_or(0),
|
||||
},
|
||||
};
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_copy_texture_to_buffer(
|
||||
command_encoder,
|
||||
&source,
|
||||
&destination,
|
||||
&wgpu_types::Extent3d {
|
||||
width: args.copy_size.width.unwrap_or(1),
|
||||
height: args.copy_size.height.unwrap_or(1),
|
||||
depth: args.copy_size.depth.unwrap_or(1),
|
||||
}
|
||||
)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderCopyTextureToTextureArgs {
|
||||
command_encoder_rid: u32,
|
||||
source: GPUImageCopyTexture,
|
||||
destination: GPUImageCopyTexture,
|
||||
copy_size: super::texture::GPUExtent3D,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_copy_texture_to_texture(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderCopyTextureToTextureArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let source_texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTexture>(args.source.texture)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let destination_texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTexture>(args.destination.texture)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let source = wgpu_core::command::TextureCopyView {
|
||||
texture: source_texture_resource.0,
|
||||
mip_level: args.source.mip_level.unwrap_or(0),
|
||||
origin: args.source.origin.map_or(Default::default(), |origin| {
|
||||
wgpu_types::Origin3d {
|
||||
x: origin.x.unwrap_or(0),
|
||||
y: origin.y.unwrap_or(0),
|
||||
z: origin.z.unwrap_or(0),
|
||||
}
|
||||
}),
|
||||
};
|
||||
let destination = wgpu_core::command::TextureCopyView {
|
||||
texture: destination_texture_resource.0,
|
||||
mip_level: args.destination.mip_level.unwrap_or(0),
|
||||
origin: args
|
||||
.destination
|
||||
.origin
|
||||
.map_or(Default::default(), |origin| wgpu_types::Origin3d {
|
||||
x: origin.x.unwrap_or(0),
|
||||
y: origin.y.unwrap_or(0),
|
||||
z: origin.z.unwrap_or(0),
|
||||
}),
|
||||
};
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_copy_texture_to_texture(
|
||||
command_encoder,
|
||||
&source,
|
||||
&destination,
|
||||
&wgpu_types::Extent3d {
|
||||
width: args.copy_size.width.unwrap_or(1),
|
||||
height: args.copy_size.height.unwrap_or(1),
|
||||
depth: args.copy_size.depth.unwrap_or(1),
|
||||
}
|
||||
)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderPushDebugGroupArgs {
|
||||
command_encoder_rid: u32,
|
||||
group_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_push_debug_group(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderPushDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
|
||||
let maybe_err = gfx_select!(command_encoder => instance
|
||||
.command_encoder_push_debug_group(command_encoder, &args.group_label))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderPopDebugGroupArgs {
|
||||
command_encoder_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_pop_debug_group(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderPopDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_pop_debug_group(command_encoder)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderInsertDebugMarkerArgs {
|
||||
command_encoder_rid: u32,
|
||||
marker_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_insert_debug_marker(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderInsertDebugMarkerArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_insert_debug_marker(
|
||||
command_encoder,
|
||||
&args.marker_label
|
||||
)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderWriteTimestampArgs {
|
||||
command_encoder_rid: u32,
|
||||
query_set: u32,
|
||||
query_index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_write_timestamp(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderWriteTimestampArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let maybe_err =
|
||||
gfx_select!(command_encoder => instance.command_encoder_write_timestamp(
|
||||
command_encoder,
|
||||
query_set_resource.0,
|
||||
args.query_index
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderResolveQuerySetArgs {
|
||||
command_encoder_rid: u32,
|
||||
query_set: u32,
|
||||
first_query: u32,
|
||||
query_count: u32,
|
||||
destination: u32,
|
||||
destination_offset: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_resolve_query_set(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderResolveQuerySetArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let destination_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.destination)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let maybe_err =
|
||||
gfx_select!(command_encoder => instance.command_encoder_resolve_query_set(
|
||||
command_encoder,
|
||||
query_set_resource.0,
|
||||
args.first_query,
|
||||
args.query_count,
|
||||
destination_resource.0,
|
||||
args.destination_offset
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommandEncoderFinishArgs {
|
||||
command_encoder_rid: u32,
|
||||
label: Option<String>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_command_encoder_finish(
|
||||
state: &mut OpState,
|
||||
args: CommandEncoderFinishArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.take::<WebGPUCommandEncoder>(args.command_encoder_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
|
||||
let descriptor = wgpu_types::CommandBufferDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
};
|
||||
|
||||
let (command_buffer, maybe_err) = gfx_select!(command_encoder => instance.command_encoder_finish(
|
||||
command_encoder,
|
||||
&descriptor
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPUCommandBuffer(command_buffer));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
365
op_crates/webgpu/compute_pass.rs
Normal file
365
op_crates/webgpu/compute_pass.rs
Normal file
|
@ -0,0 +1,365 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUComputePass(
|
||||
pub(crate) RefCell<wgpu_core::command::ComputePass>,
|
||||
);
|
||||
impl Resource for WebGPUComputePass {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUComputePass".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassSetPipelineArgs {
|
||||
compute_pass_rid: u32,
|
||||
pipeline: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_set_pipeline(
|
||||
state: &mut OpState,
|
||||
args: ComputePassSetPipelineArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pipeline_resource = state
|
||||
.resource_table
|
||||
.get::<super::pipeline::WebGPUComputePipeline>(args.pipeline)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_set_pipeline(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
compute_pipeline_resource.0,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassDispatchArgs {
|
||||
compute_pass_rid: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_dispatch(
|
||||
state: &mut OpState,
|
||||
args: ComputePassDispatchArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
args.x,
|
||||
args.y,
|
||||
args.z,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassDispatchIndirectArgs {
|
||||
compute_pass_rid: u32,
|
||||
indirect_buffer: u32,
|
||||
indirect_offset: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_dispatch_indirect(
|
||||
state: &mut OpState,
|
||||
args: ComputePassDispatchIndirectArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.indirect_buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_dispatch_indirect(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
buffer_resource.0,
|
||||
args.indirect_offset,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassBeginPipelineStatisticsQueryArgs {
|
||||
compute_pass_rid: u32,
|
||||
query_set: u32,
|
||||
query_index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query(
|
||||
state: &mut OpState,
|
||||
args: ComputePassBeginPipelineStatisticsQueryArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
query_set_resource.0,
|
||||
args.query_index,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassEndPipelineStatisticsQueryArgs {
|
||||
compute_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_end_pipeline_statistics_query(
|
||||
state: &mut OpState,
|
||||
args: ComputePassEndPipelineStatisticsQueryArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassWriteTimestampArgs {
|
||||
compute_pass_rid: u32,
|
||||
query_set: u32,
|
||||
query_index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_write_timestamp(
|
||||
state: &mut OpState,
|
||||
args: ComputePassWriteTimestampArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_write_timestamp(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
query_set_resource.0,
|
||||
args.query_index,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassEndPassArgs {
|
||||
command_encoder_rid: u32,
|
||||
compute_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_end_pass(
|
||||
state: &mut OpState,
|
||||
args: ComputePassEndPassArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<super::command_encoder::WebGPUCommandEncoder>(
|
||||
args.command_encoder_rid,
|
||||
)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.take::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let compute_pass = &compute_pass_resource.0.borrow();
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
|
||||
let maybe_err =
|
||||
gfx_select!(command_encoder => instance.command_encoder_run_compute_pass(
|
||||
command_encoder,
|
||||
compute_pass
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassSetBindGroupArgs {
|
||||
compute_pass_rid: u32,
|
||||
index: u32,
|
||||
bind_group: u32,
|
||||
dynamic_offsets_data: Option<Vec<u32>>,
|
||||
dynamic_offsets_data_start: usize,
|
||||
dynamic_offsets_data_length: usize,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_set_bind_group(
|
||||
state: &mut OpState,
|
||||
args: ComputePassSetBindGroupArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let bind_group_resource = state
|
||||
.resource_table
|
||||
.get::<super::binding::WebGPUBindGroup>(args.bind_group)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_set_bind_group(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
args.index,
|
||||
bind_group_resource.0,
|
||||
match args.dynamic_offsets_data {
|
||||
Some(data) => data.as_ptr(),
|
||||
None => {
|
||||
let (prefix, data, suffix) = zero_copy[0].align_to::<u32>();
|
||||
assert!(prefix.is_empty());
|
||||
assert!(suffix.is_empty());
|
||||
data[args.dynamic_offsets_data_start..].as_ptr()
|
||||
}
|
||||
},
|
||||
args.dynamic_offsets_data_length,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassPushDebugGroupArgs {
|
||||
compute_pass_rid: u32,
|
||||
group_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_push_debug_group(
|
||||
state: &mut OpState,
|
||||
args: ComputePassPushDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.group_label).unwrap();
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_push_debug_group(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
0, // wgpu#975
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassPopDebugGroupArgs {
|
||||
compute_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_pop_debug_group(
|
||||
state: &mut OpState,
|
||||
args: ComputePassPopDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_pop_debug_group(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePassInsertDebugMarkerArgs {
|
||||
compute_pass_rid: u32,
|
||||
marker_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pass_insert_debug_marker(
|
||||
state: &mut OpState,
|
||||
args: ComputePassInsertDebugMarkerArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let compute_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePass>(args.compute_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.marker_label).unwrap();
|
||||
wgpu_core::command::compute_ffi::wgpu_compute_pass_insert_debug_marker(
|
||||
&mut compute_pass_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
0, // wgpu#975
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
252
op_crates/webgpu/error.rs
Normal file
252
op_crates/webgpu/error.rs
Normal file
|
@ -0,0 +1,252 @@
|
|||
use deno_core::error::AnyError;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
use wgpu_core::binding_model::CreateBindGroupError;
|
||||
use wgpu_core::binding_model::CreateBindGroupLayoutError;
|
||||
use wgpu_core::binding_model::CreatePipelineLayoutError;
|
||||
use wgpu_core::binding_model::GetBindGroupLayoutError;
|
||||
use wgpu_core::command::CommandAllocatorError;
|
||||
use wgpu_core::command::CommandEncoderError;
|
||||
use wgpu_core::command::ComputePassError;
|
||||
use wgpu_core::command::CopyError;
|
||||
use wgpu_core::command::CreateRenderBundleError;
|
||||
use wgpu_core::command::QueryError;
|
||||
use wgpu_core::command::RenderBundleError;
|
||||
use wgpu_core::command::RenderPassError;
|
||||
use wgpu_core::device::queue::QueueSubmitError;
|
||||
use wgpu_core::device::queue::QueueWriteError;
|
||||
use wgpu_core::device::DeviceError;
|
||||
use wgpu_core::pipeline::CreateComputePipelineError;
|
||||
use wgpu_core::pipeline::CreateRenderPipelineError;
|
||||
use wgpu_core::pipeline::CreateShaderModuleError;
|
||||
use wgpu_core::resource::BufferAccessError;
|
||||
use wgpu_core::resource::CreateBufferError;
|
||||
use wgpu_core::resource::CreateQuerySetError;
|
||||
use wgpu_core::resource::CreateSamplerError;
|
||||
use wgpu_core::resource::CreateTextureError;
|
||||
use wgpu_core::resource::CreateTextureViewError;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", content = "value")]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum WebGPUError {
|
||||
Lost,
|
||||
OutOfMemory,
|
||||
Validation(String),
|
||||
}
|
||||
|
||||
impl From<CreateBufferError> for WebGPUError {
|
||||
fn from(err: CreateBufferError) -> Self {
|
||||
match err {
|
||||
CreateBufferError::Device(err) => err.into(),
|
||||
CreateBufferError::AccessError(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DeviceError> for WebGPUError {
|
||||
fn from(err: DeviceError) -> Self {
|
||||
match err {
|
||||
DeviceError::Lost => WebGPUError::Lost,
|
||||
DeviceError::OutOfMemory => WebGPUError::OutOfMemory,
|
||||
DeviceError::Invalid => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BufferAccessError> for WebGPUError {
|
||||
fn from(err: BufferAccessError) -> Self {
|
||||
match err {
|
||||
BufferAccessError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateBindGroupLayoutError> for WebGPUError {
|
||||
fn from(err: CreateBindGroupLayoutError) -> Self {
|
||||
match err {
|
||||
CreateBindGroupLayoutError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreatePipelineLayoutError> for WebGPUError {
|
||||
fn from(err: CreatePipelineLayoutError) -> Self {
|
||||
match err {
|
||||
CreatePipelineLayoutError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateBindGroupError> for WebGPUError {
|
||||
fn from(err: CreateBindGroupError) -> Self {
|
||||
match err {
|
||||
CreateBindGroupError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RenderBundleError> for WebGPUError {
|
||||
fn from(err: RenderBundleError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateRenderBundleError> for WebGPUError {
|
||||
fn from(err: CreateRenderBundleError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommandAllocatorError> for WebGPUError {
|
||||
fn from(err: CommandAllocatorError) -> Self {
|
||||
match err {
|
||||
CommandAllocatorError::Device(err) => err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CopyError> for WebGPUError {
|
||||
fn from(err: CopyError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommandEncoderError> for WebGPUError {
|
||||
fn from(err: CommandEncoderError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<QueryError> for WebGPUError {
|
||||
fn from(err: QueryError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ComputePassError> for WebGPUError {
|
||||
fn from(err: ComputePassError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateComputePipelineError> for WebGPUError {
|
||||
fn from(err: CreateComputePipelineError) -> Self {
|
||||
match err {
|
||||
CreateComputePipelineError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GetBindGroupLayoutError> for WebGPUError {
|
||||
fn from(err: GetBindGroupLayoutError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateRenderPipelineError> for WebGPUError {
|
||||
fn from(err: CreateRenderPipelineError) -> Self {
|
||||
match err {
|
||||
CreateRenderPipelineError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RenderPassError> for WebGPUError {
|
||||
fn from(err: RenderPassError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateSamplerError> for WebGPUError {
|
||||
fn from(err: CreateSamplerError) -> Self {
|
||||
match err {
|
||||
CreateSamplerError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateShaderModuleError> for WebGPUError {
|
||||
fn from(err: CreateShaderModuleError) -> Self {
|
||||
match err {
|
||||
CreateShaderModuleError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateTextureError> for WebGPUError {
|
||||
fn from(err: CreateTextureError) -> Self {
|
||||
match err {
|
||||
CreateTextureError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateTextureViewError> for WebGPUError {
|
||||
fn from(err: CreateTextureViewError) -> Self {
|
||||
WebGPUError::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreateQuerySetError> for WebGPUError {
|
||||
fn from(err: CreateQuerySetError) -> Self {
|
||||
match err {
|
||||
CreateQuerySetError::Device(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<QueueSubmitError> for WebGPUError {
|
||||
fn from(err: QueueSubmitError) -> Self {
|
||||
match err {
|
||||
QueueSubmitError::Queue(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<QueueWriteError> for WebGPUError {
|
||||
fn from(err: QueueWriteError) -> Self {
|
||||
match err {
|
||||
QueueWriteError::Queue(err) => err.into(),
|
||||
err => WebGPUError::Validation(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DOMExceptionOperationError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl DOMExceptionOperationError {
|
||||
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 {}
|
||||
|
||||
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||
e.downcast_ref::<DOMExceptionOperationError>()
|
||||
.map(|_| "DOMExceptionOperationError")
|
||||
}
|
1126
op_crates/webgpu/lib.deno_webgpu.d.ts
vendored
Normal file
1126
op_crates/webgpu/lib.deno_webgpu.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
541
op_crates/webgpu/lib.rs
Normal file
541
op_crates/webgpu/lib.rs
Normal file
|
@ -0,0 +1,541 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::{bad_resource_id, not_supported};
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{BufVec, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
pub use wgpu_core;
|
||||
pub use wgpu_types;
|
||||
|
||||
use error::DOMExceptionOperationError;
|
||||
use error::WebGPUError;
|
||||
|
||||
#[macro_use]
|
||||
mod macros {
|
||||
macro_rules! gfx_select {
|
||||
($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {
|
||||
match $id.backend() {
|
||||
#[cfg(all(not(target_arch = "wasm32"), not(any(target_os = "ios", target_os = "macos"))))]
|
||||
wgpu_types::Backend::Vulkan => $global.$method::<wgpu_core::backend::Vulkan>( $($param),* ),
|
||||
#[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))]
|
||||
wgpu_types::Backend::Metal => $global.$method::<wgpu_core::backend::Metal>( $($param),* ),
|
||||
#[cfg(all(not(target_arch = "wasm32"), windows))]
|
||||
wgpu_types::Backend::Dx12 => $global.$method::<wgpu_core::backend::Dx12>( $($param),* ),
|
||||
#[cfg(all(not(target_arch = "wasm32"), windows))]
|
||||
wgpu_types::Backend::Dx11 => $global.$method::<wgpu_core::backend::Dx11>( $($param),* ),
|
||||
#[cfg(any(target_arch = "wasm32", all(unix, not(any(target_os = "ios", target_os = "macos")))))]
|
||||
wgpu_types::Backend::Gl => $global.$method::<wgpu_core::backend::Gl>( $($param),+ ),
|
||||
other => panic!("Unexpected backend {:?}", other),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub mod binding;
|
||||
pub mod buffer;
|
||||
pub mod bundle;
|
||||
pub mod command_encoder;
|
||||
pub mod compute_pass;
|
||||
pub mod error;
|
||||
pub mod pipeline;
|
||||
pub mod queue;
|
||||
pub mod render_pass;
|
||||
pub mod sampler;
|
||||
pub mod shader;
|
||||
pub mod texture;
|
||||
|
||||
pub struct Unstable(pub bool);
|
||||
|
||||
fn check_unstable(state: &OpState, api_name: &str) {
|
||||
let unstable = state.borrow::<Unstable>();
|
||||
|
||||
if !unstable.0 {
|
||||
eprintln!(
|
||||
"Unstable API '{}'. The --unstable flag must be provided.",
|
||||
api_name
|
||||
);
|
||||
std::process::exit(70);
|
||||
}
|
||||
}
|
||||
|
||||
type Instance = wgpu_core::hub::Global<wgpu_core::hub::IdentityManagerFactory>;
|
||||
|
||||
struct WebGPUAdapter(wgpu_core::id::AdapterId);
|
||||
impl Resource for WebGPUAdapter {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUAdapter".into()
|
||||
}
|
||||
}
|
||||
|
||||
struct WebGPUDevice(wgpu_core::id::DeviceId);
|
||||
impl Resource for WebGPUDevice {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUDevice".into()
|
||||
}
|
||||
}
|
||||
|
||||
struct WebGPUQuerySet(wgpu_core::id::QuerySetId);
|
||||
impl Resource for WebGPUQuerySet {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUQuerySet".into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute this crates' JS source files.
|
||||
pub fn init(isolate: &mut deno_core::JsRuntime) {
|
||||
let files = vec![
|
||||
(
|
||||
"deno:op_crates/webgpu/01_webgpu.js",
|
||||
include_str!("01_webgpu.js"),
|
||||
),
|
||||
(
|
||||
"deno:op_crates/webgpu/02_idl_types.js",
|
||||
include_str!("02_idl_types.js"),
|
||||
),
|
||||
];
|
||||
for (url, source_code) in files {
|
||||
isolate.execute(url, source_code).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_declaration() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_webgpu.d.ts")
|
||||
}
|
||||
|
||||
fn deserialize_features(features: &wgpu_types::Features) -> Vec<&str> {
|
||||
let mut return_features: Vec<&str> = vec![];
|
||||
|
||||
if features.contains(wgpu_types::Features::DEPTH_CLAMPING) {
|
||||
return_features.push("depth-clamping");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) {
|
||||
return_features.push("pipeline-statistics-query");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) {
|
||||
return_features.push("texture-compression-bc");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) {
|
||||
return_features.push("timestamp-query");
|
||||
}
|
||||
|
||||
// extended from spec
|
||||
if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) {
|
||||
return_features.push("mappable-primary-buffers");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::SAMPLED_TEXTURE_BINDING_ARRAY) {
|
||||
return_features.push("sampled-texture-binding-array");
|
||||
}
|
||||
if features
|
||||
.contains(wgpu_types::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING)
|
||||
{
|
||||
return_features.push("sampled-texture-array-dynamic-indexing");
|
||||
}
|
||||
if features
|
||||
.contains(wgpu_types::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING)
|
||||
{
|
||||
return_features.push("sampled-texture-array-non-uniform-indexing");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) {
|
||||
return_features.push("unsized-binding-array");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) {
|
||||
return_features.push("multi-draw-indirect");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) {
|
||||
return_features.push("multi-draw-indirect-count");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::PUSH_CONSTANTS) {
|
||||
return_features.push("push-constants");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) {
|
||||
return_features.push("address-mode-clamp-to-border");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::NON_FILL_POLYGON_MODE) {
|
||||
return_features.push("non-fill-polygon-mode");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) {
|
||||
return_features.push("texture-compression-etc2");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) {
|
||||
return_features.push("texture-compression-astc-ldr");
|
||||
}
|
||||
if features
|
||||
.contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES)
|
||||
{
|
||||
return_features.push("texture-adapter-specific-format-features");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::SHADER_FLOAT64) {
|
||||
return_features.push("shader-float64");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) {
|
||||
return_features.push("vertex-attribute-64bit");
|
||||
}
|
||||
|
||||
return_features
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RequestAdapterArgs {
|
||||
power_preference: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn op_webgpu_request_adapter(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
args: RequestAdapterArgs,
|
||||
_bufs: BufVec,
|
||||
) -> Result<Value, AnyError> {
|
||||
let mut state = state.borrow_mut();
|
||||
check_unstable(&state, "navigator.gpu.requestAdapter");
|
||||
let instance = state.borrow::<Instance>();
|
||||
|
||||
let descriptor = wgpu_core::instance::RequestAdapterOptions {
|
||||
power_preference: match args.power_preference {
|
||||
Some(power_preference) => match power_preference.as_str() {
|
||||
"low-power" => wgpu_types::PowerPreference::LowPower,
|
||||
"high-performance" => wgpu_types::PowerPreference::HighPerformance,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => Default::default(),
|
||||
},
|
||||
compatible_surface: None, // windowless
|
||||
};
|
||||
let res = instance.request_adapter(
|
||||
&descriptor,
|
||||
wgpu_core::instance::AdapterInputs::Mask(
|
||||
wgpu_types::BackendBit::PRIMARY,
|
||||
|_| std::marker::PhantomData,
|
||||
),
|
||||
);
|
||||
|
||||
let adapter = match res {
|
||||
Ok(adapter) => adapter,
|
||||
Err(err) => {
|
||||
return Ok(json!({
|
||||
"err": err.to_string()
|
||||
}))
|
||||
}
|
||||
};
|
||||
let name = gfx_select!(adapter => instance.adapter_get_info(adapter))?.name;
|
||||
let adapter_features =
|
||||
gfx_select!(adapter => instance.adapter_features(adapter))?;
|
||||
let features = deserialize_features(&adapter_features);
|
||||
let adapter_limits =
|
||||
gfx_select!(adapter => instance.adapter_limits(adapter))?;
|
||||
|
||||
let limits = json!({
|
||||
"maxBindGroups": adapter_limits.max_bind_groups,
|
||||
"maxDynamicUniformBuffersPerPipelineLayout": adapter_limits.max_dynamic_uniform_buffers_per_pipeline_layout,
|
||||
"maxDynamicStorageBuffersPerPipelineLayout": adapter_limits.max_dynamic_storage_buffers_per_pipeline_layout,
|
||||
"maxSampledTexturesPerShaderStage": adapter_limits.max_sampled_textures_per_shader_stage,
|
||||
"maxSamplersPerShaderStage": adapter_limits.max_samplers_per_shader_stage,
|
||||
"maxStorageBuffersPerShaderStage": adapter_limits.max_storage_buffers_per_shader_stage,
|
||||
"maxStorageTexturesPerShaderStage": adapter_limits.max_storage_textures_per_shader_stage,
|
||||
"maxUniformBuffersPerShaderStage": adapter_limits.max_uniform_buffers_per_shader_stage,
|
||||
"maxUniformBufferBindingSize": adapter_limits.max_uniform_buffer_binding_size
|
||||
});
|
||||
|
||||
let rid = state.resource_table.add(WebGPUAdapter(adapter));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"name": name,
|
||||
"features": features,
|
||||
"limits": limits
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPULimits {
|
||||
_max_texture_dimension1d: Option<u32>,
|
||||
_max_texture_dimension2d: Option<u32>,
|
||||
_max_texture_dimension3d: Option<u32>,
|
||||
_max_texture_array_layers: Option<u32>,
|
||||
max_bind_groups: Option<u32>,
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: Option<u32>,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: Option<u32>,
|
||||
max_sampled_textures_per_shader_stage: Option<u32>,
|
||||
max_samplers_per_shader_stage: Option<u32>,
|
||||
max_storage_buffers_per_shader_stage: Option<u32>,
|
||||
max_storage_textures_per_shader_stage: Option<u32>,
|
||||
max_uniform_buffers_per_shader_stage: Option<u32>,
|
||||
max_uniform_buffer_binding_size: Option<u32>,
|
||||
_max_storage_buffer_binding_size: Option<u32>,
|
||||
_max_vertex_buffers: Option<u32>,
|
||||
_max_vertex_attributes: Option<u32>,
|
||||
_max_vertex_buffer_array_stride: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RequestDeviceArgs {
|
||||
adapter_rid: u32,
|
||||
label: Option<String>,
|
||||
non_guaranteed_features: Option<Vec<String>>,
|
||||
non_guaranteed_limits: Option<GPULimits>,
|
||||
}
|
||||
|
||||
pub async fn op_webgpu_request_device(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
args: RequestDeviceArgs,
|
||||
_bufs: BufVec,
|
||||
) -> Result<Value, AnyError> {
|
||||
let mut state = state.borrow_mut();
|
||||
let adapter_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUAdapter>(args.adapter_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let adapter = adapter_resource.0;
|
||||
let instance = state.borrow::<Instance>();
|
||||
|
||||
let mut features: wgpu_types::Features = wgpu_types::Features::empty();
|
||||
|
||||
if let Some(passed_features) = args.non_guaranteed_features {
|
||||
if passed_features.contains(&"depth-clamping".to_string()) {
|
||||
features.set(wgpu_types::Features::DEPTH_CLAMPING, true);
|
||||
}
|
||||
if passed_features.contains(&"pipeline-statistics-query".to_string()) {
|
||||
features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true);
|
||||
}
|
||||
if passed_features.contains(&"texture-compression-bc".to_string()) {
|
||||
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true);
|
||||
}
|
||||
if passed_features.contains(&"timestamp-query".to_string()) {
|
||||
features.set(wgpu_types::Features::TIMESTAMP_QUERY, true);
|
||||
}
|
||||
|
||||
// extended from spec
|
||||
if passed_features.contains(&"mappable-primary-buffers".to_string()) {
|
||||
features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true);
|
||||
}
|
||||
if passed_features.contains(&"sampled-texture-binding-array".to_string()) {
|
||||
features.set(wgpu_types::Features::SAMPLED_TEXTURE_BINDING_ARRAY, true);
|
||||
}
|
||||
if passed_features
|
||||
.contains(&"sampled-texture-array-dynamic-indexing".to_string())
|
||||
{
|
||||
features.set(
|
||||
wgpu_types::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if passed_features
|
||||
.contains(&"sampled-texture-array-non-uniform-indexing".to_string())
|
||||
{
|
||||
features.set(
|
||||
wgpu_types::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if passed_features.contains(&"unsized-binding-array".to_string()) {
|
||||
features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true);
|
||||
}
|
||||
if passed_features.contains(&"multi-draw-indirect".to_string()) {
|
||||
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true);
|
||||
}
|
||||
if passed_features.contains(&"multi-draw-indirect-count".to_string()) {
|
||||
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true);
|
||||
}
|
||||
if passed_features.contains(&"push-constants".to_string()) {
|
||||
features.set(wgpu_types::Features::PUSH_CONSTANTS, true);
|
||||
}
|
||||
if passed_features.contains(&"address-mode-clamp-to-border".to_string()) {
|
||||
features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true);
|
||||
}
|
||||
if passed_features.contains(&"non-fill-polygon-mode".to_string()) {
|
||||
features.set(wgpu_types::Features::NON_FILL_POLYGON_MODE, true);
|
||||
}
|
||||
if passed_features.contains(&"texture-compression-etc2".to_string()) {
|
||||
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true);
|
||||
}
|
||||
if passed_features.contains(&"texture-compression-astc-ldr".to_string()) {
|
||||
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true);
|
||||
}
|
||||
if passed_features
|
||||
.contains(&"texture-adapter-specific-format-features".to_string())
|
||||
{
|
||||
features.set(
|
||||
wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if passed_features.contains(&"shader-float64".to_string()) {
|
||||
features.set(wgpu_types::Features::SHADER_FLOAT64, true);
|
||||
}
|
||||
if passed_features.contains(&"vertex-attribute-64bit".to_string()) {
|
||||
features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true);
|
||||
}
|
||||
}
|
||||
|
||||
let descriptor = wgpu_types::DeviceDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
features,
|
||||
limits: args
|
||||
.non_guaranteed_limits
|
||||
.map_or(Default::default(), |limits| wgpu_types::Limits {
|
||||
max_bind_groups: limits.max_bind_groups.unwrap_or(4),
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: limits
|
||||
.max_dynamic_uniform_buffers_per_pipeline_layout
|
||||
.unwrap_or(8),
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: limits
|
||||
.max_dynamic_storage_buffers_per_pipeline_layout
|
||||
.unwrap_or(4),
|
||||
max_sampled_textures_per_shader_stage: limits
|
||||
.max_sampled_textures_per_shader_stage
|
||||
.unwrap_or(16),
|
||||
max_samplers_per_shader_stage: limits
|
||||
.max_samplers_per_shader_stage
|
||||
.unwrap_or(16),
|
||||
max_storage_buffers_per_shader_stage: limits
|
||||
.max_storage_buffers_per_shader_stage
|
||||
.unwrap_or(4),
|
||||
max_storage_textures_per_shader_stage: limits
|
||||
.max_storage_textures_per_shader_stage
|
||||
.unwrap_or(4),
|
||||
max_uniform_buffers_per_shader_stage: limits
|
||||
.max_uniform_buffers_per_shader_stage
|
||||
.unwrap_or(12),
|
||||
max_uniform_buffer_binding_size: limits
|
||||
.max_uniform_buffer_binding_size
|
||||
.unwrap_or(16384),
|
||||
max_push_constant_size: 0,
|
||||
}),
|
||||
};
|
||||
|
||||
let (device, 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),
|
||||
std::marker::PhantomData
|
||||
));
|
||||
if let Some(err) = maybe_err {
|
||||
return Err(DOMExceptionOperationError::new(&err.to_string()).into());
|
||||
}
|
||||
|
||||
let device_features =
|
||||
gfx_select!(device => instance.device_features(device))?;
|
||||
let features = deserialize_features(&device_features);
|
||||
let limits = gfx_select!(device => instance.device_limits(device))?;
|
||||
let json_limits = json!({
|
||||
"maxBindGroups": limits.max_bind_groups,
|
||||
"maxDynamicUniformBuffersPerPipelineLayout": limits.max_dynamic_uniform_buffers_per_pipeline_layout,
|
||||
"maxDynamicStorageBuffersPerPipelineLayout": limits.max_dynamic_storage_buffers_per_pipeline_layout,
|
||||
"maxSampledTexturesPerShaderStage": limits.max_sampled_textures_per_shader_stage,
|
||||
"maxSamplersPerShaderStage": limits.max_samplers_per_shader_stage,
|
||||
"maxStorageBuffersPerShaderStage": limits.max_storage_buffers_per_shader_stage,
|
||||
"maxStorageTexturesPerShaderStage": limits.max_storage_textures_per_shader_stage,
|
||||
"maxUniformBuffersPerShaderStage": limits.max_uniform_buffers_per_shader_stage,
|
||||
"maxUniformBufferBindingSize": limits.max_uniform_buffer_binding_size,
|
||||
});
|
||||
|
||||
let rid = state.resource_table.add(WebGPUDevice(device));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"features": features,
|
||||
"limits": json_limits,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateQuerySetArgs {
|
||||
device_rid: u32,
|
||||
_label: Option<String>, // not yet implemented
|
||||
#[serde(rename = "type")]
|
||||
kind: String,
|
||||
count: u32,
|
||||
pipeline_statistics: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_query_set(
|
||||
state: &mut OpState,
|
||||
args: CreateQuerySetArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
let instance = &state.borrow::<Instance>();
|
||||
|
||||
let descriptor = wgpu_types::QuerySetDescriptor {
|
||||
ty: match args.kind.as_str() {
|
||||
"pipeline-statistics" => {
|
||||
let mut pipeline_statistics_names =
|
||||
wgpu_types::PipelineStatisticsTypes::empty();
|
||||
|
||||
if let Some(pipeline_statistics) = args.pipeline_statistics {
|
||||
if pipeline_statistics
|
||||
.contains(&"vertex-shader-invocations".to_string())
|
||||
{
|
||||
pipeline_statistics_names.set(
|
||||
wgpu_types::PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if pipeline_statistics.contains(&"clipper-invocations".to_string()) {
|
||||
pipeline_statistics_names.set(
|
||||
wgpu_types::PipelineStatisticsTypes::CLIPPER_INVOCATIONS,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if pipeline_statistics.contains(&"clipper-primitives-out".to_string())
|
||||
{
|
||||
pipeline_statistics_names.set(
|
||||
wgpu_types::PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if pipeline_statistics
|
||||
.contains(&"fragment-shader-invocations".to_string())
|
||||
{
|
||||
pipeline_statistics_names.set(
|
||||
wgpu_types::PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS,
|
||||
true,
|
||||
);
|
||||
}
|
||||
if pipeline_statistics
|
||||
.contains(&"compute-shader-invocations".to_string())
|
||||
{
|
||||
pipeline_statistics_names.set(
|
||||
wgpu_types::PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
wgpu_types::QueryType::PipelineStatistics(pipeline_statistics_names)
|
||||
}
|
||||
"occlusion" => return Err(not_supported()),
|
||||
"timestamp" => wgpu_types::QueryType::Timestamp,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
count: args.count,
|
||||
};
|
||||
|
||||
let (query_set, maybe_err) = gfx_select!(device => instance.device_create_query_set(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUQuerySet(query_set));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from),
|
||||
}))
|
||||
}
|
643
op_crates/webgpu/pipeline.rs
Normal file
643
op_crates/webgpu/pipeline.rs
Normal file
|
@ -0,0 +1,643 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUPipelineLayout(
|
||||
pub(crate) wgpu_core::id::PipelineLayoutId,
|
||||
);
|
||||
impl Resource for WebGPUPipelineLayout {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUPipelineLayout".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPUComputePipeline(
|
||||
pub(crate) wgpu_core::id::ComputePipelineId,
|
||||
);
|
||||
impl Resource for WebGPUComputePipeline {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUComputePipeline".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPURenderPipeline(
|
||||
pub(crate) wgpu_core::id::RenderPipelineId,
|
||||
);
|
||||
impl Resource for WebGPURenderPipeline {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPURenderPipeline".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_index_format(format: String) -> wgpu_types::IndexFormat {
|
||||
match format.as_str() {
|
||||
"uint16" => wgpu_types::IndexFormat::Uint16,
|
||||
"uint32" => wgpu_types::IndexFormat::Uint32,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_stencil_operation(
|
||||
operation: &str,
|
||||
) -> wgpu_types::StencilOperation {
|
||||
match operation {
|
||||
"keep" => wgpu_types::StencilOperation::Keep,
|
||||
"zero" => wgpu_types::StencilOperation::Zero,
|
||||
"replace" => wgpu_types::StencilOperation::Replace,
|
||||
"invert" => wgpu_types::StencilOperation::Invert,
|
||||
"increment-clamp" => wgpu_types::StencilOperation::IncrementClamp,
|
||||
"decrement-clamp" => wgpu_types::StencilOperation::DecrementClamp,
|
||||
"increment-wrap" => wgpu_types::StencilOperation::IncrementWrap,
|
||||
"decrement-wrap" => wgpu_types::StencilOperation::DecrementWrap,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_stencil_face_state(
|
||||
state: GPUStencilFaceState,
|
||||
) -> wgpu_types::StencilFaceState {
|
||||
wgpu_types::StencilFaceState {
|
||||
compare: state
|
||||
.compare
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::CompareFunction::Always, |op| {
|
||||
super::sampler::serialize_compare_function(op)
|
||||
}),
|
||||
fail_op: state
|
||||
.fail_op
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::StencilOperation::Keep, |op| {
|
||||
serialize_stencil_operation(op)
|
||||
}),
|
||||
depth_fail_op: state
|
||||
.depth_fail_op
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::StencilOperation::Keep, |op| {
|
||||
serialize_stencil_operation(op)
|
||||
}),
|
||||
pass_op: state
|
||||
.pass_op
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::StencilOperation::Keep, |op| {
|
||||
serialize_stencil_operation(op)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_blend_factor(blend_factor: &str) -> wgpu_types::BlendFactor {
|
||||
match blend_factor {
|
||||
"zero" => wgpu_types::BlendFactor::Zero,
|
||||
"one" => wgpu_types::BlendFactor::One,
|
||||
"src-color" => wgpu_types::BlendFactor::SrcColor,
|
||||
"one-minus-src-color" => wgpu_types::BlendFactor::OneMinusSrcColor,
|
||||
"src-alpha" => wgpu_types::BlendFactor::SrcAlpha,
|
||||
"one-minus-src-alpha" => wgpu_types::BlendFactor::OneMinusSrcAlpha,
|
||||
"dst-color" => wgpu_types::BlendFactor::DstColor,
|
||||
"one-minus-dst-color" => wgpu_types::BlendFactor::OneMinusDstColor,
|
||||
"dst-alpha" => wgpu_types::BlendFactor::DstAlpha,
|
||||
"one-minus-dst-alpha" => wgpu_types::BlendFactor::OneMinusDstAlpha,
|
||||
"src-alpha-saturated" => wgpu_types::BlendFactor::SrcAlphaSaturated,
|
||||
"blend-color" => wgpu_types::BlendFactor::BlendColor,
|
||||
"one-minus-blend-color" => wgpu_types::BlendFactor::OneMinusBlendColor,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_blend_component(
|
||||
blend: GPUBlendComponent,
|
||||
) -> wgpu_types::BlendState {
|
||||
wgpu_types::BlendState {
|
||||
src_factor: blend
|
||||
.src_factor
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::BlendFactor::One, |factor| {
|
||||
serialize_blend_factor(factor)
|
||||
}),
|
||||
dst_factor: blend
|
||||
.dst_factor
|
||||
.as_ref()
|
||||
.map_or(wgpu_types::BlendFactor::Zero, |factor| {
|
||||
serialize_blend_factor(factor)
|
||||
}),
|
||||
operation: match &blend.operation {
|
||||
Some(operation) => match operation.as_str() {
|
||||
"add" => wgpu_types::BlendOperation::Add,
|
||||
"subtract" => wgpu_types::BlendOperation::Subtract,
|
||||
"reverse-subtract" => wgpu_types::BlendOperation::ReverseSubtract,
|
||||
"min" => wgpu_types::BlendOperation::Min,
|
||||
"max" => wgpu_types::BlendOperation::Max,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::BlendOperation::Add,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUProgrammableStage {
|
||||
module: u32,
|
||||
entry_point: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateComputePipelineArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
layout: Option<u32>,
|
||||
compute: GPUProgrammableStage,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_compute_pipeline(
|
||||
state: &mut OpState,
|
||||
args: CreateComputePipelineArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let pipeline_layout = if let Some(rid) = args.layout {
|
||||
let id = state
|
||||
.resource_table
|
||||
.get::<WebGPUPipelineLayout>(rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
Some(id.0)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let compute_shader_module_resource = state
|
||||
.resource_table
|
||||
.get::<super::shader::WebGPUShaderModule>(args.compute.module)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
layout: pipeline_layout,
|
||||
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
|
||||
module: compute_shader_module_resource.0,
|
||||
entry_point: Cow::from(args.compute.entry_point),
|
||||
},
|
||||
};
|
||||
let implicit_pipelines = match args.layout {
|
||||
Some(_) => None,
|
||||
None => Some(wgpu_core::device::ImplicitPipelineIds {
|
||||
root_id: std::marker::PhantomData,
|
||||
group_ids: &[std::marker::PhantomData; wgpu_core::MAX_BIND_GROUPS],
|
||||
}),
|
||||
};
|
||||
|
||||
let (compute_pipeline, _, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData,
|
||||
implicit_pipelines
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPUComputePipeline(compute_pipeline));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from),
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ComputePipelineGetBindGroupLayoutArgs {
|
||||
compute_pipeline_rid: u32,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_compute_pipeline_get_bind_group_layout(
|
||||
state: &mut OpState,
|
||||
args: ComputePipelineGetBindGroupLayoutArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let compute_pipeline_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUComputePipeline>(args.compute_pipeline_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let compute_pipeline = compute_pipeline_resource.0;
|
||||
|
||||
let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, args.index, std::marker::PhantomData));
|
||||
|
||||
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(super::binding::WebGPUBindGroupLayout(bind_group_layout));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"label": label,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUPrimitiveState {
|
||||
topology: Option<String>,
|
||||
strip_index_format: Option<String>,
|
||||
front_face: Option<String>,
|
||||
cull_mode: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUBlendComponent {
|
||||
src_factor: Option<String>,
|
||||
dst_factor: Option<String>,
|
||||
operation: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUBlendState {
|
||||
color: GPUBlendComponent,
|
||||
alpha: GPUBlendComponent,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUColorTargetState {
|
||||
format: String,
|
||||
blend: Option<GPUBlendState>,
|
||||
write_mask: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUStencilFaceState {
|
||||
compare: Option<String>,
|
||||
fail_op: Option<String>,
|
||||
depth_fail_op: Option<String>,
|
||||
pass_op: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUDepthStencilState {
|
||||
format: String,
|
||||
depth_write_enabled: Option<bool>,
|
||||
depth_compare: Option<String>,
|
||||
stencil_front: Option<GPUStencilFaceState>,
|
||||
stencil_back: Option<GPUStencilFaceState>,
|
||||
stencil_read_mask: Option<u32>,
|
||||
stencil_write_mask: Option<u32>,
|
||||
depth_bias: Option<i32>,
|
||||
depth_bias_slope_scale: Option<f32>,
|
||||
depth_bias_clamp: Option<f32>,
|
||||
clamp_depth: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUVertexAttribute {
|
||||
format: String,
|
||||
offset: u64,
|
||||
shader_location: u32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUVertexBufferLayout {
|
||||
array_stride: u64,
|
||||
step_mode: Option<String>,
|
||||
attributes: Vec<GPUVertexAttribute>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUVertexState {
|
||||
module: u32,
|
||||
entry_point: String,
|
||||
buffers: Option<Vec<Option<GPUVertexBufferLayout>>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUMultisampleState {
|
||||
count: Option<u32>,
|
||||
mask: Option<u64>, // against spec, but future proof
|
||||
alpha_to_coverage_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUFragmentState {
|
||||
targets: Vec<GPUColorTargetState>,
|
||||
module: u32,
|
||||
entry_point: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateRenderPipelineArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
layout: Option<u32>,
|
||||
vertex: GPUVertexState,
|
||||
primitive: Option<GPUPrimitiveState>,
|
||||
depth_stencil: Option<GPUDepthStencilState>,
|
||||
multisample: Option<GPUMultisampleState>,
|
||||
fragment: Option<GPUFragmentState>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_render_pipeline(
|
||||
state: &mut OpState,
|
||||
args: CreateRenderPipelineArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let layout = if let Some(rid) = args.layout {
|
||||
let pipeline_layout_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUPipelineLayout>(rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
Some(pipeline_layout_resource.0)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let vertex_shader_module_resource = state
|
||||
.resource_table
|
||||
.get::<super::shader::WebGPUShaderModule>(args.vertex.module)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
layout,
|
||||
vertex: wgpu_core::pipeline::VertexState {
|
||||
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
|
||||
module: vertex_shader_module_resource.0,
|
||||
entry_point: Cow::from(args.vertex.entry_point),
|
||||
},
|
||||
buffers: Cow::from(if let Some(buffers) = args.vertex.buffers {
|
||||
let mut return_buffers = vec![];
|
||||
for buffer in buffers {
|
||||
if let Some(buffer) = buffer {
|
||||
return_buffers.push(wgpu_core::pipeline::VertexBufferLayout {
|
||||
array_stride: buffer.array_stride,
|
||||
step_mode: match buffer.step_mode {
|
||||
Some(step_mode) => match step_mode.as_str() {
|
||||
"vertex" => wgpu_types::InputStepMode::Vertex,
|
||||
"instance" => wgpu_types::InputStepMode::Instance,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::InputStepMode::Vertex,
|
||||
},
|
||||
attributes: Cow::from(
|
||||
buffer
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|attribute| wgpu_types::VertexAttribute {
|
||||
format: match attribute.format.as_str() {
|
||||
"uchar2" => wgpu_types::VertexFormat::Uchar2,
|
||||
"uchar4" => wgpu_types::VertexFormat::Uchar4,
|
||||
"char2" => wgpu_types::VertexFormat::Char2,
|
||||
"char4" => wgpu_types::VertexFormat::Char4,
|
||||
"uchar2norm" => wgpu_types::VertexFormat::Uchar2Norm,
|
||||
"uchar4norm" => wgpu_types::VertexFormat::Uchar4,
|
||||
"char2norm" => wgpu_types::VertexFormat::Char2Norm,
|
||||
"char4norm" => wgpu_types::VertexFormat::Char4Norm,
|
||||
"ushort2" => wgpu_types::VertexFormat::Ushort2,
|
||||
"ushort4" => wgpu_types::VertexFormat::Ushort4,
|
||||
"short2" => wgpu_types::VertexFormat::Short2,
|
||||
"short4" => wgpu_types::VertexFormat::Short4,
|
||||
"ushort2norm" => wgpu_types::VertexFormat::Ushort2Norm,
|
||||
"ushort4norm" => wgpu_types::VertexFormat::Ushort4Norm,
|
||||
"short2norm" => wgpu_types::VertexFormat::Short2Norm,
|
||||
"short4norm" => wgpu_types::VertexFormat::Short4Norm,
|
||||
"half2" => wgpu_types::VertexFormat::Half2,
|
||||
"half4" => wgpu_types::VertexFormat::Half4,
|
||||
"float" => wgpu_types::VertexFormat::Float,
|
||||
"float2" => wgpu_types::VertexFormat::Float2,
|
||||
"float3" => wgpu_types::VertexFormat::Float3,
|
||||
"float4" => wgpu_types::VertexFormat::Float4,
|
||||
"uint" => wgpu_types::VertexFormat::Uint,
|
||||
"uint2" => wgpu_types::VertexFormat::Uint2,
|
||||
"uint3" => wgpu_types::VertexFormat::Uint3,
|
||||
"uint4" => wgpu_types::VertexFormat::Uint4,
|
||||
"int" => wgpu_types::VertexFormat::Int,
|
||||
"int2" => wgpu_types::VertexFormat::Int2,
|
||||
"int3" => wgpu_types::VertexFormat::Int3,
|
||||
"int4" => wgpu_types::VertexFormat::Int4,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
offset: attribute.offset,
|
||||
shader_location: attribute.shader_location,
|
||||
})
|
||||
.collect::<Vec<wgpu_types::VertexAttribute>>(),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
return_buffers
|
||||
} else {
|
||||
vec![]
|
||||
}),
|
||||
},
|
||||
primitive: args.primitive.map_or(Default::default(), |primitive| {
|
||||
wgpu_types::PrimitiveState {
|
||||
topology: match primitive.topology {
|
||||
Some(topology) => match topology.as_str() {
|
||||
"point-list" => wgpu_types::PrimitiveTopology::PointList,
|
||||
"line-list" => wgpu_types::PrimitiveTopology::LineList,
|
||||
"line-strip" => wgpu_types::PrimitiveTopology::LineStrip,
|
||||
"triangle-list" => wgpu_types::PrimitiveTopology::TriangleList,
|
||||
"triangle-strip" => wgpu_types::PrimitiveTopology::TriangleStrip,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::PrimitiveTopology::TriangleList,
|
||||
},
|
||||
strip_index_format: primitive
|
||||
.strip_index_format
|
||||
.map(serialize_index_format),
|
||||
front_face: match primitive.front_face {
|
||||
Some(front_face) => match front_face.as_str() {
|
||||
"ccw" => wgpu_types::FrontFace::Ccw,
|
||||
"cw" => wgpu_types::FrontFace::Cw,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::FrontFace::Ccw,
|
||||
},
|
||||
cull_mode: match primitive.cull_mode {
|
||||
Some(cull_mode) => match cull_mode.as_str() {
|
||||
"none" => wgpu_types::CullMode::None,
|
||||
"front" => wgpu_types::CullMode::Front,
|
||||
"back" => wgpu_types::CullMode::Back,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::CullMode::None,
|
||||
},
|
||||
polygon_mode: Default::default(), // native-only
|
||||
}
|
||||
}),
|
||||
depth_stencil: args.depth_stencil.map(|depth_stencil| {
|
||||
wgpu_types::DepthStencilState {
|
||||
format: super::texture::serialize_texture_format(&depth_stencil.format)
|
||||
.unwrap(),
|
||||
depth_write_enabled: depth_stencil.depth_write_enabled.unwrap_or(false),
|
||||
depth_compare: match depth_stencil.depth_compare {
|
||||
Some(depth_compare) => {
|
||||
super::sampler::serialize_compare_function(&depth_compare)
|
||||
}
|
||||
None => wgpu_types::CompareFunction::Always,
|
||||
},
|
||||
stencil: wgpu_types::StencilState {
|
||||
front: depth_stencil
|
||||
.stencil_front
|
||||
.map_or(Default::default(), serialize_stencil_face_state),
|
||||
back: depth_stencil
|
||||
.stencil_back
|
||||
.map_or(Default::default(), serialize_stencil_face_state),
|
||||
read_mask: depth_stencil.stencil_read_mask.unwrap_or(0xFFFFFFFF),
|
||||
write_mask: depth_stencil.stencil_write_mask.unwrap_or(0xFFFFFFFF),
|
||||
},
|
||||
bias: wgpu_types::DepthBiasState {
|
||||
constant: depth_stencil.depth_bias.unwrap_or(0),
|
||||
slope_scale: depth_stencil.depth_bias_slope_scale.unwrap_or(0.0),
|
||||
clamp: depth_stencil.depth_bias_clamp.unwrap_or(0.0),
|
||||
},
|
||||
clamp_depth: depth_stencil.clamp_depth.unwrap_or(false),
|
||||
}
|
||||
}),
|
||||
multisample: args.multisample.map_or(Default::default(), |multisample| {
|
||||
wgpu_types::MultisampleState {
|
||||
count: multisample.count.unwrap_or(1),
|
||||
mask: multisample.mask.unwrap_or(0xFFFFFFFF),
|
||||
alpha_to_coverage_enabled: multisample
|
||||
.alpha_to_coverage_enabled
|
||||
.unwrap_or(false),
|
||||
}
|
||||
}),
|
||||
fragment: args.fragment.map(|fragment| {
|
||||
let fragment_shader_module_resource = state
|
||||
.resource_table
|
||||
.get::<super::shader::WebGPUShaderModule>(fragment.module)
|
||||
.ok_or_else(bad_resource_id)
|
||||
.unwrap();
|
||||
|
||||
wgpu_core::pipeline::FragmentState {
|
||||
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
|
||||
module: fragment_shader_module_resource.0,
|
||||
entry_point: Cow::from(fragment.entry_point),
|
||||
},
|
||||
targets: Cow::from(
|
||||
fragment
|
||||
.targets
|
||||
.iter()
|
||||
.map(|target| {
|
||||
let blends = target.blend.clone().map(|blend| {
|
||||
(
|
||||
serialize_blend_component(blend.alpha),
|
||||
serialize_blend_component(blend.color),
|
||||
)
|
||||
});
|
||||
|
||||
wgpu_types::ColorTargetState {
|
||||
format: super::texture::serialize_texture_format(
|
||||
&target.format,
|
||||
)
|
||||
.unwrap(),
|
||||
alpha_blend: blends
|
||||
.clone()
|
||||
.map_or(Default::default(), |states| states.0),
|
||||
color_blend: blends
|
||||
.map_or(Default::default(), |states| states.1),
|
||||
write_mask: target
|
||||
.write_mask
|
||||
.map_or(Default::default(), |mask| {
|
||||
wgpu_types::ColorWrite::from_bits(mask).unwrap()
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<wgpu_types::ColorTargetState>>(),
|
||||
),
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let implicit_pipelines = match args.layout {
|
||||
Some(_) => None,
|
||||
None => Some(wgpu_core::device::ImplicitPipelineIds {
|
||||
root_id: std::marker::PhantomData,
|
||||
group_ids: &[std::marker::PhantomData; wgpu_core::MAX_BIND_GROUPS],
|
||||
}),
|
||||
};
|
||||
|
||||
let (render_pipeline, _, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData,
|
||||
implicit_pipelines
|
||||
));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(WebGPURenderPipeline(render_pipeline));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPipelineGetBindGroupLayoutArgs {
|
||||
render_pipeline_rid: u32,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pipeline_get_bind_group_layout(
|
||||
state: &mut OpState,
|
||||
args: RenderPipelineGetBindGroupLayoutArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let render_pipeline_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPipeline>(args.render_pipeline_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pipeline = render_pipeline_resource.0;
|
||||
|
||||
let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, args.index, std::marker::PhantomData));
|
||||
|
||||
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
|
||||
|
||||
let rid = state
|
||||
.resource_table
|
||||
.add(super::binding::WebGPUBindGroupLayout(bind_group_layout));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"label": label,
|
||||
"err": maybe_err.map(WebGPUError::from),
|
||||
}))
|
||||
}
|
157
op_crates/webgpu/queue.rs
Normal file
157
op_crates/webgpu/queue.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
type WebGPUQueue = super::WebGPUDevice;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct QueueSubmitArgs {
|
||||
queue_rid: u32,
|
||||
command_buffers: Vec<u32>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_queue_submit(
|
||||
state: &mut OpState,
|
||||
args: QueueSubmitArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let queue_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUQueue>(args.queue_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let queue = queue_resource.0;
|
||||
|
||||
let mut ids = vec![];
|
||||
|
||||
for rid in args.command_buffers {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::command_encoder::WebGPUCommandBuffer>(rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
ids.push(buffer_resource.0);
|
||||
}
|
||||
|
||||
let maybe_err =
|
||||
gfx_select!(queue => instance.queue_submit(queue, &ids)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct GPUImageDataLayout {
|
||||
offset: Option<u64>,
|
||||
bytes_per_row: Option<u32>,
|
||||
rows_per_image: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct QueueWriteBufferArgs {
|
||||
queue_rid: u32,
|
||||
buffer: u32,
|
||||
buffer_offset: u64,
|
||||
data_offset: usize,
|
||||
size: Option<usize>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_write_buffer(
|
||||
state: &mut OpState,
|
||||
args: QueueWriteBufferArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let buffer = buffer_resource.0;
|
||||
let queue_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUQueue>(args.queue_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let queue = queue_resource.0;
|
||||
|
||||
let data = match args.size {
|
||||
Some(size) => &zero_copy[0][args.data_offset..(args.data_offset + size)],
|
||||
None => &zero_copy[0][args.data_offset..],
|
||||
};
|
||||
let maybe_err = gfx_select!(queue => instance.queue_write_buffer(
|
||||
queue,
|
||||
buffer,
|
||||
args.buffer_offset,
|
||||
data
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct QueueWriteTextureArgs {
|
||||
queue_rid: u32,
|
||||
destination: super::command_encoder::GPUImageCopyTexture,
|
||||
data_layout: GPUImageDataLayout,
|
||||
size: super::texture::GPUExtent3D,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_write_texture(
|
||||
state: &mut OpState,
|
||||
args: QueueWriteTextureArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let texture_resource = state
|
||||
.resource_table
|
||||
.get::<super::texture::WebGPUTexture>(args.destination.texture)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let queue_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUQueue>(args.queue_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let queue = queue_resource.0;
|
||||
|
||||
let destination = wgpu_core::command::TextureCopyView {
|
||||
texture: texture_resource.0,
|
||||
mip_level: args.destination.mip_level.unwrap_or(0),
|
||||
origin: args
|
||||
.destination
|
||||
.origin
|
||||
.map_or(Default::default(), |origin| wgpu_types::Origin3d {
|
||||
x: origin.x.unwrap_or(0),
|
||||
y: origin.y.unwrap_or(0),
|
||||
z: origin.z.unwrap_or(0),
|
||||
}),
|
||||
};
|
||||
let data_layout = wgpu_types::TextureDataLayout {
|
||||
offset: args.data_layout.offset.unwrap_or(0),
|
||||
bytes_per_row: args.data_layout.bytes_per_row.unwrap_or(0),
|
||||
rows_per_image: args.data_layout.rows_per_image.unwrap_or(0),
|
||||
};
|
||||
|
||||
let maybe_err = gfx_select!(queue => instance.queue_write_texture(
|
||||
queue,
|
||||
&destination,
|
||||
&*zero_copy[0],
|
||||
&data_layout,
|
||||
&wgpu_types::Extent3d {
|
||||
width: args.size.width.unwrap_or(1),
|
||||
height: args.size.height.unwrap_or(1),
|
||||
depth: args.size.depth.unwrap_or(1),
|
||||
}
|
||||
))
|
||||
.err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
676
op_crates/webgpu/render_pass.rs
Normal file
676
op_crates/webgpu/render_pass.rs
Normal file
|
@ -0,0 +1,676 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPURenderPass(
|
||||
pub(crate) RefCell<wgpu_core::command::RenderPass>,
|
||||
);
|
||||
impl Resource for WebGPURenderPass {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPURenderPass".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetViewportArgs {
|
||||
render_pass_rid: u32,
|
||||
x: f32,
|
||||
y: f32,
|
||||
width: f32,
|
||||
height: f32,
|
||||
min_depth: f32,
|
||||
max_depth: f32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_viewport(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetViewportArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_viewport(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.x,
|
||||
args.y,
|
||||
args.width,
|
||||
args.height,
|
||||
args.min_depth,
|
||||
args.max_depth,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetScissorRectArgs {
|
||||
render_pass_rid: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_scissor_rect(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetScissorRectArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_scissor_rect(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.x,
|
||||
args.y,
|
||||
args.width,
|
||||
args.height,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPUColor {
|
||||
pub r: f64,
|
||||
pub g: f64,
|
||||
pub b: f64,
|
||||
pub a: f64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetBlendColorArgs {
|
||||
render_pass_rid: u32,
|
||||
color: GPUColor,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_blend_color(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetBlendColorArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_color(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
&wgpu_types::Color {
|
||||
r: args.color.r,
|
||||
g: args.color.g,
|
||||
b: args.color.b,
|
||||
a: args.color.a,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetStencilReferenceArgs {
|
||||
render_pass_rid: u32,
|
||||
reference: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_stencil_reference(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetStencilReferenceArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_stencil_reference(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.reference,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassBeginPipelineStatisticsQueryArgs {
|
||||
render_pass_rid: u32,
|
||||
query_set: u32,
|
||||
query_index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_begin_pipeline_statistics_query(
|
||||
state: &mut OpState,
|
||||
args: RenderPassBeginPipelineStatisticsQueryArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
query_set_resource.0,
|
||||
args.query_index,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassEndPipelineStatisticsQueryArgs {
|
||||
render_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_end_pipeline_statistics_query(
|
||||
state: &mut OpState,
|
||||
args: RenderPassEndPipelineStatisticsQueryArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassWriteTimestampArgs {
|
||||
render_pass_rid: u32,
|
||||
query_set: u32,
|
||||
query_index: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_write_timestamp(
|
||||
state: &mut OpState,
|
||||
args: RenderPassWriteTimestampArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let query_set_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUQuerySet>(args.query_set)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_write_timestamp(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
query_set_resource.0,
|
||||
args.query_index,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassExecuteBundlesArgs {
|
||||
render_pass_rid: u32,
|
||||
bundles: Vec<u32>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_execute_bundles(
|
||||
state: &mut OpState,
|
||||
args: RenderPassExecuteBundlesArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let mut render_bundle_ids = vec![];
|
||||
|
||||
for rid in &args.bundles {
|
||||
let render_bundle_resource = state
|
||||
.resource_table
|
||||
.get::<super::bundle::WebGPURenderBundle>(*rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
render_bundle_ids.push(render_bundle_resource.0);
|
||||
}
|
||||
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_execute_bundles(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
render_bundle_ids.as_ptr(),
|
||||
args.bundles.len(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassEndPassArgs {
|
||||
command_encoder_rid: u32,
|
||||
render_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_end_pass(
|
||||
state: &mut OpState,
|
||||
args: RenderPassEndPassArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let command_encoder_resource = state
|
||||
.resource_table
|
||||
.get::<super::command_encoder::WebGPUCommandEncoder>(
|
||||
args.command_encoder_rid,
|
||||
)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let command_encoder = command_encoder_resource.0;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.take::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass = &render_pass_resource.0.borrow();
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
|
||||
let maybe_err = gfx_select!(command_encoder => instance.command_encoder_run_render_pass(command_encoder, render_pass)).err();
|
||||
|
||||
Ok(json!({ "err": maybe_err.map(WebGPUError::from) }))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetBindGroupArgs {
|
||||
render_pass_rid: u32,
|
||||
index: u32,
|
||||
bind_group: u32,
|
||||
dynamic_offsets_data: Option<Vec<u32>>,
|
||||
dynamic_offsets_data_start: usize,
|
||||
dynamic_offsets_data_length: usize,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_bind_group(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetBindGroupArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let bind_group_resource = state
|
||||
.resource_table
|
||||
.get::<super::binding::WebGPUBindGroup>(args.bind_group)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
// I know this might look like it can be easily deduplicated, but it can not
|
||||
// be due to the lifetime of the args.dynamic_offsets_data slice. Because we
|
||||
// need to use a raw pointer here the slice can be freed before the pointer
|
||||
// is used in wgpu_render_pass_set_bind_group. See
|
||||
// https://matrix.to/#/!XFRnMvAfptAHthwBCx:matrix.org/$HgrlhD-Me1DwsGb8UdMu2Hqubgks8s7ILwWRwigOUAg
|
||||
match args.dynamic_offsets_data {
|
||||
Some(data) => unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.index,
|
||||
bind_group_resource.0,
|
||||
data.as_slice().as_ptr(),
|
||||
args.dynamic_offsets_data_length,
|
||||
);
|
||||
},
|
||||
None => {
|
||||
let (prefix, data, suffix) = unsafe { zero_copy[0].align_to::<u32>() };
|
||||
assert!(prefix.is_empty());
|
||||
assert!(suffix.is_empty());
|
||||
unsafe {
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_bind_group(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.index,
|
||||
bind_group_resource.0,
|
||||
data[args.dynamic_offsets_data_start..].as_ptr(),
|
||||
args.dynamic_offsets_data_length,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassPushDebugGroupArgs {
|
||||
render_pass_rid: u32,
|
||||
group_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_push_debug_group(
|
||||
state: &mut OpState,
|
||||
args: RenderPassPushDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.group_label).unwrap();
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_push_debug_group(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
0, // wgpu#975
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassPopDebugGroupArgs {
|
||||
render_pass_rid: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_pop_debug_group(
|
||||
state: &mut OpState,
|
||||
args: RenderPassPopDebugGroupArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_pop_debug_group(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassInsertDebugMarkerArgs {
|
||||
render_pass_rid: u32,
|
||||
marker_label: String,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_insert_debug_marker(
|
||||
state: &mut OpState,
|
||||
args: RenderPassInsertDebugMarkerArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
unsafe {
|
||||
let label = std::ffi::CString::new(args.marker_label).unwrap();
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_insert_debug_marker(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
label.as_ptr(),
|
||||
0, // wgpu#975
|
||||
);
|
||||
}
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetPipelineArgs {
|
||||
render_pass_rid: u32,
|
||||
pipeline: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_pipeline(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetPipelineArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pipeline_resource = state
|
||||
.resource_table
|
||||
.get::<super::pipeline::WebGPURenderPipeline>(args.pipeline)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_pipeline(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
render_pipeline_resource.0,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetIndexBufferArgs {
|
||||
render_pass_rid: u32,
|
||||
buffer: u32,
|
||||
index_format: String,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_index_buffer(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetIndexBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
render_pass_resource.0.borrow_mut().set_index_buffer(
|
||||
buffer_resource.0,
|
||||
super::pipeline::serialize_index_format(args.index_format),
|
||||
args.offset,
|
||||
std::num::NonZeroU64::new(args.size),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassSetVertexBufferArgs {
|
||||
render_pass_rid: u32,
|
||||
slot: u32,
|
||||
buffer: u32,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_set_vertex_buffer(
|
||||
state: &mut OpState,
|
||||
args: RenderPassSetVertexBufferArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_set_vertex_buffer(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.slot,
|
||||
buffer_resource.0,
|
||||
args.offset,
|
||||
std::num::NonZeroU64::new(args.size),
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassDrawArgs {
|
||||
render_pass_rid: u32,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_draw(
|
||||
state: &mut OpState,
|
||||
args: RenderPassDrawArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_draw(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.vertex_count,
|
||||
args.instance_count,
|
||||
args.first_vertex,
|
||||
args.first_instance,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassDrawIndexedArgs {
|
||||
render_pass_rid: u32,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_draw_indexed(
|
||||
state: &mut OpState,
|
||||
args: RenderPassDrawIndexedArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
args.index_count,
|
||||
args.instance_count,
|
||||
args.first_index,
|
||||
args.base_vertex,
|
||||
args.first_instance,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassDrawIndirectArgs {
|
||||
render_pass_rid: u32,
|
||||
indirect_buffer: u32,
|
||||
indirect_offset: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_draw_indirect(
|
||||
state: &mut OpState,
|
||||
args: RenderPassDrawIndirectArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.indirect_buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_draw_indirect(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
buffer_resource.0,
|
||||
args.indirect_offset,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RenderPassDrawIndexedIndirectArgs {
|
||||
render_pass_rid: u32,
|
||||
indirect_buffer: u32,
|
||||
indirect_offset: u64,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_render_pass_draw_indexed_indirect(
|
||||
state: &mut OpState,
|
||||
args: RenderPassDrawIndexedIndirectArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let buffer_resource = state
|
||||
.resource_table
|
||||
.get::<super::buffer::WebGPUBuffer>(args.indirect_buffer)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let render_pass_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPURenderPass>(args.render_pass_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
wgpu_core::command::render_ffi::wgpu_render_pass_draw_indexed_indirect(
|
||||
&mut render_pass_resource.0.borrow_mut(),
|
||||
buffer_resource.0,
|
||||
args.indirect_offset,
|
||||
);
|
||||
|
||||
Ok(json!({}))
|
||||
}
|
129
op_crates/webgpu/sampler.rs
Normal file
129
op_crates/webgpu/sampler.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUSampler(pub(crate) wgpu_core::id::SamplerId);
|
||||
impl Resource for WebGPUSampler {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUSampler".into()
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_address_mode(
|
||||
address_mode: Option<String>,
|
||||
) -> wgpu_types::AddressMode {
|
||||
match address_mode {
|
||||
Some(address_mode) => match address_mode.as_str() {
|
||||
"clamp-to-edge" => wgpu_types::AddressMode::ClampToEdge,
|
||||
"repeat" => wgpu_types::AddressMode::Repeat,
|
||||
"mirror-repeat" => wgpu_types::AddressMode::MirrorRepeat,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::AddressMode::ClampToEdge,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_filter_mode(
|
||||
filter_mode: Option<String>,
|
||||
) -> wgpu_types::FilterMode {
|
||||
match filter_mode {
|
||||
Some(filter_mode) => match filter_mode.as_str() {
|
||||
"nearest" => wgpu_types::FilterMode::Nearest,
|
||||
"linear" => wgpu_types::FilterMode::Linear,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::FilterMode::Nearest,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_compare_function(
|
||||
compare: &str,
|
||||
) -> wgpu_types::CompareFunction {
|
||||
match compare {
|
||||
"never" => wgpu_types::CompareFunction::Never,
|
||||
"less" => wgpu_types::CompareFunction::Less,
|
||||
"equal" => wgpu_types::CompareFunction::Equal,
|
||||
"less-equal" => wgpu_types::CompareFunction::LessEqual,
|
||||
"greater" => wgpu_types::CompareFunction::Greater,
|
||||
"not-equal" => wgpu_types::CompareFunction::NotEqual,
|
||||
"greater-equal" => wgpu_types::CompareFunction::GreaterEqual,
|
||||
"always" => wgpu_types::CompareFunction::Always,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSamplerArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
address_mode_u: Option<String>,
|
||||
address_mode_v: Option<String>,
|
||||
address_mode_w: Option<String>,
|
||||
mag_filter: Option<String>,
|
||||
min_filter: Option<String>,
|
||||
mipmap_filter: Option<String>,
|
||||
lod_min_clamp: Option<f32>,
|
||||
lod_max_clamp: Option<f32>,
|
||||
compare: Option<String>,
|
||||
max_anisotropy: Option<u8>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_sampler(
|
||||
state: &mut OpState,
|
||||
args: CreateSamplerArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let descriptor = wgpu_core::resource::SamplerDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
address_modes: [
|
||||
serialize_address_mode(args.address_mode_u),
|
||||
serialize_address_mode(args.address_mode_v),
|
||||
serialize_address_mode(args.address_mode_w),
|
||||
],
|
||||
mag_filter: serialize_filter_mode(args.mag_filter),
|
||||
min_filter: serialize_filter_mode(args.min_filter),
|
||||
mipmap_filter: serialize_filter_mode(args.mipmap_filter),
|
||||
lod_min_clamp: args.lod_min_clamp.unwrap_or(0.0),
|
||||
lod_max_clamp: args.lod_max_clamp.unwrap_or(
|
||||
wgpu_core::resource::SamplerDescriptor::default().lod_max_clamp,
|
||||
),
|
||||
compare: args
|
||||
.compare
|
||||
.as_ref()
|
||||
.map(|compare| serialize_compare_function(compare)),
|
||||
anisotropy_clamp: std::num::NonZeroU8::new(
|
||||
args.max_anisotropy.unwrap_or(0),
|
||||
),
|
||||
border_color: None, // native-only
|
||||
};
|
||||
|
||||
let (sampler, maybe_err) = gfx_select!(device => instance.device_create_sampler(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUSampler(sampler));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
77
op_crates/webgpu/shader.rs
Normal file
77
op_crates/webgpu/shader.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
|
||||
pub(crate) struct WebGPUShaderModule(pub(crate) wgpu_core::id::ShaderModuleId);
|
||||
impl Resource for WebGPUShaderModule {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUShaderModule".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateShaderModuleArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
code: Option<String>,
|
||||
_source_map: Option<()>, // not yet implemented
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_shader_module(
|
||||
state: &mut OpState,
|
||||
args: CreateShaderModuleArgs,
|
||||
zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let source = match args.code {
|
||||
Some(code) => {
|
||||
wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::from(code))
|
||||
}
|
||||
None => wgpu_core::pipeline::ShaderModuleSource::SpirV(Cow::from(unsafe {
|
||||
let (prefix, data, suffix) = zero_copy[0].align_to::<u32>();
|
||||
assert!(prefix.is_empty());
|
||||
assert!(suffix.is_empty());
|
||||
data
|
||||
})),
|
||||
};
|
||||
|
||||
let mut flags = wgpu_types::ShaderFlags::default();
|
||||
flags.set(wgpu_types::ShaderFlags::VALIDATION, true);
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
flags.set(wgpu_types::ShaderFlags::EXPERIMENTAL_TRANSLATION, true);
|
||||
|
||||
let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
flags,
|
||||
};
|
||||
|
||||
let (shader_module, maybe_err) = gfx_select!(device => instance.device_create_shader_module(
|
||||
device,
|
||||
&descriptor,
|
||||
source,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUShaderModule(shader_module));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
256
op_crates/webgpu/texture.rs
Normal file
256
op_crates/webgpu/texture.rs
Normal file
|
@ -0,0 +1,256 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::{bad_resource_id, not_supported};
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use deno_core::{OpState, Resource};
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::error::WebGPUError;
|
||||
pub(crate) struct WebGPUTexture(pub(crate) wgpu_core::id::TextureId);
|
||||
impl Resource for WebGPUTexture {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUTexture".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WebGPUTextureView(pub(crate) wgpu_core::id::TextureViewId);
|
||||
impl Resource for WebGPUTextureView {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"webGPUTextureView".into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_texture_format(
|
||||
format: &str,
|
||||
) -> Result<wgpu_types::TextureFormat, AnyError> {
|
||||
Ok(match format {
|
||||
// 8-bit formats
|
||||
"r8unorm" => wgpu_types::TextureFormat::R8Unorm,
|
||||
"r8snorm" => wgpu_types::TextureFormat::R8Snorm,
|
||||
"r8uint" => wgpu_types::TextureFormat::R8Uint,
|
||||
"r8sint" => wgpu_types::TextureFormat::R8Sint,
|
||||
|
||||
// 16-bit formats
|
||||
"r16uint" => wgpu_types::TextureFormat::R16Uint,
|
||||
"r16sint" => wgpu_types::TextureFormat::R16Sint,
|
||||
"r16float" => wgpu_types::TextureFormat::R16Float,
|
||||
"rg8unorm" => wgpu_types::TextureFormat::Rg8Unorm,
|
||||
"rg8snorm" => wgpu_types::TextureFormat::Rg8Snorm,
|
||||
"rg8uint" => wgpu_types::TextureFormat::Rg8Uint,
|
||||
"rg8sint" => wgpu_types::TextureFormat::Rg8Sint,
|
||||
|
||||
// 32-bit formats
|
||||
"r32uint" => wgpu_types::TextureFormat::R32Uint,
|
||||
"r32sint" => wgpu_types::TextureFormat::R32Sint,
|
||||
"r32float" => wgpu_types::TextureFormat::R32Float,
|
||||
"rg16uint" => wgpu_types::TextureFormat::Rg16Uint,
|
||||
"rg16sint" => wgpu_types::TextureFormat::Rg16Sint,
|
||||
"rg16float" => wgpu_types::TextureFormat::Rg16Float,
|
||||
"rgba8unorm" => wgpu_types::TextureFormat::Rgba8Unorm,
|
||||
"rgba8unorm-srgb" => wgpu_types::TextureFormat::Rgba8UnormSrgb,
|
||||
"rgba8snorm" => wgpu_types::TextureFormat::Rgba8Snorm,
|
||||
"rgba8uint" => wgpu_types::TextureFormat::Rgba8Uint,
|
||||
"rgba8sint" => wgpu_types::TextureFormat::Rgba8Sint,
|
||||
"bgra8unorm" => wgpu_types::TextureFormat::Bgra8Unorm,
|
||||
"bgra8unorm-srgb" => wgpu_types::TextureFormat::Bgra8UnormSrgb,
|
||||
// Packed 32-bit formats
|
||||
"rgb9e5ufloat" => return Err(not_supported()), // wgpu#967
|
||||
"rgb10a2unorm" => wgpu_types::TextureFormat::Rgb10a2Unorm,
|
||||
"rg11b10ufloat" => wgpu_types::TextureFormat::Rg11b10Float,
|
||||
|
||||
// 64-bit formats
|
||||
"rg32uint" => wgpu_types::TextureFormat::Rg32Uint,
|
||||
"rg32sint" => wgpu_types::TextureFormat::Rg32Sint,
|
||||
"rg32float" => wgpu_types::TextureFormat::Rg32Float,
|
||||
"rgba16uint" => wgpu_types::TextureFormat::Rgba16Uint,
|
||||
"rgba16sint" => wgpu_types::TextureFormat::Rgba16Sint,
|
||||
"rgba16float" => wgpu_types::TextureFormat::Rgba16Float,
|
||||
|
||||
// 128-bit formats
|
||||
"rgba32uint" => wgpu_types::TextureFormat::Rgba32Uint,
|
||||
"rgba32sint" => wgpu_types::TextureFormat::Rgba32Sint,
|
||||
"rgba32float" => wgpu_types::TextureFormat::Rgba32Float,
|
||||
|
||||
// Depth and stencil formats
|
||||
"stencil8" => return Err(not_supported()), // wgpu#967
|
||||
"depth16unorm" => return Err(not_supported()), // wgpu#967
|
||||
"depth24plus" => wgpu_types::TextureFormat::Depth24Plus,
|
||||
"depth24plus-stencil8" => wgpu_types::TextureFormat::Depth24PlusStencil8,
|
||||
"depth32float" => wgpu_types::TextureFormat::Depth32Float,
|
||||
|
||||
// BC compressed formats usable if "texture-compression-bc" is both
|
||||
// supported by the device/user agent and enabled in requestDevice.
|
||||
"bc1-rgba-unorm" => wgpu_types::TextureFormat::Bc1RgbaUnorm,
|
||||
"bc1-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc1RgbaUnormSrgb,
|
||||
"bc2-rgba-unorm" => wgpu_types::TextureFormat::Bc2RgbaUnorm,
|
||||
"bc2-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc2RgbaUnormSrgb,
|
||||
"bc3-rgba-unorm" => wgpu_types::TextureFormat::Bc3RgbaUnorm,
|
||||
"bc3-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc3RgbaUnormSrgb,
|
||||
"bc4-r-unorm" => wgpu_types::TextureFormat::Bc4RUnorm,
|
||||
"bc4-r-snorm" => wgpu_types::TextureFormat::Bc4RSnorm,
|
||||
"bc5-rg-unorm" => wgpu_types::TextureFormat::Bc5RgUnorm,
|
||||
"bc5-rg-snorm" => wgpu_types::TextureFormat::Bc5RgSnorm,
|
||||
"bc6h-rgb-ufloat" => wgpu_types::TextureFormat::Bc6hRgbUfloat,
|
||||
"bc6h-rgb-float" => wgpu_types::TextureFormat::Bc6hRgbSfloat, // wgpu#967
|
||||
"bc7-rgba-unorm" => wgpu_types::TextureFormat::Bc7RgbaUnorm,
|
||||
"bc7-rgba-unorm-srgb" => wgpu_types::TextureFormat::Bc7RgbaUnormSrgb,
|
||||
|
||||
// "depth24unorm-stencil8" extension
|
||||
"depth24unorm-stencil8" => return Err(not_supported()), // wgpu#967
|
||||
|
||||
// "depth32float-stencil8" extension
|
||||
"depth32float-stencil8" => return Err(not_supported()), // wgpu#967
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn serialize_dimension(
|
||||
dimension: &str,
|
||||
) -> wgpu_types::TextureViewDimension {
|
||||
match dimension {
|
||||
"1d" => wgpu_types::TextureViewDimension::D1,
|
||||
"2d" => wgpu_types::TextureViewDimension::D2,
|
||||
"2d-array" => wgpu_types::TextureViewDimension::D2Array,
|
||||
"cube" => wgpu_types::TextureViewDimension::Cube,
|
||||
"cube-array" => wgpu_types::TextureViewDimension::CubeArray,
|
||||
"3d" => wgpu_types::TextureViewDimension::D3,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GPUExtent3D {
|
||||
pub width: Option<u32>,
|
||||
pub height: Option<u32>,
|
||||
pub depth: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateTextureArgs {
|
||||
device_rid: u32,
|
||||
label: Option<String>,
|
||||
size: GPUExtent3D,
|
||||
mip_level_count: Option<u32>,
|
||||
sample_count: Option<u32>,
|
||||
dimension: Option<String>,
|
||||
format: String,
|
||||
usage: u32,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_texture(
|
||||
state: &mut OpState,
|
||||
args: CreateTextureArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let device_resource = state
|
||||
.resource_table
|
||||
.get::<super::WebGPUDevice>(args.device_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let device = device_resource.0;
|
||||
|
||||
let descriptor = wgpu_core::resource::TextureDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
size: wgpu_types::Extent3d {
|
||||
width: args.size.width.unwrap_or(1),
|
||||
height: args.size.height.unwrap_or(1),
|
||||
depth: args.size.depth.unwrap_or(1),
|
||||
},
|
||||
mip_level_count: args.mip_level_count.unwrap_or(1),
|
||||
sample_count: args.sample_count.unwrap_or(1),
|
||||
dimension: match args.dimension {
|
||||
Some(dimension) => match dimension.as_str() {
|
||||
"1d" => wgpu_types::TextureDimension::D1,
|
||||
"2d" => wgpu_types::TextureDimension::D2,
|
||||
"3d" => wgpu_types::TextureDimension::D3,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::TextureDimension::D2,
|
||||
},
|
||||
format: serialize_texture_format(&args.format)?,
|
||||
usage: wgpu_types::TextureUsage::from_bits(args.usage).unwrap(),
|
||||
};
|
||||
|
||||
let (texture, maybe_err) = gfx_select!(device => instance.device_create_texture(
|
||||
device,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUTexture(texture));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateTextureViewArgs {
|
||||
texture_rid: u32,
|
||||
label: Option<String>,
|
||||
format: Option<String>,
|
||||
dimension: Option<String>,
|
||||
aspect: Option<String>,
|
||||
base_mip_level: Option<u32>,
|
||||
mip_level_count: Option<u32>,
|
||||
base_array_layer: Option<u32>,
|
||||
array_layer_count: Option<u32>,
|
||||
}
|
||||
|
||||
pub fn op_webgpu_create_texture_view(
|
||||
state: &mut OpState,
|
||||
args: CreateTextureViewArgs,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let instance = state.borrow::<super::Instance>();
|
||||
let texture_resource = state
|
||||
.resource_table
|
||||
.get::<WebGPUTexture>(args.texture_rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
let texture = texture_resource.0;
|
||||
|
||||
let descriptor = wgpu_core::resource::TextureViewDescriptor {
|
||||
label: args.label.map(Cow::from),
|
||||
format: args
|
||||
.format
|
||||
.map(|s| serialize_texture_format(&s))
|
||||
.transpose()?,
|
||||
dimension: args.dimension.map(|s| serialize_dimension(&s)),
|
||||
aspect: match args.aspect {
|
||||
Some(aspect) => match aspect.as_str() {
|
||||
"all" => wgpu_types::TextureAspect::All,
|
||||
"stencil-only" => wgpu_types::TextureAspect::StencilOnly,
|
||||
"depth-only" => wgpu_types::TextureAspect::DepthOnly,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => wgpu_types::TextureAspect::All,
|
||||
},
|
||||
base_mip_level: args.base_mip_level.unwrap_or(0),
|
||||
level_count: std::num::NonZeroU32::new(args.mip_level_count.unwrap_or(0)),
|
||||
base_array_layer: args.base_array_layer.unwrap_or(0),
|
||||
array_layer_count: std::num::NonZeroU32::new(
|
||||
args.array_layer_count.unwrap_or(0),
|
||||
),
|
||||
};
|
||||
|
||||
let (texture_view, maybe_err) = gfx_select!(texture => instance.texture_create_view(
|
||||
texture,
|
||||
&descriptor,
|
||||
std::marker::PhantomData
|
||||
));
|
||||
|
||||
let rid = state.resource_table.add(WebGPUTextureView(texture_view));
|
||||
|
||||
Ok(json!({
|
||||
"rid": rid,
|
||||
"err": maybe_err.map(WebGPUError::from)
|
||||
}))
|
||||
}
|
1023
op_crates/webgpu/webgpu.idl
Normal file
1023
op_crates/webgpu/webgpu.idl
Normal file
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,7 @@ deno_crypto = { path = "../op_crates/crypto", version = "0.13.0" }
|
|||
deno_fetch = { path = "../op_crates/fetch", version = "0.22.0" }
|
||||
deno_web = { path = "../op_crates/web", version = "0.30.0" }
|
||||
deno_websocket = { path = "../op_crates/websocket", version = "0.5.0" }
|
||||
deno_webgpu = { path = "../op_crates/webgpu", version = "0.1.0" }
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
winres = "0.1.11"
|
||||
|
@ -34,6 +35,7 @@ deno_crypto = { path = "../op_crates/crypto", version = "0.13.0" }
|
|||
deno_fetch = { path = "../op_crates/fetch", version = "0.22.0" }
|
||||
deno_web = { path = "../op_crates/web", version = "0.30.0" }
|
||||
deno_websocket = { path = "../op_crates/websocket", version = "0.5.0" }
|
||||
deno_webgpu = { path = "../op_crates/webgpu", version = "0.1.0" }
|
||||
|
||||
atty = "0.2.14"
|
||||
dlopen = "0.1.8"
|
||||
|
|
|
@ -17,6 +17,7 @@ fn create_snapshot(
|
|||
deno_fetch::init(&mut js_runtime);
|
||||
deno_websocket::init(&mut js_runtime);
|
||||
deno_crypto::init(&mut js_runtime);
|
||||
deno_webgpu::init(&mut js_runtime);
|
||||
// TODO(nayeemrmn): https://github.com/rust-lang/cargo/issues/3946 to get the
|
||||
// workspace root.
|
||||
let display_root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
|
||||
|
|
|
@ -151,6 +151,7 @@ fn get_nix_error_class(error: &nix::Error) -> &'static str {
|
|||
|
||||
pub fn get_error_class_name(e: &AnyError) -> Option<&'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::<dlopen::Error>()
|
||||
.map(get_dlopen_error_class)
|
||||
|
|
|
@ -27,6 +27,7 @@ delete Object.prototype.__proto__;
|
|||
const headers = window.__bootstrap.headers;
|
||||
const streams = window.__bootstrap.streams;
|
||||
const fileReader = window.__bootstrap.fileReader;
|
||||
const webgpu = window.__bootstrap.webgpu;
|
||||
const webSocket = window.__bootstrap.webSocket;
|
||||
const file = window.__bootstrap.file;
|
||||
const fetch = window.__bootstrap.fetch;
|
||||
|
@ -195,6 +196,11 @@ delete Object.prototype.__proto__;
|
|||
core.registerErrorClass("SyntaxError", SyntaxError);
|
||||
core.registerErrorClass("TypeError", TypeError);
|
||||
core.registerErrorClass("URIError", URIError);
|
||||
core.registerErrorClass(
|
||||
"DOMExceptionOperationError",
|
||||
DOMException,
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
|
||||
|
@ -249,6 +255,37 @@ delete Object.prototype.__proto__;
|
|||
performance: util.writable(performance.performance),
|
||||
setInterval: util.writable(timers.setInterval),
|
||||
setTimeout: util.writable(timers.setTimeout),
|
||||
|
||||
GPU: util.nonEnumerable(webgpu.GPU),
|
||||
GPUAdapter: util.nonEnumerable(webgpu.GPUAdapter),
|
||||
GPUAdapterLimits: util.nonEnumerable(webgpu.GPUAdapterLimits),
|
||||
GPUAdapterFeatures: util.nonEnumerable(webgpu.GPUAdapterFeatures),
|
||||
GPUDevice: util.nonEnumerable(webgpu.GPUDevice),
|
||||
GPUQueue: util.nonEnumerable(webgpu.GPUQueue),
|
||||
GPUBuffer: util.nonEnumerable(webgpu.GPUBuffer),
|
||||
GPUBufferUsage: util.nonEnumerable(webgpu.GPUBufferUsage),
|
||||
GPUMapMode: util.nonEnumerable(webgpu.GPUMapMode),
|
||||
GPUTexture: util.nonEnumerable(webgpu.GPUTexture),
|
||||
GPUTextureUsage: util.nonEnumerable(webgpu.GPUTextureUsage),
|
||||
GPUTextureView: util.nonEnumerable(webgpu.GPUTextureView),
|
||||
GPUSampler: util.nonEnumerable(webgpu.GPUSampler),
|
||||
GPUBindGroupLayout: util.nonEnumerable(webgpu.GPUBindGroupLayout),
|
||||
GPUPipelineLayout: util.nonEnumerable(webgpu.GPUPipelineLayout),
|
||||
GPUBindGroup: util.nonEnumerable(webgpu.GPUBindGroup),
|
||||
GPUShaderModule: util.nonEnumerable(webgpu.GPUShaderModule),
|
||||
GPUShaderStage: util.nonEnumerable(webgpu.GPUShaderStage),
|
||||
GPUComputePipeline: util.nonEnumerable(webgpu.GPUComputePipeline),
|
||||
GPURenderPipeline: util.nonEnumerable(webgpu.GPURenderPipeline),
|
||||
GPUColorWrite: util.nonEnumerable(webgpu.GPUColorWrite),
|
||||
GPUCommandEncoder: util.nonEnumerable(webgpu.GPUCommandEncoder),
|
||||
GPURenderPassEncoder: util.nonEnumerable(webgpu.GPURenderPassEncoder),
|
||||
GPUComputePassEncoder: util.nonEnumerable(webgpu.GPUComputePassEncoder),
|
||||
GPUCommandBuffer: util.nonEnumerable(webgpu.GPUCommandBuffer),
|
||||
GPURenderBundleEncoder: util.nonEnumerable(webgpu.GPURenderBundleEncoder),
|
||||
GPURenderBundle: util.nonEnumerable(webgpu.GPURenderBundle),
|
||||
GPUQuerySet: util.nonEnumerable(webgpu.GPUQuerySet),
|
||||
GPUOutOfMemoryError: util.nonEnumerable(webgpu.GPUOutOfMemoryError),
|
||||
GPUValidationError: util.nonEnumerable(webgpu.GPUValidationError),
|
||||
};
|
||||
|
||||
// The console seems to be the only one that should be writable and non-enumerable
|
||||
|
@ -256,12 +293,17 @@ delete Object.prototype.__proto__;
|
|||
// structure, it might be worth it to define a helper in `util`
|
||||
windowOrWorkerGlobalScope.console.enumerable = false;
|
||||
|
||||
const windowNavigatorProperties = {
|
||||
gpu: webgpu.gpu,
|
||||
};
|
||||
|
||||
const mainRuntimeGlobalProperties = {
|
||||
Location: location.locationConstructorDescriptor,
|
||||
location: location.locationDescriptor,
|
||||
Window: globalInterfaces.windowConstructorDescriptor,
|
||||
window: util.readOnly(globalThis),
|
||||
self: util.readOnly(globalThis),
|
||||
navigator: util.readOnly(windowNavigatorProperties),
|
||||
// TODO(bartlomieju): from MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope)
|
||||
// it seems those two properties should be available to workers as well
|
||||
onload: util.writable(null),
|
||||
|
@ -273,12 +315,17 @@ delete Object.prototype.__proto__;
|
|||
prompt: util.writable(prompt.prompt),
|
||||
};
|
||||
|
||||
const workerNavigatorProperties = {
|
||||
gpu: webgpu.gpu,
|
||||
};
|
||||
|
||||
const workerRuntimeGlobalProperties = {
|
||||
WorkerLocation: location.workerLocationConstructorDescriptor,
|
||||
location: location.workerLocationDescriptor,
|
||||
WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor,
|
||||
DedicatedWorkerGlobalScope:
|
||||
globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor,
|
||||
navigator: util.readOnly(workerNavigatorProperties),
|
||||
self: util.readOnly(globalThis),
|
||||
onmessage: util.writable(onmessage),
|
||||
onerror: util.writable(onerror),
|
||||
|
|
|
@ -10,6 +10,7 @@ extern crate log;
|
|||
pub use deno_crypto;
|
||||
pub use deno_fetch;
|
||||
pub use deno_web;
|
||||
pub use deno_webgpu;
|
||||
pub use deno_websocket;
|
||||
|
||||
pub mod colors;
|
||||
|
|
|
@ -21,6 +21,7 @@ pub mod timers;
|
|||
pub mod tls;
|
||||
pub mod tty;
|
||||
pub mod web_worker;
|
||||
pub mod webgpu;
|
||||
pub mod websocket;
|
||||
pub mod worker_host;
|
||||
|
||||
|
|
421
runtime/ops/webgpu.rs
Normal file
421
runtime/ops/webgpu.rs
Normal file
|
@ -0,0 +1,421 @@
|
|||
use deno_webgpu::*;
|
||||
|
||||
pub fn init(rt: &mut deno_core::JsRuntime) {
|
||||
{
|
||||
let op_state = rt.op_state();
|
||||
let mut state = op_state.borrow_mut();
|
||||
state.put(wgpu_core::hub::Global::new(
|
||||
"webgpu",
|
||||
wgpu_core::hub::IdentityManagerFactory,
|
||||
wgpu_types::BackendBit::PRIMARY,
|
||||
));
|
||||
let unstable_checker = state.borrow::<super::UnstableChecker>();
|
||||
let unstable = unstable_checker.unstable;
|
||||
state.put(Unstable(unstable));
|
||||
}
|
||||
|
||||
super::reg_json_async(
|
||||
rt,
|
||||
"op_webgpu_request_adapter",
|
||||
op_webgpu_request_adapter,
|
||||
);
|
||||
super::reg_json_async(
|
||||
rt,
|
||||
"op_webgpu_request_device",
|
||||
op_webgpu_request_device,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_query_set",
|
||||
op_webgpu_create_query_set,
|
||||
);
|
||||
|
||||
{
|
||||
// buffer
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_buffer",
|
||||
buffer::op_webgpu_create_buffer,
|
||||
);
|
||||
super::reg_json_async(
|
||||
rt,
|
||||
"op_webgpu_buffer_get_map_async",
|
||||
buffer::op_webgpu_buffer_get_map_async,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_buffer_get_mapped_range",
|
||||
buffer::op_webgpu_buffer_get_mapped_range,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_buffer_unmap",
|
||||
buffer::op_webgpu_buffer_unmap,
|
||||
);
|
||||
}
|
||||
{
|
||||
// texture
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_texture",
|
||||
texture::op_webgpu_create_texture,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_texture_view",
|
||||
texture::op_webgpu_create_texture_view,
|
||||
);
|
||||
}
|
||||
{
|
||||
// sampler
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_sampler",
|
||||
sampler::op_webgpu_create_sampler,
|
||||
);
|
||||
}
|
||||
{
|
||||
// binding
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_bind_group_layout",
|
||||
binding::op_webgpu_create_bind_group_layout,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_pipeline_layout",
|
||||
binding::op_webgpu_create_pipeline_layout,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_bind_group",
|
||||
binding::op_webgpu_create_bind_group,
|
||||
);
|
||||
}
|
||||
{
|
||||
// pipeline
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_compute_pipeline",
|
||||
pipeline::op_webgpu_create_compute_pipeline,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pipeline_get_bind_group_layout",
|
||||
pipeline::op_webgpu_compute_pipeline_get_bind_group_layout,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_render_pipeline",
|
||||
pipeline::op_webgpu_create_render_pipeline,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pipeline_get_bind_group_layout",
|
||||
pipeline::op_webgpu_render_pipeline_get_bind_group_layout,
|
||||
);
|
||||
}
|
||||
{
|
||||
// command_encoder
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_command_encoder",
|
||||
command_encoder::op_webgpu_create_command_encoder,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_begin_render_pass",
|
||||
command_encoder::op_webgpu_command_encoder_begin_render_pass,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_begin_compute_pass",
|
||||
command_encoder::op_webgpu_command_encoder_begin_compute_pass,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_copy_buffer_to_buffer",
|
||||
command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_copy_buffer_to_texture",
|
||||
command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_copy_texture_to_buffer",
|
||||
command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_copy_texture_to_texture",
|
||||
command_encoder::op_webgpu_command_encoder_copy_texture_to_texture,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_push_debug_group",
|
||||
command_encoder::op_webgpu_command_encoder_push_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_pop_debug_group",
|
||||
command_encoder::op_webgpu_command_encoder_pop_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_insert_debug_marker",
|
||||
command_encoder::op_webgpu_command_encoder_insert_debug_marker,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_write_timestamp",
|
||||
command_encoder::op_webgpu_command_encoder_write_timestamp,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_resolve_query_set",
|
||||
command_encoder::op_webgpu_command_encoder_resolve_query_set,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_command_encoder_finish",
|
||||
command_encoder::op_webgpu_command_encoder_finish,
|
||||
);
|
||||
}
|
||||
{
|
||||
// render_pass
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_viewport",
|
||||
render_pass::op_webgpu_render_pass_set_viewport,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_scissor_rect",
|
||||
render_pass::op_webgpu_render_pass_set_scissor_rect,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_blend_color",
|
||||
render_pass::op_webgpu_render_pass_set_blend_color,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_stencil_reference",
|
||||
render_pass::op_webgpu_render_pass_set_stencil_reference,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_begin_pipeline_statistics_query",
|
||||
render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_end_pipeline_statistics_query",
|
||||
render_pass::op_webgpu_render_pass_end_pipeline_statistics_query,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_write_timestamp",
|
||||
render_pass::op_webgpu_render_pass_write_timestamp,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_execute_bundles",
|
||||
render_pass::op_webgpu_render_pass_execute_bundles,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_end_pass",
|
||||
render_pass::op_webgpu_render_pass_end_pass,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_bind_group",
|
||||
render_pass::op_webgpu_render_pass_set_bind_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_push_debug_group",
|
||||
render_pass::op_webgpu_render_pass_push_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_pop_debug_group",
|
||||
render_pass::op_webgpu_render_pass_pop_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_insert_debug_marker",
|
||||
render_pass::op_webgpu_render_pass_insert_debug_marker,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_pipeline",
|
||||
render_pass::op_webgpu_render_pass_set_pipeline,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_index_buffer",
|
||||
render_pass::op_webgpu_render_pass_set_index_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_set_vertex_buffer",
|
||||
render_pass::op_webgpu_render_pass_set_vertex_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_draw",
|
||||
render_pass::op_webgpu_render_pass_draw,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_draw_indexed",
|
||||
render_pass::op_webgpu_render_pass_draw_indexed,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_draw_indirect",
|
||||
render_pass::op_webgpu_render_pass_draw_indirect,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_pass_draw_indexed_indirect",
|
||||
render_pass::op_webgpu_render_pass_draw_indexed_indirect,
|
||||
);
|
||||
}
|
||||
{
|
||||
// compute_pass
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_set_pipeline",
|
||||
compute_pass::op_webgpu_compute_pass_set_pipeline,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_dispatch",
|
||||
compute_pass::op_webgpu_compute_pass_dispatch,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_dispatch_indirect",
|
||||
compute_pass::op_webgpu_compute_pass_dispatch_indirect,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_end_pass",
|
||||
compute_pass::op_webgpu_compute_pass_end_pass,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_set_bind_group",
|
||||
compute_pass::op_webgpu_compute_pass_set_bind_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_push_debug_group",
|
||||
compute_pass::op_webgpu_compute_pass_push_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_pop_debug_group",
|
||||
compute_pass::op_webgpu_compute_pass_pop_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_compute_pass_insert_debug_marker",
|
||||
compute_pass::op_webgpu_compute_pass_insert_debug_marker,
|
||||
);
|
||||
}
|
||||
{
|
||||
// bundle
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_render_bundle_encoder",
|
||||
bundle::op_webgpu_create_render_bundle_encoder,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_finish",
|
||||
bundle::op_webgpu_render_bundle_encoder_finish,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_set_bind_group",
|
||||
bundle::op_webgpu_render_bundle_encoder_set_bind_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_push_debug_group",
|
||||
bundle::op_webgpu_render_bundle_encoder_push_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_pop_debug_group",
|
||||
bundle::op_webgpu_render_bundle_encoder_pop_debug_group,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_insert_debug_marker",
|
||||
bundle::op_webgpu_render_bundle_encoder_insert_debug_marker,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_set_pipeline",
|
||||
bundle::op_webgpu_render_bundle_encoder_set_pipeline,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_set_index_buffer",
|
||||
bundle::op_webgpu_render_bundle_encoder_set_index_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_set_vertex_buffer",
|
||||
bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_draw",
|
||||
bundle::op_webgpu_render_bundle_encoder_draw,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_draw_indexed",
|
||||
bundle::op_webgpu_render_bundle_encoder_draw_indexed,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_render_bundle_encoder_draw_indirect",
|
||||
bundle::op_webgpu_render_bundle_encoder_draw_indirect,
|
||||
);
|
||||
}
|
||||
{
|
||||
// queue
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_queue_submit",
|
||||
queue::op_webgpu_queue_submit,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_write_buffer",
|
||||
queue::op_webgpu_write_buffer,
|
||||
);
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_write_texture",
|
||||
queue::op_webgpu_write_texture,
|
||||
);
|
||||
}
|
||||
{
|
||||
// shader
|
||||
super::reg_json_sync(
|
||||
rt,
|
||||
"op_webgpu_create_shader_module",
|
||||
shader::op_webgpu_create_shader_module,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -237,6 +237,7 @@ impl WebWorker {
|
|||
deno_web::op_domain_to_ascii,
|
||||
);
|
||||
ops::io::init(js_runtime);
|
||||
ops::webgpu::init(js_runtime);
|
||||
ops::websocket::init(
|
||||
js_runtime,
|
||||
options.user_agent.clone(),
|
||||
|
|
|
@ -142,6 +142,7 @@ impl MainWorker {
|
|||
ops::signal::init(js_runtime);
|
||||
ops::tls::init(js_runtime);
|
||||
ops::tty::init(js_runtime);
|
||||
ops::webgpu::init(js_runtime);
|
||||
ops::websocket::init(
|
||||
js_runtime,
|
||||
options.user_agent.clone(),
|
||||
|
|
Loading…
Reference in a new issue