commit ef0195a8c0286ae27b2a4d3d7ce5120dffce0db8 parent 5e702c7b79773013fe6e4a87928d66a2ff720f14 Author: Jim Blandy <jimb@red-bean.com> Date: Tue, 9 Dec 2025 19:00:25 +0000 Bug 2000474 - Update wgpu to upstream 9a975b24 (2025-11-16) r=webgpu-reviewers,supply-chain-reviewers,aleiserson Differential Revision: https://phabricator.services.mozilla.com/D274054 Diffstat:
79 files changed, 4101 insertions(+), 1478 deletions(-)
diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in @@ -35,9 +35,9 @@ git = "https://github.com/franziskuskiefer/cose-rust" rev = "43c22248d136c8b38fe42ea709d08da6355cf04b" replace-with = "vendored-sources" -[source."git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4"] +[source."git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a"] git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" replace-with = "vendored-sources" [source."git+https://github.com/glandium/allocator-api2?rev=ad5f3d56a5a4519eff52af4ff85293431466ef5c"] diff --git a/Cargo.lock b/Cargo.lock @@ -4785,7 +4785,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" [[package]] name = "naga" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "arrayvec", "bit-set", @@ -7973,7 +7973,7 @@ dependencies = [ [[package]] name = "wgpu-core" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "arrayvec", "bit-set", @@ -8004,7 +8004,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "wgpu-hal", ] @@ -8012,7 +8012,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-windows-linux-android" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "wgpu-hal", ] @@ -8020,7 +8020,7 @@ dependencies = [ [[package]] name = "wgpu-hal" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "android_system_properties", "arrayvec", @@ -8058,7 +8058,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +source = "git+https://github.com/gfx-rs/wgpu?rev=9a975b24deb379b31a8a7cb999d2da5f3227a91a#9a975b24deb379b31a8a7cb999d2da5f3227a91a" dependencies = [ "bitflags 2.9.0", "bytemuck", diff --git a/gfx/wgpu_bindings/Cargo.toml b/gfx/wgpu_bindings/Cargo.toml @@ -17,7 +17,7 @@ default = [] [dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" features = ["serde", "trace", "strict_asserts", "wgsl", "api_log_info"] # We want the wgpu-core Metal backend on macOS and iOS. @@ -25,32 +25,32 @@ features = ["serde", "trace", "strict_asserts", "wgsl", "api_log_info"] [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" features = ["metal"] # We want the wgpu-core Direct3D backends on Windows. [target.'cfg(windows)'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" features = ["dx12"] # We want the wgpu-core Vulkan backend on Linux and Windows. [target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +rev = "9a975b24deb379b31a8a7cb999d2da5f3227a91a" features = ["device_lost_panic", "internal_error_panic"] [target.'cfg(windows)'.dependencies] diff --git a/gfx/wgpu_bindings/moz.yaml b/gfx/wgpu_bindings/moz.yaml @@ -8,8 +8,8 @@ origin: name: wgpu description: A cross-platform pure-Rust graphics API, modeled on the WebGPU standard url: https://github.com/gfx-rs/wgpu - release: d65295a3ce2bb11a36c2c2454ef400652fc1c4a4 (2025-11-18T17:48:01Z). - revision: d65295a3ce2bb11a36c2c2454ef400652fc1c4a4 + release: 9a975b24deb379b31a8a7cb999d2da5f3227a91a (2025-11-16T19:09:51Z). + revision: 9a975b24deb379b31a8a7cb999d2da5f3227a91a license: ['MIT', 'Apache-2.0'] updatebot: diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs @@ -1794,6 +1794,7 @@ impl Global { Some(Box::new(move || { image_holder.destroy(); })), + None, ); let (_, error) = self.create_texture_from_hal( diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml @@ -4371,12 +4371,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.naga]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.net2]] @@ -6943,12 +6943,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.wgpu-core]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.wgpu-core-deps-apple]] @@ -6974,12 +6974,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.wgpu-core-deps-apple]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.wgpu-core-deps-windows-linux-android]] @@ -7005,12 +7005,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.wgpu-core-deps-windows-linux-android]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.wgpu-hal]] @@ -7114,12 +7114,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.wgpu-hal]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.wgpu-types]] @@ -7218,12 +7218,12 @@ delta = "26.0.0 -> 27.0.0" [[audits.wgpu-types]] who = [ "Andy Leiserson <aleiserson@mozilla.com>", - "Jim Blandy <jimb@red-bean.com>", "Teodor Tanasoaia <ttanasoaia@mozilla.com>", "Erich Gubler <erichdongubler@gmail.com>", + "Jim Blandy <jimb@red-bean.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" +delta = "27.0.0 -> 27.0.0@git:9a975b24deb379b31a8a7cb999d2da5f3227a91a" importable = false [[audits.whatsys]] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/queue/buffer_mapped/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/queue/buffer_mapped/cts.https.html.ini @@ -15,6 +15,4 @@ [cts.https.html?q=webgpu:api,validation,queue,buffer_mapped:writeBuffer:*] - implementation-status: backlog [:] - expected: FAIL diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/state/device_lost/destroy/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/state/device_lost/destroy/cts.https.html.ini @@ -2577,16 +2577,14 @@ expected: if os == "win" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "win" and not debug: [TIMEOUT, NOTRUN] - if os == "linux" and debug: [TIMEOUT, NOTRUN] - if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:format="bgra8unorm-srgb";usageType="render";usageCopy="src-dest";awaitLost=true] expected: if os == "win" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "win" and not debug: [TIMEOUT, NOTRUN] - if os == "linux" and debug: [TIMEOUT, NOTRUN] - if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:format="bgra8unorm-srgb";usageType="texture";usageCopy="dst";awaitLost=false] @@ -3325,8 +3323,7 @@ expected: if os == "win" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "win" and not debug: [TIMEOUT, NOTRUN] - if os == "linux" and debug: [TIMEOUT, NOTRUN] - if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:format="r16unorm";usageType="texture";usageCopy="src";awaitLost=false] @@ -5926,7 +5923,7 @@ [:format="rgba8uint";usageType="render";usageCopy="src-dest";awaitLost=false] expected: if os == "win" and debug: [PASS, FAIL, TIMEOUT, NOTRUN] - if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "win" and not debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] @@ -6967,44 +6964,36 @@ [:format="astc-5x5-unorm";usageType="texture";usageCopy="src-dest";awaitLost=false] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm";usageType="texture";usageCopy="src-dest";awaitLost=true] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="dst";awaitLost=false] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="dst";awaitLost=true] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="none";awaitLost=false] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="none";awaitLost=true] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="src";awaitLost=false] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="src";awaitLost=true] expected: - if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="astc-5x5-unorm-srgb";usageType="texture";usageCopy="src-dest";awaitLost=false] expected: @@ -9656,8 +9645,7 @@ [:format="rg16unorm";usageType="render";usageCopy="none";awaitLost=true] expected: - if os == "win" and debug: [TIMEOUT, NOTRUN] - if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "win": [PASS, TIMEOUT, NOTRUN] if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] @@ -9725,15 +9713,13 @@ [:format="rg16unorm";usageType="storage";usageCopy="src-dest";awaitLost=false] expected: - if os == "win" and debug: [TIMEOUT, NOTRUN] - if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "win": [PASS, TIMEOUT, NOTRUN] if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:format="rg16unorm";usageType="storage";usageCopy="src-dest";awaitLost=true] expected: - if os == "win" and debug: [TIMEOUT, NOTRUN] - if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "win": [PASS, TIMEOUT, NOTRUN] if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] @@ -11154,7 +11140,8 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [PASS, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="rgba8sint";usageType="texture";usageCopy="none";awaitLost=false] expected: @@ -11174,13 +11161,15 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [PASS, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="rgba8sint";usageType="texture";usageCopy="src";awaitLost=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [PASS, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="rgba8sint";usageType="texture";usageCopy="src-dest";awaitLost=false] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureGather/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureGather/cts.https.html.ini @@ -11070,6 +11070,8 @@ [:stage="c";format="rgba16snorm";filt="linear";modeU="c";modeV="r";offset=true] [:stage="c";format="rgba16snorm";filt="linear";modeU="m";modeV="c";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rgba16snorm";filt="linear";modeU="m";modeV="c";offset=true] expected: @@ -11096,12 +11098,20 @@ [:stage="c";format="rgba16snorm";filt="linear";modeU="r";modeV="c";offset=true] [:stage="c";format="rgba16snorm";filt="linear";modeU="r";modeV="m";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rgba16snorm";filt="linear";modeU="r";modeV="m";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rgba16snorm";filt="linear";modeU="r";modeV="r";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rgba16snorm";filt="linear";modeU="r";modeV="r";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rgba16snorm";filt="nearest";modeU="c";modeV="c";offset=false] @@ -32652,91 +32662,109 @@ [:stage="f";format="astc-4x4-unorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm-srgb";filt="linear";mode="c"] @@ -32760,6 +32788,7 @@ [:stage="f";format="astc-5x4-unorm-srgb";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x4-unorm-srgb";filt="nearest";mode="m"] @@ -32771,6 +32800,7 @@ [:stage="f";format="astc-5x4-unorm-srgb";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-5x5-unorm";filt="linear";mode="c"] @@ -33259,6 +33289,7 @@ [:stage="f";format="bc2-rgba-unorm";filt="linear";mode="m"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm";filt="linear";mode="r"] @@ -33279,26 +33310,32 @@ [:stage="f";format="bc2-rgba-unorm-srgb";filt="linear";mode="c"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm-srgb";filt="linear";mode="m"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm-srgb";filt="linear";mode="r"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm-srgb";filt="nearest";mode="c"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm-srgb";filt="nearest";mode="m"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc2-rgba-unorm-srgb";filt="nearest";mode="r"] expected: + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc3-rgba-unorm";filt="linear";mode="c"] @@ -33711,46 +33748,55 @@ [:stage="f";format="eac-r11snorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11snorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11snorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11snorm";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11snorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11snorm";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11unorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11unorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11unorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11unorm";filt="nearest";mode="c"] @@ -33761,6 +33807,7 @@ [:stage="f";format="eac-r11unorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-r11unorm";filt="nearest";mode="r"] @@ -33771,61 +33818,73 @@ [:stage="f";format="eac-rg11snorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11snorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11snorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11snorm";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11snorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11snorm";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="linear";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="linear";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="linear";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="nearest";mode="c"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="nearest";mode="m"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="eac-rg11unorm";filt="nearest";mode="r"] expected: if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="etc2-rgb8a1unorm";filt="linear";mode="c"] @@ -45568,8 +45627,12 @@ if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="c";modeV="c";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="c";modeV="c";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="c";modeV="m";offset=false] expected: @@ -45580,8 +45643,12 @@ if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="c";modeV="r";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="c";modeV="r";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16float";filt="nearest";modeU="m";modeV="c";offset=false] expected: @@ -45638,34 +45705,60 @@ [:stage="c";format="rg16sint";filt="nearest";modeU="c";modeV="m";offset=false] [:stage="c";format="rg16sint";filt="nearest";modeU="c";modeV="m";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="c";modeV="r";offset=false] [:stage="c";format="rg16sint";filt="nearest";modeU="c";modeV="r";offset=true] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="c";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="c";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="m";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="m";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="r";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="m";modeV="r";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="c";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="c";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="m";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="m";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="r";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16sint";filt="nearest";modeU="r";modeV="r";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg16snorm";filt="linear";modeU="c";modeV="c";offset=false] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureGatherCompare/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureGatherCompare/cts.https.html.ini @@ -3351,7 +3351,8 @@ [:stage="v";format="depth32float-stencil8";filt="nearest";mode="m"] expected: - if os == "win": FAIL + if os == "win" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "win" and not debug: FAIL if os == "linux": FAIL if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "mac" and not debug: FAIL diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSample/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSample/cts.https.html.ini @@ -6442,13 +6442,15 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="m";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="r";offset=false] expected: @@ -6504,13 +6506,15 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="c";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="m";offset=false] expected: @@ -46789,7 +46793,7 @@ [:format="rgba8unorm";dim="3d";filt="linear";modeU="c";modeV="r";modeW="r";offset=true] expected: if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="linear";modeU="m";modeV="c";modeW="c";offset=false] expected: @@ -46995,14 +46999,24 @@ [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="c";offset=false] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="c";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="m";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="m";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="r";offset=false] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="c";modeV="r";modeW="r";offset=true] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:format="rgba8unorm";dim="3d";filt="nearest";modeU="m";modeV="c";modeW="c";offset=false] expected: @@ -58322,7 +58336,7 @@ [:format="bc7-rgba-unorm";filt="linear";mode="m"] expected: - if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc7-rgba-unorm";filt="linear";mode="r"] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleBias/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleBias/cts.https.html.ini @@ -7739,15 +7739,13 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="r";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="nearest";modeU="c";modeV="c";offset=false] expected: @@ -10650,11 +10648,13 @@ [:format="bc3-rgba-unorm";filt="linear";mode="m"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm";filt="linear";mode="r"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm";filt="nearest";mode="c"] @@ -10675,31 +10675,37 @@ [:format="bc3-rgba-unorm-srgb";filt="linear";mode="c"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm-srgb";filt="linear";mode="m"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm-srgb";filt="linear";mode="r"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm-srgb";filt="nearest";mode="c"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm-srgb";filt="nearest";mode="m"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc3-rgba-unorm-srgb";filt="nearest";mode="r"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] [:format="bc4-r-snorm";filt="linear";mode="c"] @@ -11029,7 +11035,7 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "mac" and not debug: FAIL [:format="eac-r11snorm";filt="linear";mode="c"] @@ -19278,57 +19284,49 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="c";modeV="c";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="c";modeV="m";offset=false] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="c";modeV="m";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="c";modeV="r";offset=false] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="c";modeV="r";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="m";modeV="c";offset=false] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="m";modeV="c";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="m";modeV="m";offset=false] expected: @@ -19346,8 +19344,7 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="m";modeV="r";offset=true] expected: @@ -19359,43 +19356,37 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="c";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="m";offset=false] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="m";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="r";offset=false] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="linear";modeU="r";modeV="r";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="nearest";modeU="c";modeV="c";offset=false] expected: @@ -19457,15 +19448,13 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="nearest";modeU="m";modeV="m";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:format="rg11b10ufloat";filt="nearest";modeU="m";modeV="r";offset=false] expected: @@ -49835,7 +49824,11 @@ if os == "mac": [TIMEOUT, NOTRUN] [:format="r16unorm";dim="3d";filt="linear";modeU="r";modeV="c";modeW="m";offset=true] - expected: [TIMEOUT, NOTRUN] + expected: + if os == "win" and debug: [TIMEOUT, NOTRUN] + if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [TIMEOUT, NOTRUN] + if os == "mac": [TIMEOUT, NOTRUN] [:format="r16unorm";dim="3d";filt="linear";modeU="r";modeV="c";modeW="r";offset=false] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleCompare/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleCompare/cts.https.html.ini @@ -1352,7 +1352,11 @@ expected: FAIL [:format="depth32float";filt="linear";modeU="m";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:format="depth32float";filt="linear";modeU="m";modeV="c";offset=true] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleCompareLevel/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleCompareLevel/cts.https.html.ini @@ -680,25 +680,45 @@ if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="c";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="m";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="m";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="r";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="m";modeV="r";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [PASS, FAIL] + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="r";modeV="c";offset=false] @@ -712,20 +732,32 @@ expected: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="r";modeV="m";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="r";modeV="m";offset=true] expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [PASS, FAIL] + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="r";modeV="r";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="linear";modeU="r";modeV="r";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus";filt="nearest";modeU="c";modeV="c";offset=false] expected: FAIL @@ -908,28 +940,60 @@ if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="c";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="m";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="m";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="r";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="r";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="m";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="m";modeV="c";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="m";modeV="m";offset=false] expected: @@ -946,28 +1010,60 @@ if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="m";modeV="r";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="m";modeV="r";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="c";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="m";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="m";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="r";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth24plus-stencil8";filt="nearest";modeU="r";modeV="r";offset=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth32float";filt="linear";modeU="c";modeV="c";offset=false] expected: FAIL @@ -1801,7 +1897,8 @@ [:stage="v";format="depth24plus";filt="nearest";modeU="m";modeV="r";offset=true] expected: if os == "win": FAIL - if os == "linux": FAIL + if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "linux" and not debug: FAIL if os == "mac" and debug: [TIMEOUT, NOTRUN] if os == "mac" and not debug: [PASS, FAIL, TIMEOUT, NOTRUN] @@ -2022,7 +2119,7 @@ [:stage="v";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="r";offset=false] expected: if os == "win": FAIL - if os == "linux" and debug: [TIMEOUT, NOTRUN] + if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL if os == "mac": [TIMEOUT, NOTRUN] @@ -3450,7 +3547,11 @@ if not debug: FAIL [:stage="c";format="depth32float";filt="linear";modeU="c";modeV="c";offset=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="c";format="depth32float";filt="linear";modeU="c";modeV="c";offset=true] expected: @@ -6357,10 +6458,18 @@ expected: FAIL [:stage="f";format="depth32float-stencil8";filt="linear";mode="m"] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth32float-stencil8";filt="linear";mode="r"] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="f";format="depth32float-stencil8";filt="nearest";mode="c"] expected: FAIL @@ -6376,42 +6485,48 @@ if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth16unorm";filt="linear";mode="m"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth16unorm";filt="linear";mode="r"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth16unorm";filt="nearest";mode="c"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth16unorm";filt="nearest";mode="m"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth16unorm";filt="nearest";mode="r"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth24plus";filt="linear";mode="c"] expected: @@ -6505,42 +6620,48 @@ if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float";filt="linear";mode="m"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float";filt="linear";mode="r"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float";filt="nearest";mode="c"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float";filt="nearest";mode="m"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float";filt="nearest";mode="r"] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:stage="v";format="depth32float-stencil8";filt="linear";mode="c"] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleLevel/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/execution/expression/call/builtin/textureSampleLevel/cts.https.html.ini @@ -2798,6 +2798,8 @@ [:stage="c";format="astc-8x5-unorm";filt="nearest";modeU="r";modeV="r"] [:stage="c";format="astc-8x5-unorm-srgb";filt="linear";modeU="c";modeV="c"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="astc-8x5-unorm-srgb";filt="linear";modeU="c";modeV="m"] expected: @@ -2838,14 +2840,22 @@ [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="c";modeV="r"] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="m";modeV="c"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="m";modeV="m"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="m";modeV="r"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="r";modeV="c"] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="r";modeV="m"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:stage="c";format="astc-8x5-unorm-srgb";filt="nearest";modeU="r";modeV="r"] @@ -5648,7 +5658,7 @@ [:stage="f";format="astc-4x4-unorm-srgb";filt="linear";modeU="c";modeV="m"] expected: if os == "win" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [PASS, TIMEOUT, NOTRUN] if os == "mac": [TIMEOUT, NOTRUN] [:stage="f";format="astc-4x4-unorm-srgb";filt="linear";modeU="c";modeV="r"] @@ -20280,7 +20290,11 @@ if os == "mac": [TIMEOUT, NOTRUN] [:stage="c";format="bc4-r-unorm";filt="nearest";modeU="r";modeV="m";offset=false] - expected: [TIMEOUT, NOTRUN] + expected: + if os == "win" and debug: [TIMEOUT, NOTRUN] + if os == "win" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "linux": [TIMEOUT, NOTRUN] + if os == "mac": [TIMEOUT, NOTRUN] [:stage="c";format="bc4-r-unorm";filt="nearest";modeU="r";modeV="m";offset=true] expected: [TIMEOUT, NOTRUN] @@ -21115,7 +21129,8 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:stage="c";format="depth24plus";filt="nearest";modeU="m";modeV="r";offset=false] expected: @@ -23162,21 +23177,19 @@ [:stage="c";format="rg11b10ufloat";filt="linear";modeU="c";modeV="m";offset=false] expected: - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="c";modeV="m";offset=true] expected: - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="c";modeV="r";offset=false] expected: - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="c";modeV="r";offset=true] expected: - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="m";modeV="c";offset=false] expected: @@ -23204,12 +23217,11 @@ [:stage="c";format="rg11b10ufloat";filt="linear";modeU="r";modeV="c";offset=false] expected: - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="r";modeV="c";offset=true] expected: - if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac" and not debug: FAIL + if os == "mac": [FAIL, TIMEOUT, NOTRUN] [:stage="c";format="rg11b10ufloat";filt="linear";modeU="r";modeV="m";offset=false] expected: @@ -67133,7 +67145,7 @@ if os == "win": FAIL if os == "linux": FAIL if os == "mac" and debug: [TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:stage="c";format="depth24plus-stencil8";filt="nearest";modeU="c";modeV="c";offset=true] expected: @@ -90564,7 +90576,8 @@ expected: if os == "win" and debug: [TIMEOUT, NOTRUN] if os == "linux" and debug: [TIMEOUT, NOTRUN] - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] [:stage="f";format="bc5-rg-snorm";filt="linear";mode="c"] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/validation/expression/call/builtin/subgroupShuffle/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/shader/validation/expression/call/builtin/subgroupShuffle/cts.https.html.ini @@ -1282,6 +1282,8 @@ if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleDown";paramType="bool"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleDown";paramType="f16"] expected: @@ -1396,6 +1398,8 @@ [:retType="i32";op="subgroupShuffleUp";paramType="i32"] [:retType="i32";op="subgroupShuffleUp";paramType="u32"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec2%3Cabstract-float%3E"] @@ -1408,8 +1412,12 @@ [:retType="i32";op="subgroupShuffleUp";paramType="vec2%3Cf32%3E"] [:retType="i32";op="subgroupShuffleUp";paramType="vec2%3Ci32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec2%3Cu32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec3%3Cabstract-float%3E"] @@ -1422,8 +1430,12 @@ [:retType="i32";op="subgroupShuffleUp";paramType="vec3%3Cf32%3E"] [:retType="i32";op="subgroupShuffleUp";paramType="vec3%3Ci32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec3%3Cu32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec4%3Cabstract-float%3E"] @@ -1436,8 +1448,12 @@ [:retType="i32";op="subgroupShuffleUp";paramType="vec4%3Cf32%3E"] [:retType="i32";op="subgroupShuffleUp";paramType="vec4%3Ci32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleUp";paramType="vec4%3Cu32%3E"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:retType="i32";op="subgroupShuffleXor";paramType="abstract-float"] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageBitmap/dedicated.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageBitmap/dedicated.https.html.ini @@ -1770,7 +1770,8 @@ if os == "win" and debug: [TIMEOUT, NOTRUN] if os == "linux" and debug: [TIMEOUT, NOTRUN] if os == "linux" and not debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [PASS, TIMEOUT, NOTRUN] [:alpha="premultiply";orientation="flipY";colorSpaceConversion="none";srcFlipYInCopy=false;dstFormat="rg11b10ufloat";dstPremultiplied=false] expected: @@ -1998,7 +1999,8 @@ if os == "win" and not debug: FAIL if os == "linux" and debug: [TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:alpha="premultiply";orientation="flipY";colorSpaceConversion="none";srcFlipYInCopy=true;dstFormat="rg11b10ufloat";dstPremultiplied=true] expected: @@ -2006,7 +2008,8 @@ if os == "win" and not debug: FAIL if os == "linux" and debug: [TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:alpha="premultiply";orientation="flipY";colorSpaceConversion="none";srcFlipYInCopy=true;dstFormat="rg16float";dstPremultiplied=false] expected: @@ -2058,7 +2061,8 @@ if os == "win" and not debug: FAIL if os == "linux" and debug: [TIMEOUT, NOTRUN] if os == "linux" and not debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:alpha="premultiply";orientation="flipY";colorSpaceConversion="none";srcFlipYInCopy=true;dstFormat="rgb10a2unorm";dstPremultiplied=true] expected: @@ -2066,7 +2070,8 @@ if os == "win" and not debug: FAIL if os == "linux" and debug: [TIMEOUT, NOTRUN] if os == "linux" and not debug: [FAIL, TIMEOUT, NOTRUN] - if os == "mac": [TIMEOUT, NOTRUN] + if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:alpha="premultiply";orientation="flipY";colorSpaceConversion="none";srcFlipYInCopy=true;dstFormat="rgba16float";dstPremultiplied=false] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageBitmap/shared.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageBitmap/shared.https.html.ini @@ -4166,7 +4166,7 @@ expected: if os == "win": FAIL if os == "linux": FAIL - if os == "mac" and debug: [TIMEOUT, NOTRUN] + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "mac" and not debug: FAIL [:orientation="none";colorSpaceConversion="none";srcFlipYInCopy=true;dstFormat="rg16float";dstPremultiplied=false] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageData/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/web_platform/copyToTexture/ImageData/cts.https.html.ini @@ -17,6 +17,7 @@ implementation-status: backlog expected: if os == "linux" and debug: [OK, TIMEOUT] + if os == "mac" and debug: [OK, TIMEOUT] [:srcDoFlipYDuringCopy=false;dstColorFormat="bgra8unorm";dstPremultiplied=false] expected: if os == "win": FAIL @@ -60,10 +61,18 @@ if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] [:srcDoFlipYDuringCopy=false;dstColorFormat="r32float";dstPremultiplied=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="r32float";dstPremultiplied=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="r8unorm";dstPremultiplied=false] expected: FAIL @@ -72,10 +81,18 @@ expected: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rg11b10ufloat";dstPremultiplied=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rg11b10ufloat";dstPremultiplied=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rg16float";dstPremultiplied=false] expected: FAIL @@ -92,10 +109,18 @@ if os == "linux" and debug: [PASS, TIMEOUT, NOTRUN] [:srcDoFlipYDuringCopy=false;dstColorFormat="rg32float";dstPremultiplied=false] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rg32float";dstPremultiplied=true] - expected: FAIL + expected: + if os == "win": FAIL + if os == "linux": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rg8unorm";dstPremultiplied=false] expected: FAIL @@ -108,14 +133,16 @@ if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rgb10a2unorm";dstPremultiplied=true] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rgba16float";dstPremultiplied=false] expected: @@ -144,14 +171,16 @@ if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rgba32float";dstPremultiplied=true] expected: if os == "win": FAIL if os == "linux" and debug: [FAIL, TIMEOUT, NOTRUN] if os == "linux" and not debug: FAIL - if os == "mac": FAIL + if os == "mac" and debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and not debug: FAIL [:srcDoFlipYDuringCopy=false;dstColorFormat="rgba8unorm";dstPremultiplied=false] expected: FAIL diff --git a/third_party/rust/naga/.cargo-checksum.json b/third_party/rust/naga/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"16c70c2205a241af1934fa82693b68dd82b53777e349465be5b79991b8374848","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"baaed995bcbd2f7d15bd63cede28e579175d408e5a40289f74b32ab65c6850c3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"0e2d1c372a7c40b77793dc413b8920e86459e4656775a010f32974b4ad67a7fd","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"b25c4dc06050c563114caa33cd3ffd8e44797e670b35d325ab39f5793b208d5a","src/back/glsl/features.rs":"f187af71341bf9f853b019990ca211cdf6b5b57121a4dda33d609f21f8f828ad","src/back/glsl/keywords.rs":"fee8ed132e44bace54869a7c169a1ab7ed55db1bf590b4b1bce9efa4552e1dd7","src/back/glsl/mod.rs":"06229cbeae78ff43c173017786e001cddcd465dafe3e6edc3dec79784709edea","src/back/hlsl/conv.rs":"c34ce84d9e2dc6f081d7192f85fefc23ee7b05df1da843517cbe19cb2dc87751","src/back/hlsl/help.rs":"12ddb9d08fe64eb34b66ae2166edffce5106a04ccef0b8cc0391a6fafd676270","src/back/hlsl/keywords.rs":"f7fc06c44d2f0d620bcf1a02b699c98c32059741b771a0d1ba5645d71b2f433f","src/back/hlsl/mod.rs":"cbba2f7b5a3c7247c16422f0ce61c1ae4ce20edab8f8a4f2f29a219651606a7b","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"5083d03b1f25fe767e45e0c507bd30424352fccd48484c081620712d3682aae8","src/back/hlsl/writer.rs":"ce9b1abb593a2881e743b60698ace0ed759664d34af88fc0c057383591bda7a3","src/back/mod.rs":"e4fdfcd2baba2f805422852753a9892a3d2b6449928265f061902f91bea90463","src/back/msl/keywords.rs":"b3e5d86d2586d553ff0fc6d91a25f0f4726c829d280a65dd2deeeb146cbbaf6d","src/back/msl/mod.rs":"77b1506c26e80ca5ae1c786debbeedaf3384625eda7c4223530dfa264e770801","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"cfae3edc9afe8b454f2548b4b1b289e9926a825fb5a313afb87fe9af6f13f44c","src/back/pipeline_constants.rs":"33d3898cd411c542eca7727222065bf39f3bdb4699046e9b4bbbc976da9e0768","src/back/spv/block.rs":"dc8dda2d581c67085261ccecabb4df61bcc4669bd3dc4b1a417b3b6a96de4e39","src/back/spv/f16_polyfill.rs":"44ce07ef497dff13a9152eb9bc5936c486ef53de6d476da6b0a39396b0e6abdb","src/back/spv/helpers.rs":"8b430ceb6722a1542ab95e581f11277eff38d0041e98b97ce9681541491e1a28","src/back/spv/image.rs":"5fb7e36ffb4236168809978ed8634a4024a910ca5a233833d89e39f9768880d3","src/back/spv/index.rs":"f4cc05768672658780f159ff8280bcf30af081af7a735338789b31f662ad1889","src/back/spv/instructions.rs":"556f1f30ae11c3e01910c354a36ba314280932e3a2928584b06eb0812a2cb81a","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"20ab263c44ce41ebc39b5fe120116cd42b8543fa0471e60b8344e39c15834fe1","src/back/spv/ray.rs":"a31fd66e9497ffd19437bdab53427705b7f28f555ab215c8f0a4c2156283413e","src/back/spv/recyclable.rs":"8ea397d4d8d3f2cd5fbc8e0be94d136c2d6e0f0e8a4b5eb567dcc1be104c9ae5","src/back/spv/selection.rs":"aea4bb4da7c0fa4e907b8f1e185433a48f2f0eb7ded97fdd3225beb3f6c1f249","src/back/spv/subgroup.rs":"68fc3e3153022a0a8bddec20ad9221820678f02921878318e571d5aa2ca13cee","src/back/spv/writer.rs":"b206304de667a34392ed1b64c7a0700220a7a9c9e176abac4a04cdb5f847d4a0","src/back/wgsl/mod.rs":"1b04d66e8dba609513d43431d1f0ee9a209fbfd8453862d6e8a7aa41f8910997","src/back/wgsl/polyfill/inverse/inverse_2x2_f16.wgsl":"9e7635d04724822931c805a8b35e76d6d294d447e4ea8d57b308ce45609bf736","src/back/wgsl/polyfill/inverse/inverse_2x2_f32.wgsl":"340d491abde07f93996391796db65a5f88402663eaf6b9d2d894d11cb8cf8b6d","src/back/wgsl/polyfill/inverse/inverse_3x3_f16.wgsl":"4f13a1a4b3e1b51f0f992d13c55cf854a80917554a4d13c997819fa1fe776ba4","src/back/wgsl/polyfill/inverse/inverse_3x3_f32.wgsl":"9b16d2f4b9e433c8e03a0cb46ab48508f3bf7e185ce1b4e26106c47e81a677cb","src/back/wgsl/polyfill/inverse/inverse_4x4_f16.wgsl":"86d39d1db5d03995b404950279db7f1698ad9622982aa319fdedb7532673235b","src/back/wgsl/polyfill/inverse/inverse_4x4_f32.wgsl":"dc510525ac2dce66389a8c4bf8b2f31f0dedd9e6debdbe4ffd939a0a7fc533d3","src/back/wgsl/polyfill/mod.rs":"f4ab3c9b9cdc36d16dab00d0f7f07d6e6beda0e27a36053e9b5ffeeb7ca18edc","src/back/wgsl/writer.rs":"e2112a67d67e246281610e880cd28c42c107d52a4bba3a8f483e32808690ed56","src/common/diagnostic_debug.rs":"8c73fe605e5b6162d0485e264287ac50c061cf581743feebbffe1474d1d3516d","src/common/diagnostic_display.rs":"46f1ff8a32179703ef0bcdb704db9f6e6e8b4eaad6cadf94577eeab3d8a16cd1","src/common/mod.rs":"289231637b08407fbe2cc976a1bab4eac4c9e66042c6618aff3af44baaff3e26","src/common/predeclared.rs":"a5f42d55f2e13d8f5a8213d4a881e9155c3994c4054d43edcf7bd7bb7c868ccf","src/common/wgsl/diagnostics.rs":"4fec985b4c5cc6dfae4dd78bd7c850adc88a1761d7b6691de0355ea49300e532","src/common/wgsl/mod.rs":"d944915ff692c96aecca67737bccc2d5d9eb68f475166a2744f29a025f4a4c93","src/common/wgsl/to_wgsl.rs":"536f542cfcf19f67635d13ef3d13cc023a06afa3956900590bcfcdec0a57de6f","src/common/wgsl/types.rs":"390323fecff390100fafcc2cb1e5cf349c7aac9da8065e9aec52a56718ab5534","src/compact/expressions.rs":"12653b34c7c7d68ce7d14a9c15e59c469fda4931425d14600fbaa99226af735f","src/compact/functions.rs":"27a0d33e5a8f02778b518c6e0db5a5d41f77a93b64eadef54b6cf0914067d7ad","src/compact/handle_set_map.rs":"b4688bff174487f2da4a1a946af07c80b6ba59f60dc84184c6a30039354209e8","src/compact/mod.rs":"77d54a73fcb47fdb99fc8c58c6dc688fb0e3594ef11686605c98a0aa23b5cc3f","src/compact/statements.rs":"b5fd961acdf84bea626452fbcf73ee4d9923907c4cee5f4c3c892167b574ce4c","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"46180b139b60cca1e46a8848f9eecc5cab8220a022e4c6f8ce297d1d968e87e7","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"76821d82b315ab6812e8411908885f0687ad98abfe0ea9f007e2deefed10cc0a","src/front/glsl/context.rs":"8314e1ed58b509788adbda82a8f4c7fbd2767522d0352ca1ebd11d86b4bfd10d","src/front/glsl/error.rs":"f445297e0357919e2345ae15f2d23c58d36a64c9a666f1cf1b09cbcfd6e4627a","src/front/glsl/functions.rs":"8040564f5429bf4be23e8dbd02c9cd3bbdd7eb8915b1b90ded6bc889db0b88c7","src/front/glsl/lex.rs":"24706628b600b5ce435cef464c84196ac5d58013122a97e7b59d509cc25f85a2","src/front/glsl/mod.rs":"132f2a60812b3910f65e6281562d4dc94efa329fd1eb0f2778ffe67631a35f78","src/front/glsl/offset.rs":"66bd524a2d17dc44f431430dcbbb74a771fdab43c9581e88bb1123e6cfec516b","src/front/glsl/parser.rs":"6a13b4737f53b09d5bbc0add01f8fc1b2633b7957f0318374edfe0b903939912","src/front/glsl/parser/declarations.rs":"9949649fba43636d03eaf7f7560d3bb3743b19c7204fb95859283ee84b5dd239","src/front/glsl/parser/expressions.rs":"e056fbdde3bc7c8473acbd485aecd14120d3dbefbabd813ddbc5cfedaf605889","src/front/glsl/parser/functions.rs":"302e24e06190aff555131c33f9a80b15df6a0390d6c776f888a44d5ef7df697e","src/front/glsl/parser/types.rs":"ee242048a65cd3709e16b70a3882e9296e615327480f2ad779e3d2523778181f","src/front/glsl/parser_tests.rs":"6834f0d595f4077266054e5da43e4f1b60e5c6780611ab0f530d9964cc62fad3","src/front/glsl/token.rs":"83780c0c1954ef216896c9d8a48e412b357783e00ccd4909a7a249935c742629","src/front/glsl/types.rs":"286395d82707a09d28b4c1a8bade917822478e53d8eb277ceec5fa9e71649ba2","src/front/glsl/variables.rs":"320f79e066631431d428b313d85594bf98a5b47009678e67d8ab6daa0e0752ab","src/front/interpolator.rs":"caf8c8c3ddca56fbece33cc18615c4d8c5b3b68112c9de22196d9dd49c84bf96","src/front/mod.rs":"fddd2be54ff44b52743ac8eb4a19e153a8a169af8e65d9061a9b9fc9857f64db","src/front/spv/convert.rs":"2e649c93ed5aff83b2e5d6a0daa8772baffdb5558d2b423bf23bf17fdf9e893e","src/front/spv/error.rs":"d08e1d65716ccc0f2a94a1285a1d034fa4840dc79ca60a5ec7481697bdec74d1","src/front/spv/function.rs":"55a3f0fa17f6acc71feb36ebb29e1254d056f797ec420f8c535f6ef8ddce3790","src/front/spv/image.rs":"c39ffdb19a19861cec009de39431a879be99bdd4d9d08c0ecdef397c2f3f6fa5","src/front/spv/mod.rs":"b07d855765f3522b1b8b1e33cd00aa081408b94fa878b56ecd53b1e75728b65d","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"111832af89a268ae3206d2ba2159b9b9d64224ed09375a29eec142725ea7fb34","src/front/wgsl/error.rs":"60c7113a98f5642dc31ff23d20d8f533ee3fa80e88246a6e277615e7b9efa0f1","src/front/wgsl/index.rs":"476e5c4eddb14dfb53eee7976bcf4276c8a3fad81fbed92dc7b5dd31a5ab1593","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"2fa19ef6239ea37101ff234652fc61de6bc291da37e7b24cddd80cfcbd4942c8","src/front/wgsl/mod.rs":"95d38b0a49833638a06ac35c6df30c8fd3dcfa5494871e6d166f7e70f54b8fa3","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"4da994543503af097312ad94908c794a3e1d2bebd73c0ca64ee432e751b0f48a","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"99aaeb71f33363a6a57acdbb94ffedcace3ab2ebba2d7841e9444f8ce0fca749","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"560870a843951191dcb422be6e083f16c6e0109b97fa77d225bf588124822f57","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"05bf78f672e54ca335ed8be59ddfb1504289ee7444258cf2d30823687a418864","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"dbdf40511def9cdbc46872fd88f8f4e5c58fe37de120162542b8f4e99f6ab299","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"7236f0e751066712970b4f3dc9942b41d678c6a6e202c7da834f4f398e7cc657","src/lib.rs":"1e40237435eebd4a91fd5c9b2e8a58664ebd1c40a0d27c0c5220047f0221704a","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/proc/constant_evaluator.rs":"6fa4c03f8e756ae39b44db9537870663e81537a19beac3599cdce41ffc81c6b1","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"17c22571251996583b724af87c7d238f584cd39104256c8e90de7b18e737bb09","src/proc/keyword_set.rs":"928414d2b79ee48735d532e03d3f0a58427c3f27a2a0c6938425749b00943784","src/proc/layouter.rs":"78a91c2c9406c0319a344cc8ec9eda33ed7812ef4a4e73e25f7709afde580381","src/proc/mod.rs":"c2d52a7a18ec93b72468b0edf9d650ab793a15dee55ca741092e5f95cb96cd4b","src/proc/namer.rs":"f2c11c6d29d4a991fc9a08cf4531acdd309b6a9fef1c06198cc08193dc03a01d","src/proc/overloads/any_overload_set.rs":"877cd637d979abc08caa021dabb9821a79fc9109eb97024a230bcfac82830388","src/proc/overloads/constructor_set.rs":"b702f866ac1472bcc075bd0bede450388123b5899431934fd60a29865498c68b","src/proc/overloads/list.rs":"7cfbf66a3619fdd66f9acf652d56cd2a9451f7905c5d4637cdb9f77f4ef2af51","src/proc/overloads/mathfunction.rs":"d5801d64d1a6fd10e0da30a7c0ac7368954654e5f3d0b022fa806ff9a2ab61b8","src/proc/overloads/mod.rs":"0e96479cbd0ec9fa8200a5e88c16a22ee7ed2021ecf6f80a7e4ded69cad5239f","src/proc/overloads/one_bits_iter.rs":"6b98769fdec777d311248084f13958c5cca44659d0928603ece8618387ea58b2","src/proc/overloads/regular.rs":"73d64fab79019d589cb0595d0ef606fd6af732c42a418c60c81da4c96e113c89","src/proc/overloads/rule.rs":"b7f87d5ca0cffdaa8ee0db0110918f5a726359fd8a72bc638d8ce27a4b0ae3b2","src/proc/overloads/scalar_set.rs":"3729bc754dbf29a2337379ecb46568fdc3149a48074a354244da91e3d9cb5cef","src/proc/overloads/utils.rs":"4b5e02f20611bd24c6849e1f2c01aad4b271388407e8eb866d5a34983538ef8f","src/proc/terminator.rs":"1ea31a26b3316bfdd105cb181f55bc0aa448ea642fe9372d131bb788386d2a1f","src/proc/type_methods.rs":"fef829acb2da08a22a2e30dc356e7a8b9149ef13582525bea0143c687a1c57dd","src/proc/typifier.rs":"a31a97013838e43d31cef69b032680187ac709e13db0bf8fc85f4e8e11f236cf","src/racy_lock.rs":"6c541795172660e02bac86c3808cf7346b4791910febc0d289bf93d36271d416","src/span.rs":"e91190a7cd116fb811a295dcf9cd796a25b886cc5d35c3756771e3bc61768455","src/valid/analyzer.rs":"dda1e7f940431afc5f87a299e8fee3142e658629faa09c8b23bfc8fdb33dc309","src/valid/compose.rs":"46eeed8c4d5b66fc043ddb701074bd864a9fdd24e38b88e282046230acefb747","src/valid/expression.rs":"f8d9e3e20d21ddb9ade2e793d590631bcf4e7c135804a0130302d57212521f6f","src/valid/function.rs":"5b7ae29b5050f8231da7430a51753b52550b9c18fd9f15ef5e5074d01698b547","src/valid/handles.rs":"da60838b8badfc822cb176aecb65adc1594cb543964cf9f79e33a745bb456903","src/valid/interface.rs":"49a8efdcc57cc0c36ab845d462f9b1eb0f952e35eb80da34b38bcd76d80ead53","src/valid/mod.rs":"d6754af97573061d9f54e65ebeb55cc33f648fed8c746a871598d981c0d34216","src/valid/type.rs":"6f686499f1ab5bd68dd80977d0983006b19be4fafaf302454a9ba7619c623b70"},"package":null} -\ No newline at end of file +{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"16c70c2205a241af1934fa82693b68dd82b53777e349465be5b79991b8374848","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"baaed995bcbd2f7d15bd63cede28e579175d408e5a40289f74b32ab65c6850c3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"0e2d1c372a7c40b77793dc413b8920e86459e4656775a010f32974b4ad67a7fd","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"3f63a91f4afde7bedb3163489a347ccfa4b833e1fc7a0f33ccd8817efc7d303a","src/back/glsl/features.rs":"f187af71341bf9f853b019990ca211cdf6b5b57121a4dda33d609f21f8f828ad","src/back/glsl/keywords.rs":"fee8ed132e44bace54869a7c169a1ab7ed55db1bf590b4b1bce9efa4552e1dd7","src/back/glsl/mod.rs":"878db45fd458577b0d4ee55d0c2a5786847386d567cceb35750ecf14d54ab151","src/back/hlsl/conv.rs":"5da58838c166b753f135689a72b2bb46811269303c6104f8f483eeed93332ec3","src/back/hlsl/help.rs":"12ddb9d08fe64eb34b66ae2166edffce5106a04ccef0b8cc0391a6fafd676270","src/back/hlsl/keywords.rs":"f7fc06c44d2f0d620bcf1a02b699c98c32059741b771a0d1ba5645d71b2f433f","src/back/hlsl/mod.rs":"cbba2f7b5a3c7247c16422f0ce61c1ae4ce20edab8f8a4f2f29a219651606a7b","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"5083d03b1f25fe767e45e0c507bd30424352fccd48484c081620712d3682aae8","src/back/hlsl/writer.rs":"76667184d1e3f75b4f47ec9754fd5dad2bef7a3e11a3a8296b4adb36d235a5b1","src/back/mod.rs":"e4fdfcd2baba2f805422852753a9892a3d2b6449928265f061902f91bea90463","src/back/msl/keywords.rs":"b3e5d86d2586d553ff0fc6d91a25f0f4726c829d280a65dd2deeeb146cbbaf6d","src/back/msl/mod.rs":"274cdd070e0df4d65f555afac5a6de2c04bffa5fe39699ecead83d4acdbc8890","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"cd4cb7524a5802a1217f3438e005db290941fac2e0bdbe706b798b9d03e4cdf6","src/back/pipeline_constants.rs":"2d1ac050e587d23adc785ebcfe7120e743878101a63c4af4e62a88641fde5b43","src/back/spv/block.rs":"8a60f872f700e132e698d744e017b54bddca8cb176ac5e377a646bd639b44124","src/back/spv/f16_polyfill.rs":"44ce07ef497dff13a9152eb9bc5936c486ef53de6d476da6b0a39396b0e6abdb","src/back/spv/helpers.rs":"8b430ceb6722a1542ab95e581f11277eff38d0041e98b97ce9681541491e1a28","src/back/spv/image.rs":"105b5f8286d6afaabbb6fd7a5f86380274bae4011f3ba28c4f860c3694678557","src/back/spv/index.rs":"c410c0596c047c278def6b073a6373d233d53642a4c3f5a9be8cb53ca23d9c7d","src/back/spv/instructions.rs":"52a8b9fcb9bfc41dbfb75a03f3132df110cd33ae4d60ba8e9cf45083b4fe2da2","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"bb0186f8fa49be2e8f746e591c6153099bd5642ca658667f7f3d3496a8702939","src/back/spv/ray.rs":"064a4e13f55f5ca17876e32d6afb6bf8f58ad79104e81f2a4bee0bc6b731cac1","src/back/spv/recyclable.rs":"8ea397d4d8d3f2cd5fbc8e0be94d136c2d6e0f0e8a4b5eb567dcc1be104c9ae5","src/back/spv/selection.rs":"aea4bb4da7c0fa4e907b8f1e185433a48f2f0eb7ded97fdd3225beb3f6c1f249","src/back/spv/subgroup.rs":"68fc3e3153022a0a8bddec20ad9221820678f02921878318e571d5aa2ca13cee","src/back/spv/writer.rs":"588010f31591015c91558a15c6e53c28cb231f653f8cf70cf6f898bce03e848f","src/back/wgsl/mod.rs":"1b04d66e8dba609513d43431d1f0ee9a209fbfd8453862d6e8a7aa41f8910997","src/back/wgsl/polyfill/inverse/inverse_2x2_f16.wgsl":"9e7635d04724822931c805a8b35e76d6d294d447e4ea8d57b308ce45609bf736","src/back/wgsl/polyfill/inverse/inverse_2x2_f32.wgsl":"340d491abde07f93996391796db65a5f88402663eaf6b9d2d894d11cb8cf8b6d","src/back/wgsl/polyfill/inverse/inverse_3x3_f16.wgsl":"4f13a1a4b3e1b51f0f992d13c55cf854a80917554a4d13c997819fa1fe776ba4","src/back/wgsl/polyfill/inverse/inverse_3x3_f32.wgsl":"9b16d2f4b9e433c8e03a0cb46ab48508f3bf7e185ce1b4e26106c47e81a677cb","src/back/wgsl/polyfill/inverse/inverse_4x4_f16.wgsl":"86d39d1db5d03995b404950279db7f1698ad9622982aa319fdedb7532673235b","src/back/wgsl/polyfill/inverse/inverse_4x4_f32.wgsl":"dc510525ac2dce66389a8c4bf8b2f31f0dedd9e6debdbe4ffd939a0a7fc533d3","src/back/wgsl/polyfill/mod.rs":"f4ab3c9b9cdc36d16dab00d0f7f07d6e6beda0e27a36053e9b5ffeeb7ca18edc","src/back/wgsl/writer.rs":"2607b42f85a7f365f3b3965f60c9b0c0a102dc4135634a1da03ce374767f59da","src/common/diagnostic_debug.rs":"8c73fe605e5b6162d0485e264287ac50c061cf581743feebbffe1474d1d3516d","src/common/diagnostic_display.rs":"46f1ff8a32179703ef0bcdb704db9f6e6e8b4eaad6cadf94577eeab3d8a16cd1","src/common/mod.rs":"289231637b08407fbe2cc976a1bab4eac4c9e66042c6618aff3af44baaff3e26","src/common/predeclared.rs":"a5f42d55f2e13d8f5a8213d4a881e9155c3994c4054d43edcf7bd7bb7c868ccf","src/common/wgsl/diagnostics.rs":"4fec985b4c5cc6dfae4dd78bd7c850adc88a1761d7b6691de0355ea49300e532","src/common/wgsl/mod.rs":"d944915ff692c96aecca67737bccc2d5d9eb68f475166a2744f29a025f4a4c93","src/common/wgsl/to_wgsl.rs":"9055b193376e987d880f4c450465cb1ea34b560df8bf313fed445c901963c14c","src/common/wgsl/types.rs":"390323fecff390100fafcc2cb1e5cf349c7aac9da8065e9aec52a56718ab5534","src/compact/expressions.rs":"12653b34c7c7d68ce7d14a9c15e59c469fda4931425d14600fbaa99226af735f","src/compact/functions.rs":"27a0d33e5a8f02778b518c6e0db5a5d41f77a93b64eadef54b6cf0914067d7ad","src/compact/handle_set_map.rs":"b4688bff174487f2da4a1a946af07c80b6ba59f60dc84184c6a30039354209e8","src/compact/mod.rs":"1ace9291d919b0430e46184788a505513708506a5df40aacc96aece2c1e85cc9","src/compact/statements.rs":"85b2faf6a4caaebc0372e773ca3be2904db5bb0e691ac7ea845720ef0864a22b","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"46180b139b60cca1e46a8848f9eecc5cab8220a022e4c6f8ce297d1d968e87e7","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"76821d82b315ab6812e8411908885f0687ad98abfe0ea9f007e2deefed10cc0a","src/front/glsl/context.rs":"8314e1ed58b509788adbda82a8f4c7fbd2767522d0352ca1ebd11d86b4bfd10d","src/front/glsl/error.rs":"f445297e0357919e2345ae15f2d23c58d36a64c9a666f1cf1b09cbcfd6e4627a","src/front/glsl/functions.rs":"8040564f5429bf4be23e8dbd02c9cd3bbdd7eb8915b1b90ded6bc889db0b88c7","src/front/glsl/lex.rs":"24706628b600b5ce435cef464c84196ac5d58013122a97e7b59d509cc25f85a2","src/front/glsl/mod.rs":"132f2a60812b3910f65e6281562d4dc94efa329fd1eb0f2778ffe67631a35f78","src/front/glsl/offset.rs":"66bd524a2d17dc44f431430dcbbb74a771fdab43c9581e88bb1123e6cfec516b","src/front/glsl/parser.rs":"6a13b4737f53b09d5bbc0add01f8fc1b2633b7957f0318374edfe0b903939912","src/front/glsl/parser/declarations.rs":"9949649fba43636d03eaf7f7560d3bb3743b19c7204fb95859283ee84b5dd239","src/front/glsl/parser/expressions.rs":"e056fbdde3bc7c8473acbd485aecd14120d3dbefbabd813ddbc5cfedaf605889","src/front/glsl/parser/functions.rs":"302e24e06190aff555131c33f9a80b15df6a0390d6c776f888a44d5ef7df697e","src/front/glsl/parser/types.rs":"ee242048a65cd3709e16b70a3882e9296e615327480f2ad779e3d2523778181f","src/front/glsl/parser_tests.rs":"6834f0d595f4077266054e5da43e4f1b60e5c6780611ab0f530d9964cc62fad3","src/front/glsl/token.rs":"83780c0c1954ef216896c9d8a48e412b357783e00ccd4909a7a249935c742629","src/front/glsl/types.rs":"286395d82707a09d28b4c1a8bade917822478e53d8eb277ceec5fa9e71649ba2","src/front/glsl/variables.rs":"320f79e066631431d428b313d85594bf98a5b47009678e67d8ab6daa0e0752ab","src/front/interpolator.rs":"caf8c8c3ddca56fbece33cc18615c4d8c5b3b68112c9de22196d9dd49c84bf96","src/front/mod.rs":"fddd2be54ff44b52743ac8eb4a19e153a8a169af8e65d9061a9b9fc9857f64db","src/front/spv/convert.rs":"2e649c93ed5aff83b2e5d6a0daa8772baffdb5558d2b423bf23bf17fdf9e893e","src/front/spv/error.rs":"d08e1d65716ccc0f2a94a1285a1d034fa4840dc79ca60a5ec7481697bdec74d1","src/front/spv/function.rs":"55a3f0fa17f6acc71feb36ebb29e1254d056f797ec420f8c535f6ef8ddce3790","src/front/spv/image.rs":"c39ffdb19a19861cec009de39431a879be99bdd4d9d08c0ecdef397c2f3f6fa5","src/front/spv/mod.rs":"86141c03f83dfb26cff860eba0dde147da411f888bedbb894390c0d73dfc5e88","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"111832af89a268ae3206d2ba2159b9b9d64224ed09375a29eec142725ea7fb34","src/front/wgsl/error.rs":"0b55d5b881888f3cb7001942012f1a6815aaea7b60b3362583947d5ea19e5680","src/front/wgsl/index.rs":"476e5c4eddb14dfb53eee7976bcf4276c8a3fad81fbed92dc7b5dd31a5ab1593","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"4fa491f4c487ce8d43ae623a060179a17685f185ffa51a8f7bf62aaffa117040","src/front/wgsl/mod.rs":"95d38b0a49833638a06ac35c6df30c8fd3dcfa5494871e6d166f7e70f54b8fa3","src/front/wgsl/parse/ast.rs":"acc31dd4d5f3b784db77ff408856cefb9794e6238ca84e59d0483542396cc063","src/front/wgsl/parse/conv.rs":"7292892e3731927d55431c98e86fb532c02a9d334c5e1418701b023d6cdc9d4b","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"9417a7c5ab332d41d306ade6e141bfca0ab834675862f12679f6a0f302dbba7b","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"afe2ab904cce536fc2672942f081c1df93896e47d2511388eb1a986c9ffdfb87","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"05bf78f672e54ca335ed8be59ddfb1504289ee7444258cf2d30823687a418864","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"92dccb73b824669d6b37ec8ab1d4e9cf1701c259fd8daa1293e3ea08da3d7b0d","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"7236f0e751066712970b4f3dc9942b41d678c6a6e202c7da834f4f398e7cc657","src/lib.rs":"1e40237435eebd4a91fd5c9b2e8a58664ebd1c40a0d27c0c5220047f0221704a","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/proc/constant_evaluator.rs":"6fa4c03f8e756ae39b44db9537870663e81537a19beac3599cdce41ffc81c6b1","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"17c22571251996583b724af87c7d238f584cd39104256c8e90de7b18e737bb09","src/proc/keyword_set.rs":"928414d2b79ee48735d532e03d3f0a58427c3f27a2a0c6938425749b00943784","src/proc/layouter.rs":"78a91c2c9406c0319a344cc8ec9eda33ed7812ef4a4e73e25f7709afde580381","src/proc/mod.rs":"22c424050903e566546095632fc6277784da35065255bd652fc1b86119f2c79f","src/proc/namer.rs":"f2c11c6d29d4a991fc9a08cf4531acdd309b6a9fef1c06198cc08193dc03a01d","src/proc/overloads/any_overload_set.rs":"877cd637d979abc08caa021dabb9821a79fc9109eb97024a230bcfac82830388","src/proc/overloads/constructor_set.rs":"b702f866ac1472bcc075bd0bede450388123b5899431934fd60a29865498c68b","src/proc/overloads/list.rs":"7cfbf66a3619fdd66f9acf652d56cd2a9451f7905c5d4637cdb9f77f4ef2af51","src/proc/overloads/mathfunction.rs":"d5801d64d1a6fd10e0da30a7c0ac7368954654e5f3d0b022fa806ff9a2ab61b8","src/proc/overloads/mod.rs":"0e96479cbd0ec9fa8200a5e88c16a22ee7ed2021ecf6f80a7e4ded69cad5239f","src/proc/overloads/one_bits_iter.rs":"6b98769fdec777d311248084f13958c5cca44659d0928603ece8618387ea58b2","src/proc/overloads/regular.rs":"73d64fab79019d589cb0595d0ef606fd6af732c42a418c60c81da4c96e113c89","src/proc/overloads/rule.rs":"b7f87d5ca0cffdaa8ee0db0110918f5a726359fd8a72bc638d8ce27a4b0ae3b2","src/proc/overloads/scalar_set.rs":"3729bc754dbf29a2337379ecb46568fdc3149a48074a354244da91e3d9cb5cef","src/proc/overloads/utils.rs":"4b5e02f20611bd24c6849e1f2c01aad4b271388407e8eb866d5a34983538ef8f","src/proc/terminator.rs":"61df2289408be24f69b6c23da469ca3f63f913568f8c314427c3571b826632dd","src/proc/type_methods.rs":"fef829acb2da08a22a2e30dc356e7a8b9149ef13582525bea0143c687a1c57dd","src/proc/typifier.rs":"a31a97013838e43d31cef69b032680187ac709e13db0bf8fc85f4e8e11f236cf","src/racy_lock.rs":"6c541795172660e02bac86c3808cf7346b4791910febc0d289bf93d36271d416","src/span.rs":"e91190a7cd116fb811a295dcf9cd796a25b886cc5d35c3756771e3bc61768455","src/valid/analyzer.rs":"847b9b997a64f36c43ea608066a74246bcbda596e72cd23a4204243b1cf6ecf4","src/valid/compose.rs":"46eeed8c4d5b66fc043ddb701074bd864a9fdd24e38b88e282046230acefb747","src/valid/expression.rs":"f8d9e3e20d21ddb9ade2e793d590631bcf4e7c135804a0130302d57212521f6f","src/valid/function.rs":"4e7133aaa1903b473e45f819b1ac6a4d7789b22ffbf2d25655cb739c88bf774c","src/valid/handles.rs":"65ea8d24307f6eadabd772a9eb95416f64b410ea3150b8e2cf00574ef55d6c3a","src/valid/interface.rs":"9e174ff59621b305bd7202643ae86b50455aea35336fff0ba33f433d4de60b10","src/valid/mod.rs":"763c85d3b0922eaf017c87d247f1914525f86cd41977ac4c035ab306bef9bd6e","src/valid/type.rs":"6f686499f1ab5bd68dd80977d0983006b19be4fafaf302454a9ba7619c623b70"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/naga/src/back/dot/mod.rs b/third_party/rust/naga/src/back/dot/mod.rs @@ -307,25 +307,6 @@ impl StatementGraph { crate::RayQueryFunction::Terminate => "RayQueryTerminate", } } - S::MeshFunction(crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - }) => { - self.dependencies.push((id, vertex_count, "vertex_count")); - self.dependencies - .push((id, primitive_count, "primitive_count")); - "SetMeshOutputs" - } - S::MeshFunction(crate::MeshFunction::SetVertex { index, value }) => { - self.dependencies.push((id, index, "index")); - self.dependencies.push((id, value, "value")); - "SetVertex" - } - S::MeshFunction(crate::MeshFunction::SetPrimitive { index, value }) => { - self.dependencies.push((id, index, "index")); - self.dependencies.push((id, value, "value")); - "SetPrimitive" - } S::SubgroupBallot { result, predicate } => { if let Some(predicate) = predicate { self.dependencies.push((id, predicate, "predicate")); diff --git a/third_party/rust/naga/src/back/glsl/mod.rs b/third_party/rust/naga/src/back/glsl/mod.rs @@ -2675,11 +2675,6 @@ impl<'a, W: Write> Writer<'a, W> { self.write_image_atomic(ctx, image, coordinate, array_index, fun, value)? } Statement::RayQuery { .. } => unreachable!(), - Statement::MeshFunction( - crate::MeshFunction::SetMeshOutputs { .. } - | crate::MeshFunction::SetVertex { .. } - | crate::MeshFunction::SetPrimitive { .. }, - ) => unreachable!(), Statement::SubgroupBallot { result, predicate } => { write!(self.out, "{level}")?; let res_name = Baked(result).to_string(); @@ -5270,7 +5265,11 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s | Bi::PointIndex | Bi::LineIndices | Bi::TriangleIndices - | Bi::MeshTaskSize => { + | Bi::MeshTaskSize + | Bi::VertexCount + | Bi::PrimitiveCount + | Bi::Vertices + | Bi::Primitives => { unimplemented!() } } diff --git a/third_party/rust/naga/src/back/hlsl/conv.rs b/third_party/rust/naga/src/back/hlsl/conv.rs @@ -187,7 +187,11 @@ impl crate::BuiltIn { } Self::CullPrimitive => "SV_CullPrimitive", Self::PointIndex | Self::LineIndices | Self::TriangleIndices => unimplemented!(), - Self::MeshTaskSize => unreachable!(), + Self::MeshTaskSize + | Self::VertexCount + | Self::PrimitiveCount + | Self::Vertices + | Self::Primitives => unreachable!(), }) } } diff --git a/third_party/rust/naga/src/back/hlsl/writer.rs b/third_party/rust/naga/src/back/hlsl/writer.rs @@ -2608,19 +2608,6 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { writeln!(self.out, ".Abort();")?; } }, - Statement::MeshFunction(crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - }) => { - write!(self.out, "{level}SetMeshOutputCounts(")?; - self.write_expr(module, vertex_count, func_ctx)?; - write!(self.out, ", ")?; - self.write_expr(module, primitive_count, func_ctx)?; - write!(self.out, ");")?; - } - Statement::MeshFunction( - crate::MeshFunction::SetVertex { .. } | crate::MeshFunction::SetPrimitive { .. }, - ) => unimplemented!(), Statement::SubgroupBallot { result, predicate } => { write!(self.out, "{level}")?; let name = Baked(result).to_string(); diff --git a/third_party/rust/naga/src/back/msl/mod.rs b/third_party/rust/naga/src/back/msl/mod.rs @@ -714,7 +714,11 @@ impl ResolvedBinding { Bi::CullPrimitive => "primitive_culled", // TODO: figure out how to make this written as a function call Bi::PointIndex | Bi::LineIndices | Bi::TriangleIndices => unimplemented!(), - Bi::MeshTaskSize => unreachable!(), + Bi::MeshTaskSize + | Bi::VertexCount + | Bi::PrimitiveCount + | Bi::Vertices + | Bi::Primitives => unreachable!(), }; write!(out, "{name}")?; } diff --git a/third_party/rust/naga/src/back/msl/writer.rs b/third_party/rust/naga/src/back/msl/writer.rs @@ -4063,14 +4063,6 @@ impl<W: Write> Writer<W> { } } } - // TODO: write emitters for these - crate::Statement::MeshFunction(crate::MeshFunction::SetMeshOutputs { .. }) => { - unimplemented!() - } - crate::Statement::MeshFunction( - crate::MeshFunction::SetVertex { .. } - | crate::MeshFunction::SetPrimitive { .. }, - ) => unimplemented!(), crate::Statement::SubgroupBallot { result, predicate } => { write!(self.out, "{level}")?; let name = self.namer.call(""); diff --git a/third_party/rust/naga/src/back/pipeline_constants.rs b/third_party/rust/naga/src/back/pipeline_constants.rs @@ -860,26 +860,6 @@ fn adjust_stmt(new_pos: &HandleVec<Expression, Handle<Expression>>, stmt: &mut S crate::RayQueryFunction::Terminate => {} } } - Statement::MeshFunction(crate::MeshFunction::SetMeshOutputs { - ref mut vertex_count, - ref mut primitive_count, - }) => { - adjust(vertex_count); - adjust(primitive_count); - } - Statement::MeshFunction( - crate::MeshFunction::SetVertex { - ref mut index, - ref mut value, - } - | crate::MeshFunction::SetPrimitive { - ref mut index, - ref mut value, - }, - ) => { - adjust(index); - adjust(value); - } Statement::Break | Statement::Continue | Statement::Kill diff --git a/third_party/rust/naga/src/back/spv/block.rs b/third_party/rust/naga/src/back/spv/block.rs @@ -203,7 +203,7 @@ impl Writer { )); let clamp_id = self.id_gen.next(); - body.push(Instruction::ext_inst( + body.push(Instruction::ext_inst_gl_op( self.gl450_ext_inst_id, spirv::GLOp::FClamp, float_type_id, @@ -1026,7 +1026,7 @@ impl BlockContext<'_> { }; let max_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, max_op, result_type_id, @@ -1034,7 +1034,7 @@ impl BlockContext<'_> { &[arg0_id, arg1_id], )); - MathOp::Custom(Instruction::ext_inst( + MathOp::Custom(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, min_op, result_type_id, @@ -1068,7 +1068,7 @@ impl BlockContext<'_> { arg2_id = self.writer.get_constant_composite(ty, &self.temp_list); } - MathOp::Custom(Instruction::ext_inst( + MathOp::Custom(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::FClamp, result_type_id, @@ -1282,7 +1282,7 @@ impl BlockContext<'_> { &self.temp_list, )); - MathOp::Custom(Instruction::ext_inst( + MathOp::Custom(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::FMix, result_type_id, @@ -1339,7 +1339,7 @@ impl BlockContext<'_> { }; let lsb_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::FindILsb, result_type_id, @@ -1347,7 +1347,7 @@ impl BlockContext<'_> { &[arg0_id], )); - MathOp::Custom(Instruction::ext_inst( + MathOp::Custom(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, result_type_id, @@ -1388,7 +1388,7 @@ impl BlockContext<'_> { }; let msb_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, if width != 4 { spirv::GLOp::FindILsb @@ -1445,7 +1445,7 @@ impl BlockContext<'_> { // o = min(offset, w) let offset_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, u32_type, @@ -1465,7 +1465,7 @@ impl BlockContext<'_> { // c = min(count, tmp) let count_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, u32_type, @@ -1495,7 +1495,7 @@ impl BlockContext<'_> { // o = min(offset, w) let offset_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, u32_type, @@ -1515,7 +1515,7 @@ impl BlockContext<'_> { // c = min(count, tmp) let count_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, u32_type, @@ -1610,7 +1610,7 @@ impl BlockContext<'_> { }; block.body.push(match math_op { - MathOp::Ext(op) => Instruction::ext_inst( + MathOp::Ext(op) => Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, op, result_type_id, @@ -1621,7 +1621,27 @@ impl BlockContext<'_> { }); id } - crate::Expression::LocalVariable(variable) => self.function.variables[&variable].id, + crate::Expression::LocalVariable(variable) => { + if let Some(rq_tracker) = self + .function + .ray_query_initialization_tracker_variables + .get(&variable) + { + self.ray_query_tracker_expr.insert( + expr_handle, + super::RayQueryTrackers { + initialized_tracker: rq_tracker.id, + t_max_tracker: self + .function + .ray_query_t_max_tracker_variables + .get(&variable) + .expect("Both trackers are set at the same time.") + .id, + }, + ); + } + self.function.variables[&variable].id + } crate::Expression::Load { pointer } => { self.write_checked_load(pointer, block, AccessTypeAdjustment::None, result_type_id)? } @@ -1772,6 +1792,10 @@ impl BlockContext<'_> { crate::Expression::ArrayLength(expr) => self.write_runtime_array_length(expr, block)?, crate::Expression::RayQueryGetIntersection { query, committed } => { let query_id = self.cached[query]; + let init_tracker_id = *self + .ray_query_tracker_expr + .get(&query) + .expect("not a cached ray query"); let func_id = self .writer .write_ray_query_get_intersection_function(committed, self.ir_module); @@ -1782,7 +1806,7 @@ impl BlockContext<'_> { intersection_type_id, id, func_id, - &[query_id], + &[query_id, init_tracker_id.initialized_tracker], )); id } @@ -2008,7 +2032,7 @@ impl BlockContext<'_> { let max_const_id = maybe_splat_const(self.writer, max_const_id); let clamp_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::FClamp, expr_type_id, @@ -2671,7 +2695,7 @@ impl BlockContext<'_> { }); let clamp_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, clamp_op, wide_vector_type_id, @@ -2765,7 +2789,7 @@ impl BlockContext<'_> { let [min, max] = [min, max].map(|lit| self.writer.get_constant_scalar(lit)); let clamp_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, clamp_op, result_type_id, @@ -3655,7 +3679,6 @@ impl BlockContext<'_> { } => { self.write_subgroup_gather(mode, argument, result, &mut block)?; } - Statement::MeshFunction(_) => unreachable!(), } } diff --git a/third_party/rust/naga/src/back/spv/image.rs b/third_party/rust/naga/src/back/spv/image.rs @@ -446,7 +446,7 @@ impl BlockContext<'_> { // and negative values in a single instruction: negative values of // `input_id` get treated as very large positive values. let restricted_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, type_id, @@ -580,7 +580,7 @@ impl BlockContext<'_> { // and negative values in a single instruction: negative values of // `coordinates` get treated as very large positive values. let restricted_coordinates_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, coordinates.type_id, @@ -923,7 +923,7 @@ impl BlockContext<'_> { // Clamp the coords to the calculated margins let clamped_coords_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::NClamp, vec2f_type_id, diff --git a/third_party/rust/naga/src/back/spv/index.rs b/third_party/rust/naga/src/back/spv/index.rs @@ -366,7 +366,7 @@ impl BlockContext<'_> { // One or the other of the index or length is dynamic, so emit code for // BoundsCheckPolicy::Restrict. let restricted_index_id = self.gen_id(); - block.body.push(Instruction::ext_inst( + block.body.push(Instruction::ext_inst_gl_op( self.writer.gl450_ext_inst_id, spirv::GLOp::UMin, self.writer.get_u32_type_id(), diff --git a/third_party/rust/naga/src/back/spv/instructions.rs b/third_party/rust/naga/src/back/spv/instructions.rs @@ -156,18 +156,28 @@ impl super::Instruction { instruction } - pub(super) fn ext_inst( + pub(super) fn ext_inst_gl_op( set_id: Word, op: spirv::GLOp, result_type_id: Word, id: Word, operands: &[Word], ) -> Self { + Self::ext_inst(set_id, op as u32, result_type_id, id, operands) + } + + pub(super) fn ext_inst( + set_id: Word, + op: u32, + result_type_id: Word, + id: Word, + operands: &[Word], + ) -> Self { let mut instruction = Self::new(Op::ExtInst); instruction.set_type(result_type_id); instruction.set_result(id); instruction.add_operand(set_id); - instruction.add_operand(op as u32); + instruction.add_operand(op); for operand in operands { instruction.add_operand(*operand) } @@ -824,6 +834,14 @@ impl super::Instruction { instruction } + pub(super) fn ray_query_get_t_min(result_type_id: Word, id: Word, query: Word) -> Self { + let mut instruction = Self::new(Op::RayQueryGetRayTMinKHR); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(query); + instruction + } + // // Conversion Instructions // diff --git a/third_party/rust/naga/src/back/spv/mod.rs b/third_party/rust/naga/src/back/spv/mod.rs @@ -151,6 +151,12 @@ struct Function { signature: Option<Instruction>, parameters: Vec<FunctionArgument>, variables: crate::FastHashMap<Handle<crate::LocalVariable>, LocalVariable>, + /// Map from a local variable that is a ray query to its u32 tracker. + ray_query_initialization_tracker_variables: + crate::FastHashMap<Handle<crate::LocalVariable>, LocalVariable>, + /// Map from a local variable that is a ray query to its tracker for the t max. + ray_query_t_max_tracker_variables: + crate::FastHashMap<Handle<crate::LocalVariable>, LocalVariable>, /// List of local variables used as a counters to ensure that all loops are bounded. force_loop_bounding_vars: Vec<LocalVariable>, @@ -445,6 +451,16 @@ struct LookupFunctionType { return_type_id: Word, } +#[derive(Debug, PartialEq, Clone, Hash, Eq)] +enum LookupRayQueryFunction { + Initialize, + Proceed, + GenerateIntersection, + ConfirmIntersection, + GetVertexPositions { committed: bool }, + GetIntersection { committed: bool }, +} + #[derive(Debug)] enum Dimension { Scalar, @@ -685,6 +701,21 @@ struct BlockContext<'w> { expression_constness: ExpressionConstnessTracker, force_loop_bounding: bool, + + /// Hash from an expression whose type is a ray query / pointer to a ray query to its tracker. + /// Note: this is sparse, so can't be a handle vec + ray_query_tracker_expr: crate::FastHashMap<Handle<crate::Expression>, RayQueryTrackers>, +} + +#[derive(Clone, Copy)] +struct RayQueryTrackers { + // Initialization tracker + initialized_tracker: Word, + // Tracks the t max from ray query initialize. + // Unlike HLSL, spir-v's equivalent getter for the current committed t has UB (instead of just + // returning t_max) if there was no previous hit (though in some places it treats the behaviour as + // defined), therefore we must track the tmax inputted into ray query initialize. + t_max_tracker: Word, } impl BlockContext<'_> { @@ -741,6 +772,7 @@ pub struct Writer { /// The set of spirv extensions used. extensions_used: crate::FastIndexSet<&'static str>, + debug_strings: Vec<Instruction>, debugs: Vec<Instruction>, annotations: Vec<Instruction>, flags: WriterFlags, @@ -773,12 +805,15 @@ pub struct Writer { // Just a temporary list of SPIR-V ids temp_list: Vec<Word>, - ray_get_committed_intersection_function: Option<Word>, - ray_get_candidate_intersection_function: Option<Word>, + ray_query_functions: crate::FastHashMap<LookupRayQueryFunction, Word>, /// F16 I/O polyfill manager for handling `f16` input/output variables /// when `StorageInputOutput16` capability is not available. io_f16_polyfills: f16_polyfill::F16IoPolyfill, + + /// Non semantic debug printf extension `OpExtInstImport` + debug_printf: Option<Word>, + pub(crate) ray_query_initialization_tracking: bool, } bitflags::bitflags! { @@ -810,6 +845,26 @@ bitflags::bitflags! { /// /// [`BuiltIn::FragDepth`]: crate::BuiltIn::FragDepth const CLAMP_FRAG_DEPTH = 0x10; + + /// Instead of silently failing if the arguments to generate a ray query are + /// invalid, uses debug printf extension to print to the command line + /// + /// Note: VK_KHR_shader_non_semantic_info must be enabled. This will have no + /// effect if `options.ray_query_initialization_tracking` is set to false. + const PRINT_ON_RAY_QUERY_INITIALIZATION_FAIL = 0x20; + } +} + +bitflags::bitflags! { + /// How far through a ray query are we + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub(super) struct RayQueryPoint: u32 { + /// Ray query has been successfully initialized. + const INITIALIZED = 1 << 0; + /// Proceed has been called on ray query. + const PROCEED = 1 << 1; + /// Proceed has returned false (have finished traversal). + const FINISHED_TRAVERSAL = 1 << 2; } } @@ -867,6 +922,10 @@ pub struct Options<'a> { /// to think the number of iterations is bounded. pub force_loop_bounding: bool, + /// if set, ray queries will get a variable to track their state to prevent + /// misuse. + pub ray_query_initialization_tracking: bool, + /// Whether to use the `StorageInputOutput16` capability for `f16` shader I/O. /// When false, `f16` I/O is polyfilled using `f32` types with conversions. pub use_storage_input_output_16: bool, @@ -891,6 +950,7 @@ impl Default for Options<'_> { bounds_check_policies: BoundsCheckPolicies::default(), zero_initialize_workgroup_memory: ZeroInitializeWorkgroupMemoryMode::Polyfill, force_loop_bounding: true, + ray_query_initialization_tracking: true, use_storage_input_output_16: true, debug_info: None, } diff --git a/third_party/rust/naga/src/back/spv/ray.rs b/third_party/rust/naga/src/back/spv/ray.rs @@ -2,27 +2,123 @@ Generating SPIR-V for ray query operations. */ -use alloc::vec; +use alloc::{vec, vec::Vec}; use super::{ Block, BlockContext, Function, FunctionArgument, Instruction, LookupFunctionType, NumericType, Writer, }; -use crate::arena::Handle; +use crate::{arena::Handle, back::spv::LookupRayQueryFunction}; + +/// helper function to check if a particular flag is set in a u32. +fn write_ray_flags_contains_flags( + writer: &mut Writer, + block: &mut Block, + id: spirv::Word, + flag: u32, +) -> spirv::Word { + let bit_id = writer.get_constant_scalar(crate::Literal::U32(flag)); + let zero_id = writer.get_constant_scalar(crate::Literal::U32(0)); + let u32_type_id = writer.get_u32_type_id(); + let bool_ty = writer.get_bool_type_id(); + + let and_id = writer.id_gen.next(); + block.body.push(Instruction::binary( + spirv::Op::BitwiseAnd, + u32_type_id, + and_id, + id, + bit_id, + )); + + let eq_id = writer.id_gen.next(); + block.body.push(Instruction::binary( + spirv::Op::INotEqual, + bool_ty, + eq_id, + and_id, + zero_id, + )); + + eq_id +} impl Writer { + /// writes a logical and of two scalar booleans + fn write_logical_and( + &mut self, + block: &mut Block, + one: spirv::Word, + two: spirv::Word, + ) -> spirv::Word { + let id = self.id_gen.next(); + let bool_id = self.get_bool_type_id(); + block.body.push(Instruction::binary( + spirv::Op::LogicalAnd, + bool_id, + id, + one, + two, + )); + id + } + + fn write_reduce_and(&mut self, block: &mut Block, mut bools: Vec<spirv::Word>) -> spirv::Word { + // The combined `and`ed together of all of the bools up to this point. + let mut current_combined = bools.pop().unwrap(); + for boolean in bools { + current_combined = self.write_logical_and(block, current_combined, boolean) + } + current_combined + } + + // returns the id of the function, the function, and ids for its arguments. + fn write_function_signature( + &mut self, + arg_types: &[spirv::Word], + return_ty: spirv::Word, + ) -> (spirv::Word, Function, Vec<spirv::Word>) { + let func_ty = self.get_function_type(LookupFunctionType { + parameter_type_ids: Vec::from(arg_types), + return_type_id: return_ty, + }); + + let mut function = Function::default(); + let func_id = self.id_gen.next(); + function.signature = Some(Instruction::function( + return_ty, + func_id, + spirv::FunctionControl::empty(), + func_ty, + )); + + let mut arg_ids = Vec::with_capacity(arg_types.len()); + + for (idx, &arg_ty) in arg_types.iter().enumerate() { + let id = self.id_gen.next(); + let instruction = Instruction::function_parameter(arg_ty, id); + function.parameters.push(FunctionArgument { + instruction, + handle_id: idx as u32, + }); + arg_ids.push(id); + } + (func_id, function, arg_ids) + } + pub(super) fn write_ray_query_get_intersection_function( &mut self, is_committed: bool, ir_module: &crate::Module, ) -> spirv::Word { - if is_committed { - if let Some(func_id) = self.ray_get_committed_intersection_function { - return func_id; - } - } else if let Some(func_id) = self.ray_get_candidate_intersection_function { - return func_id; - }; + if let Some(&word) = + self.ray_query_functions + .get(&LookupRayQueryFunction::GetIntersection { + committed: is_committed, + }) + { + return word; + } let ray_intersection = ir_module.special_types.ray_intersection.unwrap(); let intersection_type_id = self.get_handle_type_id(ray_intersection); let intersection_pointer_type_id = @@ -56,31 +152,20 @@ impl Writer { let argument_type_id = self.get_ray_query_pointer_id(); - let func_ty = self.get_function_type(LookupFunctionType { - parameter_type_ids: vec![argument_type_id], - return_type_id: intersection_type_id, - }); - - let mut function = Function::default(); - let func_id = self.id_gen.next(); - function.signature = Some(Instruction::function( + let (func_id, mut function, arg_ids) = self.write_function_signature( + &[argument_type_id, flag_pointer_type_id], intersection_type_id, - func_id, - spirv::FunctionControl::empty(), - func_ty, - )); - let blank_intersection = self.get_constant_null(intersection_type_id); - let query_id = self.id_gen.next(); - let instruction = Instruction::function_parameter(argument_type_id, query_id); - function.parameters.push(FunctionArgument { - instruction, - handle_id: 0, - }); + ); + + let query_id = arg_ids[0]; + let intersection_tracker_id = arg_ids[1]; let label_id = self.id_gen.next(); let mut block = Block::new(label_id); + let blank_intersection = self.get_constant_null(intersection_type_id); let blank_intersection_id = self.id_gen.next(); + // This must be before everything else in the function. block.body.push(Instruction::variable( intersection_pointer_type_id, blank_intersection_id, @@ -93,14 +178,67 @@ impl Writer { } else { spirv::RayQueryIntersection::RayQueryCandidateIntersectionKHR } as _)); - let raw_kind_id = self.id_gen.next(); - block.body.push(Instruction::ray_query_get_intersection( - spirv::Op::RayQueryGetIntersectionTypeKHR, + + let loaded_ray_query_tracker_id = self.id_gen.next(); + block.body.push(Instruction::load( flag_type_id, - raw_kind_id, - query_id, - intersection_id, + loaded_ray_query_tracker_id, + intersection_tracker_id, + None, + )); + let proceeded_id = write_ray_flags_contains_flags( + self, + &mut block, + loaded_ray_query_tracker_id, + super::RayQueryPoint::PROCEED.bits(), + ); + let finished_proceed_id = write_ray_flags_contains_flags( + self, + &mut block, + loaded_ray_query_tracker_id, + super::RayQueryPoint::FINISHED_TRAVERSAL.bits(), + ); + let proceed_finished_correct_id = if is_committed { + finished_proceed_id + } else { + let not_finished_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + not_finished_id, + finished_proceed_id, + )); + not_finished_id + }; + + let is_valid_id = + self.write_logical_and(&mut block, proceed_finished_correct_id, proceeded_id); + + let valid_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_id); + + let final_label_id = self.id_gen.next(); + let mut final_block = Block::new(final_label_id); + + block.body.push(Instruction::selection_merge( + final_label_id, + spirv::SelectionControl::NONE, )); + function.consume( + block, + Instruction::branch_conditional(is_valid_id, valid_id, final_label_id), + ); + + let raw_kind_id = self.id_gen.next(); + valid_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTypeKHR, + flag_type_id, + raw_kind_id, + query_id, + intersection_id, + )); let kind_id = if is_committed { // Nothing to do: the IR value matches `spirv::RayQueryCommittedIntersectionType` raw_kind_id @@ -111,7 +249,7 @@ impl Writer { spirv::RayQueryCandidateIntersectionType::RayQueryCandidateIntersectionTriangleKHR as _, )); - block.body.push(Instruction::binary( + valid_block.body.push(Instruction::binary( spirv::Op::IEqual, self.get_bool_type_id(), condition_id, @@ -119,7 +257,7 @@ impl Writer { committed_triangle_kind_id, )); let kind_id = self.id_gen.next(); - block.body.push(Instruction::select( + valid_block.body.push(Instruction::select( flag_type_id, kind_id, condition_id, @@ -134,20 +272,20 @@ impl Writer { }; let idx_id = self.get_index_constant(0); let access_idx = self.id_gen.next(); - block.body.push(Instruction::access_chain( + valid_block.body.push(Instruction::access_chain( flag_pointer_type_id, access_idx, blank_intersection_id, &[idx_id], )); - block + valid_block .body .push(Instruction::store(access_idx, kind_id, None)); let not_none_comp_id = self.id_gen.next(); let none_id = self.get_constant_scalar(crate::Literal::U32(crate::RayQueryIntersection::None as _)); - block.body.push(Instruction::binary( + valid_block.body.push(Instruction::binary( spirv::Op::INotEqual, self.get_bool_type_id(), not_none_comp_id, @@ -158,16 +296,20 @@ impl Writer { let not_none_label_id = self.id_gen.next(); let mut not_none_block = Block::new(not_none_label_id); - let final_label_id = self.id_gen.next(); - let mut final_block = Block::new(final_label_id); + let outer_merge_label_id = self.id_gen.next(); + let outer_merge_block = Block::new(outer_merge_label_id); - block.body.push(Instruction::selection_merge( - final_label_id, + valid_block.body.push(Instruction::selection_merge( + outer_merge_label_id, spirv::SelectionControl::NONE, )); function.consume( - block, - Instruction::branch_conditional(not_none_comp_id, not_none_label_id, final_label_id), + valid_block, + Instruction::branch_conditional( + not_none_comp_id, + not_none_label_id, + outer_merge_label_id, + ), ); let instance_custom_index_id = self.id_gen.next(); @@ -426,7 +568,8 @@ impl Writer { .body .push(Instruction::store(access_idx, front_face_id, None)); function.consume(tri_block, Instruction::branch(merge_label_id)); - function.consume(merge_block, Instruction::branch(final_label_id)); + function.consume(merge_block, Instruction::branch(outer_merge_label_id)); + function.consume(outer_merge_block, Instruction::branch(final_label_id)); let loaded_blank_intersection_id = self.id_gen.next(); final_block.body.push(Instruction::load( @@ -441,151 +584,1321 @@ impl Writer { ); function.to_words(&mut self.logical_layout.function_definitions); - if is_committed { - self.ray_get_committed_intersection_function = Some(func_id); - } else { - self.ray_get_candidate_intersection_function = Some(func_id); - } + self.ray_query_functions.insert( + LookupRayQueryFunction::GetIntersection { + committed: is_committed, + }, + func_id, + ); func_id } -} -impl BlockContext<'_> { - pub(super) fn write_ray_query_function( - &mut self, - query: Handle<crate::Expression>, - function: &crate::RayQueryFunction, - block: &mut Block, - ) { - let query_id = self.cached[query]; - match *function { - crate::RayQueryFunction::Initialize { - acceleration_structure, - descriptor, - } => { - //Note: composite extract indices and types must match `generate_ray_desc_type` - let desc_id = self.cached[descriptor]; - let acc_struct_id = self.get_handle_id(acceleration_structure); + fn write_ray_query_initialize(&mut self, ir_module: &crate::Module) -> spirv::Word { + if let Some(&word) = self + .ray_query_functions + .get(&LookupRayQueryFunction::Initialize) + { + return word; + } - let flag_type_id = - self.get_numeric_type_id(NumericType::Scalar(crate::Scalar::U32)); - let ray_flags_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - flag_type_id, - ray_flags_id, - desc_id, - &[0], - )); - let cull_mask_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - flag_type_id, - cull_mask_id, - desc_id, - &[1], - )); + let ray_query_type_id = self.get_ray_query_pointer_id(); + let acceleration_structure_type_id = + self.get_localtype_id(super::LocalType::AccelerationStructure); + let ray_desc_type_id = self.get_handle_type_id( + ir_module + .special_types + .ray_desc + .expect("ray desc should be set if ray queries are being initialized"), + ); - let scalar_type_id = - self.get_numeric_type_id(NumericType::Scalar(crate::Scalar::F32)); - let tmin_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - scalar_type_id, - tmin_id, - desc_id, - &[2], - )); - let tmax_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - scalar_type_id, - tmax_id, - desc_id, - &[3], - )); + let u32_ty = self.get_u32_type_id(); + let u32_ptr_ty = self.get_pointer_type_id(u32_ty, spirv::StorageClass::Function); - let vector_type_id = self.get_numeric_type_id(NumericType::Vector { - size: crate::VectorSize::Tri, - scalar: crate::Scalar::F32, - }); - let ray_origin_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - vector_type_id, - ray_origin_id, - desc_id, - &[4], - )); - let ray_dir_id = self.gen_id(); - block.body.push(Instruction::composite_extract( - vector_type_id, - ray_dir_id, - desc_id, - &[5], - )); + let f32_type_id = self.get_f32_type_id(); + let f32_ptr_ty = self.get_pointer_type_id(f32_type_id, spirv::StorageClass::Function); - block.body.push(Instruction::ray_query_initialize( - query_id, - acc_struct_id, - ray_flags_id, - cull_mask_id, - ray_origin_id, - tmin_id, - ray_dir_id, - tmax_id, + let bool_type_id = self.get_bool_type_id(); + let bool_vec3_type_id = self.get_vec3_bool_type_id(); + + let (func_id, mut function, arg_ids) = self.write_function_signature( + &[ + ray_query_type_id, + acceleration_structure_type_id, + ray_desc_type_id, + u32_ptr_ty, + f32_ptr_ty, + ], + self.void_type, + ); + + let query_id = arg_ids[0]; + let acceleration_structure_id = arg_ids[1]; + let desc_id = arg_ids[2]; + let init_tracker_id = arg_ids[3]; + let t_max_tracker_id = arg_ids[4]; + + let label_id = self.id_gen.next(); + let mut block = Block::new(label_id); + + let flag_type_id = self.get_numeric_type_id(NumericType::Scalar(crate::Scalar::U32)); + + //Note: composite extract indices and types must match `generate_ray_desc_type` + let ray_flags_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + flag_type_id, + ray_flags_id, + desc_id, + &[0], + )); + let cull_mask_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + flag_type_id, + cull_mask_id, + desc_id, + &[1], + )); + + let tmin_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + f32_type_id, + tmin_id, + desc_id, + &[2], + )); + let tmax_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + f32_type_id, + tmax_id, + desc_id, + &[3], + )); + block + .body + .push(Instruction::store(t_max_tracker_id, tmax_id, None)); + + let vector_type_id = self.get_numeric_type_id(NumericType::Vector { + size: crate::VectorSize::Tri, + scalar: crate::Scalar::F32, + }); + let ray_origin_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + vector_type_id, + ray_origin_id, + desc_id, + &[4], + )); + let ray_dir_id = self.id_gen.next(); + block.body.push(Instruction::composite_extract( + vector_type_id, + ray_dir_id, + desc_id, + &[5], + )); + + let valid_id = self.ray_query_initialization_tracking.then(||{ + let tmin_le_tmax_id = self.id_gen.next(); + // Check both that tmin is less than or equal to tmax (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06350) + // and implicitly that neither tmin or tmax are NaN (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06351) + // because this checks if tmin and tmax are ordered too (i.e: not NaN). + block.body.push(Instruction::binary( + spirv::Op::FOrdLessThanEqual, + bool_type_id, + tmin_le_tmax_id, + tmin_id, + tmax_id, + )); + + // Check that tmin is greater than or equal to 0 (and + // therefore also tmax is too because it is greater than + // or equal to tmin) (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06349). + let tmin_ge_zero_id = self.id_gen.next(); + let zero_id = self.get_constant_scalar(crate::Literal::F32(0.0)); + block.body.push(Instruction::binary( + spirv::Op::FOrdGreaterThanEqual, + bool_type_id, + tmin_ge_zero_id, + tmin_id, + zero_id, + )); + + // Check that ray origin is finite (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06348) + let ray_origin_infinite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::IsInf, + bool_vec3_type_id, + ray_origin_infinite_id, + ray_origin_id, + )); + let any_ray_origin_infinite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::Any, + bool_type_id, + any_ray_origin_infinite_id, + ray_origin_infinite_id, + )); + + let ray_origin_nan_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::IsNan, + bool_vec3_type_id, + ray_origin_nan_id, + ray_origin_id, + )); + let any_ray_origin_nan_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::Any, + bool_type_id, + any_ray_origin_nan_id, + ray_origin_nan_id, + )); + + let ray_origin_not_finite_id = self.id_gen.next(); + block.body.push(Instruction::binary( + spirv::Op::LogicalOr, + bool_type_id, + ray_origin_not_finite_id, + any_ray_origin_nan_id, + any_ray_origin_infinite_id, + )); + + let all_ray_origin_finite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + all_ray_origin_finite_id, + ray_origin_not_finite_id, + )); + + // Check that ray direction is finite (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06348) + let ray_dir_infinite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::IsInf, + bool_vec3_type_id, + ray_dir_infinite_id, + ray_dir_id, + )); + let any_ray_dir_infinite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::Any, + bool_type_id, + any_ray_dir_infinite_id, + ray_dir_infinite_id, + )); + + let ray_dir_nan_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::IsNan, + bool_vec3_type_id, + ray_dir_nan_id, + ray_dir_id, + )); + let any_ray_dir_nan_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::Any, + bool_type_id, + any_ray_dir_nan_id, + ray_dir_nan_id, + )); + + let ray_dir_not_finite_id = self.id_gen.next(); + block.body.push(Instruction::binary( + spirv::Op::LogicalOr, + bool_type_id, + ray_dir_not_finite_id, + any_ray_dir_nan_id, + any_ray_dir_infinite_id, + )); + + let all_ray_dir_finite_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + all_ray_dir_finite_id, + ray_dir_not_finite_id, + )); + + /// Writes spirv to check that less than two booleans are true + /// + /// For each boolean: removes it, `and`s it with all others (i.e for all possible combinations of two booleans in the list checks to see if both are true). + /// Then `or`s all of these checks together. This produces whether two or more booleans are true. + fn write_less_than_2_true( + writer: &mut Writer, + block: &mut Block, + mut bools: Vec<spirv::Word>, + ) -> spirv::Word { + assert!(bools.len() > 1, "Must have multiple booleans!"); + let bool_ty = writer.get_bool_type_id(); + let mut each_two_true = Vec::new(); + while let Some(last_bool) = bools.pop() { + for &bool in &bools { + let both_true_id = writer.write_logical_and( + block, + last_bool, + bool, + ); + each_two_true.push(both_true_id); + } + } + let mut all_or_id = each_two_true.pop().expect("since this must have multiple booleans, there must be at least one thing in `each_two_true`"); + for two_true in each_two_true { + let new_all_or_id = writer.id_gen.next(); + block.body.push(Instruction::binary( + spirv::Op::LogicalOr, + bool_ty, + new_all_or_id, + all_or_id, + two_true, + )); + all_or_id = new_all_or_id; + } + + let less_than_two_id = writer.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_ty, + less_than_two_id, + all_or_id, )); + less_than_two_id } - crate::RayQueryFunction::Proceed { result } => { - let id = self.gen_id(); - self.cached[result] = id; - let result_type_id = self.get_expression_type_id(&self.fun_info[result].ty); - block - .body - .push(Instruction::ray_query_proceed(result_type_id, id, query_id)); - } - crate::RayQueryFunction::GenerateIntersection { hit_t } => { - let hit_id = self.cached[hit_t]; - block - .body - .push(Instruction::ray_query_generate_intersection( - query_id, hit_id, - )); + // Check that at most one of skip triangles and skip AABBs is + // present (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06889) + let contains_skip_triangles = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::SKIP_TRIANGLES.bits(), + ); + let contains_skip_aabbs = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::SKIP_AABBS.bits(), + ); + + let not_contain_skip_triangles_aabbs = write_less_than_2_true( + self, + &mut block, + vec![contains_skip_triangles, contains_skip_aabbs], + ); + + // Check that at most one of skip triangles (taken from above check), + // cull back facing, and cull front face is present (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06890) + let contains_cull_back = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::CULL_BACK_FACING.bits(), + ); + let contains_cull_front = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::CULL_FRONT_FACING.bits(), + ); + + let not_contain_skip_triangles_cull = write_less_than_2_true( + self, + &mut block, + vec![ + contains_skip_triangles, + contains_cull_back, + contains_cull_front, + ], + ); + + // Check that at most one of force opaque, force not opaque, cull opaque, + // and cull not opaque are present (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06891) + let contains_opaque = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::FORCE_OPAQUE.bits(), + ); + let contains_no_opaque = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::FORCE_NO_OPAQUE.bits(), + ); + let contains_cull_opaque = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::CULL_OPAQUE.bits(), + ); + let contains_cull_no_opaque = write_ray_flags_contains_flags( + self, + &mut block, + ray_flags_id, + crate::RayFlag::CULL_NO_OPAQUE.bits(), + ); + + let not_contain_multiple_opaque = write_less_than_2_true( + self, + &mut block, + vec![ + contains_opaque, + contains_no_opaque, + contains_cull_opaque, + contains_cull_no_opaque, + ], + ); + + // Combine all checks into a single flag saying whether the call is valid or not. + self.write_reduce_and( + &mut block, + vec![ + tmin_le_tmax_id, + tmin_ge_zero_id, + all_ray_origin_finite_id, + all_ray_dir_finite_id, + not_contain_skip_triangles_aabbs, + not_contain_skip_triangles_cull, + not_contain_multiple_opaque, + ], + ) + }); + + let merge_label_id = self.id_gen.next(); + let merge_block = Block::new(merge_label_id); + + // NOTE: this block will be unreachable if initialization tracking is disabled. + let invalid_label_id = self.id_gen.next(); + let mut invalid_block = Block::new(invalid_label_id); + + let valid_label_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_label_id); + + match valid_id { + Some(all_valid_id) => { + block.body.push(Instruction::selection_merge( + merge_label_id, + spirv::SelectionControl::NONE, + )); + function.consume( + block, + Instruction::branch_conditional(all_valid_id, valid_label_id, invalid_label_id), + ); } - crate::RayQueryFunction::ConfirmIntersection => { - block - .body - .push(Instruction::ray_query_confirm_intersection(query_id)); + None => { + function.consume(block, Instruction::branch(valid_label_id)); } - crate::RayQueryFunction::Terminate => {} } - } - pub(super) fn write_ray_query_return_vertex_position( - &mut self, - query: Handle<crate::Expression>, - block: &mut Block, - is_committed: bool, - ) -> spirv::Word { - let query_id = self.cached[query]; - let id = self.gen_id(); - let ray_vertex_return_ty = self - .ir_module - .special_types - .ray_vertex_return - .expect("type should have been populated"); - let ray_vertex_return_ty_id = self.writer.get_handle_type_id(ray_vertex_return_ty); - let intersection_id = - self.writer - .get_constant_scalar(crate::Literal::U32(if is_committed { - spirv::RayQueryIntersection::RayQueryCommittedIntersectionKHR - } else { - spirv::RayQueryIntersection::RayQueryCandidateIntersectionKHR - } as _)); - block + valid_block.body.push(Instruction::ray_query_initialize( + query_id, + acceleration_structure_id, + ray_flags_id, + cull_mask_id, + ray_origin_id, + tmin_id, + ray_dir_id, + tmax_id, + )); + + let const_initialized = self.get_constant_scalar(crate::Literal::U32( + super::RayQueryPoint::INITIALIZED.bits(), + )); + valid_block .body - .push(Instruction::ray_query_return_vertex_position( - ray_vertex_return_ty_id, - id, - query_id, - intersection_id, - )); - id + .push(Instruction::store(init_tracker_id, const_initialized, None)); + + function.consume(valid_block, Instruction::branch(merge_label_id)); + + if self + .flags + .contains(super::WriterFlags::PRINT_ON_RAY_QUERY_INITIALIZATION_FAIL) + { + self.write_debug_printf( + &mut invalid_block, + "Naga ignored invalid arguments to rayQueryInitialize with flags: %u t_min: %f t_max: %f origin: %v4f dir: %v4f", + &[ + ray_flags_id, + tmin_id, + tmax_id, + ray_origin_id, + ray_dir_id, + ], + ); + } + + function.consume(invalid_block, Instruction::branch(merge_label_id)); + + function.consume(merge_block, Instruction::return_void()); + + function.to_words(&mut self.logical_layout.function_definitions); + + self.ray_query_functions + .insert(LookupRayQueryFunction::Initialize, func_id); + func_id + } + + fn write_ray_query_proceed(&mut self) -> spirv::Word { + if let Some(&word) = self + .ray_query_functions + .get(&LookupRayQueryFunction::Proceed) + { + return word; + } + + let ray_query_type_id = self.get_ray_query_pointer_id(); + + let u32_ty = self.get_u32_type_id(); + let u32_ptr_ty = self.get_pointer_type_id(u32_ty, spirv::StorageClass::Function); + + let bool_type_id = self.get_bool_type_id(); + let bool_ptr_ty = self.get_pointer_type_id(bool_type_id, spirv::StorageClass::Function); + + let (func_id, mut function, arg_ids) = + self.write_function_signature(&[ray_query_type_id, u32_ptr_ty], bool_type_id); + + let query_id = arg_ids[0]; + let init_tracker_id = arg_ids[1]; + + let block_id = self.id_gen.next(); + let mut block = Block::new(block_id); + + // TODO: perhaps this could be replaced with an OpPhi? + let proceeded_id = self.id_gen.next(); + let const_false = self.get_constant_scalar(crate::Literal::Bool(false)); + block.body.push(Instruction::variable( + bool_ptr_ty, + proceeded_id, + spirv::StorageClass::Function, + Some(const_false), + )); + + let initialized_tracker_id = self.id_gen.next(); + block.body.push(Instruction::load( + u32_ty, + initialized_tracker_id, + init_tracker_id, + None, + )); + + let merge_id = self.id_gen.next(); + let mut merge_block = Block::new(merge_id); + + let valid_block_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_block_id); + + let instruction = if self.ray_query_initialization_tracking { + let is_initialized = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::INITIALIZED.bits(), + ); + + block.body.push(Instruction::selection_merge( + merge_id, + spirv::SelectionControl::NONE, + )); + + Instruction::branch_conditional(is_initialized, valid_block_id, merge_id) + } else { + Instruction::branch(valid_block_id) + }; + + function.consume(block, instruction); + + let has_proceeded = self.id_gen.next(); + valid_block.body.push(Instruction::ray_query_proceed( + bool_type_id, + has_proceeded, + query_id, + )); + + valid_block + .body + .push(Instruction::store(proceeded_id, has_proceeded, None)); + + let add_flag_finished = self.get_constant_scalar(crate::Literal::U32( + (super::RayQueryPoint::PROCEED | super::RayQueryPoint::FINISHED_TRAVERSAL).bits(), + )); + let add_flag_continuing = + self.get_constant_scalar(crate::Literal::U32(super::RayQueryPoint::PROCEED.bits())); + + let add_flags_id = self.id_gen.next(); + valid_block.body.push(Instruction::select( + u32_ty, + add_flags_id, + has_proceeded, + add_flag_continuing, + add_flag_finished, + )); + let final_flags = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::BitwiseOr, + u32_ty, + final_flags, + initialized_tracker_id, + add_flags_id, + )); + valid_block + .body + .push(Instruction::store(init_tracker_id, final_flags, None)); + + function.consume(valid_block, Instruction::branch(merge_id)); + + let loaded_proceeded_id = self.id_gen.next(); + merge_block.body.push(Instruction::load( + bool_type_id, + loaded_proceeded_id, + proceeded_id, + None, + )); + + function.consume(merge_block, Instruction::return_value(loaded_proceeded_id)); + + function.to_words(&mut self.logical_layout.function_definitions); + + self.ray_query_functions + .insert(LookupRayQueryFunction::Proceed, func_id); + func_id + } + + fn write_ray_query_generate_intersection(&mut self) -> spirv::Word { + if let Some(&word) = self + .ray_query_functions + .get(&LookupRayQueryFunction::GenerateIntersection) + { + return word; + } + + let ray_query_type_id = self.get_ray_query_pointer_id(); + + let u32_ty = self.get_u32_type_id(); + let u32_ptr_ty = self.get_pointer_type_id(u32_ty, spirv::StorageClass::Function); + + let f32_type_id = self.get_f32_type_id(); + let f32_ptr_type_id = self.get_pointer_type_id(f32_type_id, spirv::StorageClass::Function); + + let bool_type_id = self.get_bool_type_id(); + + let (func_id, mut function, arg_ids) = self.write_function_signature( + &[ray_query_type_id, u32_ptr_ty, f32_type_id, f32_ptr_type_id], + self.void_type, + ); + + let query_id = arg_ids[0]; + let init_tracker_id = arg_ids[1]; + let depth_id = arg_ids[2]; + let t_max_tracker_id = arg_ids[3]; + + let block_id = self.id_gen.next(); + let mut block = Block::new(block_id); + + let current_t = self.id_gen.next(); + block.body.push(Instruction::variable( + f32_ptr_type_id, + current_t, + spirv::StorageClass::Function, + None, + )); + + let current_t = self.id_gen.next(); + block.body.push(Instruction::variable( + f32_ptr_type_id, + current_t, + spirv::StorageClass::Function, + None, + )); + + let valid_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_id); + + let final_label_id = self.id_gen.next(); + let final_block = Block::new(final_label_id); + + let instruction = if self.ray_query_initialization_tracking { + let initialized_tracker_id = self.id_gen.next(); + block.body.push(Instruction::load( + u32_ty, + initialized_tracker_id, + init_tracker_id, + None, + )); + + let proceeded_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::PROCEED.bits(), + ); + let finished_proceed_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::FINISHED_TRAVERSAL.bits(), + ); + + // Can't find anything to suggest double calling this function is invalid. + + let not_finished_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + not_finished_id, + finished_proceed_id, + )); + + let is_valid_id = self.write_logical_and(&mut block, not_finished_id, proceeded_id); + + block.body.push(Instruction::selection_merge( + final_label_id, + spirv::SelectionControl::NONE, + )); + + Instruction::branch_conditional(is_valid_id, valid_id, final_label_id) + } else { + Instruction::branch(valid_id) + }; + + function.consume(block, instruction); + + let intersection_id = self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryIntersection::RayQueryCandidateIntersectionKHR as _, + )); + let committed_intersection_id = self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryIntersection::RayQueryCommittedIntersectionKHR as _, + )); + let raw_kind_id = self.id_gen.next(); + valid_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTypeKHR, + u32_ty, + raw_kind_id, + query_id, + intersection_id, + )); + + let candidate_aabb_id = self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryCandidateIntersectionType::RayQueryCandidateIntersectionAABBKHR as _, + )); + let intersection_aabb_id = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::IEqual, + bool_type_id, + intersection_aabb_id, + raw_kind_id, + candidate_aabb_id, + )); + + // Check that the provided t value is between t min and the current committed + // t value, (https://docs.vulkan.org/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-OpRayQueryGenerateIntersectionKHR-06353) + + // Get the tmin + let t_min_id = self.id_gen.next(); + valid_block.body.push(Instruction::ray_query_get_t_min( + f32_type_id, + t_min_id, + query_id, + )); + + // Get the current committed t, or tmax if no hit. + // Basically emulate HLSL's (easier) version + // Pseudo-code: + // ````wgsl + // // start of function + // var current_t:f32; + // ... + // let committed_type_id = RayQueryGetIntersectionTypeKHR<Committed>(query_id); + // if committed_type_id == Committed_None { + // current_t = load(t_max_tracker); + // } else { + // current_t = RayQueryGetIntersectionTKHR<Committed>(query_id); + // } + // ... + // ```` + + let committed_type_id = self.id_gen.next(); + valid_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTypeKHR, + u32_ty, + committed_type_id, + query_id, + committed_intersection_id, + )); + + let no_committed = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::IEqual, + bool_type_id, + no_committed, + committed_type_id, + self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryCommittedIntersectionType::RayQueryCommittedIntersectionNoneKHR as _, + )), + )); + + let next_valid_block_id = self.id_gen.next(); + let no_committed_block_id = self.id_gen.next(); + let mut no_committed_block = Block::new(no_committed_block_id); + let committed_block_id = self.id_gen.next(); + let mut committed_block = Block::new(committed_block_id); + valid_block.body.push(Instruction::selection_merge( + next_valid_block_id, + spirv::SelectionControl::NONE, + )); + function.consume( + valid_block, + Instruction::branch_conditional( + no_committed, + no_committed_block_id, + committed_block_id, + ), + ); + + // Assign t_max to current_t + let t_max_id = self.id_gen.next(); + no_committed_block.body.push(Instruction::load( + f32_type_id, + t_max_id, + t_max_tracker_id, + None, + )); + no_committed_block + .body + .push(Instruction::store(current_t, t_max_id, None)); + function.consume(no_committed_block, Instruction::branch(next_valid_block_id)); + + // Assign t_current to current_t + let latest_t_id = self.id_gen.next(); + committed_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTKHR, + f32_type_id, + latest_t_id, + query_id, + intersection_id, + )); + committed_block + .body + .push(Instruction::store(current_t, latest_t_id, None)); + function.consume(committed_block, Instruction::branch(next_valid_block_id)); + + let mut valid_block = Block::new(next_valid_block_id); + + let t_ge_t_min = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::FOrdGreaterThanEqual, + bool_type_id, + t_ge_t_min, + depth_id, + t_min_id, + )); + let t_current = self.id_gen.next(); + valid_block + .body + .push(Instruction::load(f32_type_id, t_current, current_t, None)); + let t_le_t_current = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::FOrdLessThanEqual, + bool_type_id, + t_le_t_current, + depth_id, + t_current, + )); + + let t_in_range = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::LogicalAnd, + bool_type_id, + t_in_range, + t_ge_t_min, + t_le_t_current, + )); + + let call_valid_id = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::LogicalAnd, + bool_type_id, + call_valid_id, + t_in_range, + intersection_aabb_id, + )); + + let generate_label_id = self.id_gen.next(); + let mut generate_block = Block::new(generate_label_id); + + let merge_label_id = self.id_gen.next(); + let merge_block = Block::new(merge_label_id); + + valid_block.body.push(Instruction::selection_merge( + merge_label_id, + spirv::SelectionControl::NONE, + )); + function.consume( + valid_block, + Instruction::branch_conditional(call_valid_id, generate_label_id, merge_label_id), + ); + + generate_block + .body + .push(Instruction::ray_query_generate_intersection( + query_id, depth_id, + )); + + function.consume(generate_block, Instruction::branch(merge_label_id)); + function.consume(merge_block, Instruction::branch(final_label_id)); + + function.consume(final_block, Instruction::return_void()); + + function.to_words(&mut self.logical_layout.function_definitions); + + self.ray_query_functions + .insert(LookupRayQueryFunction::GenerateIntersection, func_id); + func_id + } + + fn write_ray_query_confirm_intersection(&mut self) -> spirv::Word { + if let Some(&word) = self + .ray_query_functions + .get(&LookupRayQueryFunction::ConfirmIntersection) + { + return word; + } + + let ray_query_type_id = self.get_ray_query_pointer_id(); + + let u32_ty = self.get_u32_type_id(); + let u32_ptr_ty = self.get_pointer_type_id(u32_ty, spirv::StorageClass::Function); + + let bool_type_id = self.get_bool_type_id(); + + let (func_id, mut function, arg_ids) = + self.write_function_signature(&[ray_query_type_id, u32_ptr_ty], self.void_type); + + let query_id = arg_ids[0]; + let init_tracker_id = arg_ids[1]; + + let block_id = self.id_gen.next(); + let mut block = Block::new(block_id); + + let valid_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_id); + + let final_label_id = self.id_gen.next(); + let final_block = Block::new(final_label_id); + + let instruction = if self.ray_query_initialization_tracking { + let initialized_tracker_id = self.id_gen.next(); + block.body.push(Instruction::load( + u32_ty, + initialized_tracker_id, + init_tracker_id, + None, + )); + + let proceeded_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::PROCEED.bits(), + ); + let finished_proceed_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::FINISHED_TRAVERSAL.bits(), + ); + // Although it seems strange to call this twice, I (Vecvec) can't find anything to suggest double calling this function is invalid. + let not_finished_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + not_finished_id, + finished_proceed_id, + )); + + let is_valid_id = self.write_logical_and(&mut block, not_finished_id, proceeded_id); + + block.body.push(Instruction::selection_merge( + final_label_id, + spirv::SelectionControl::NONE, + )); + + Instruction::branch_conditional(is_valid_id, valid_id, final_label_id) + } else { + Instruction::branch(valid_id) + }; + + function.consume(block, instruction); + + let intersection_id = self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryIntersection::RayQueryCandidateIntersectionKHR as _, + )); + let raw_kind_id = self.id_gen.next(); + valid_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTypeKHR, + u32_ty, + raw_kind_id, + query_id, + intersection_id, + )); + + let candidate_tri_id = self.get_constant_scalar(crate::Literal::U32( + spirv::RayQueryCandidateIntersectionType::RayQueryCandidateIntersectionTriangleKHR as _, + )); + let intersection_tri_id = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::IEqual, + bool_type_id, + intersection_tri_id, + raw_kind_id, + candidate_tri_id, + )); + + let generate_label_id = self.id_gen.next(); + let mut generate_block = Block::new(generate_label_id); + + let merge_label_id = self.id_gen.next(); + let merge_block = Block::new(merge_label_id); + + valid_block.body.push(Instruction::selection_merge( + merge_label_id, + spirv::SelectionControl::NONE, + )); + function.consume( + valid_block, + Instruction::branch_conditional(intersection_tri_id, generate_label_id, merge_label_id), + ); + + generate_block + .body + .push(Instruction::ray_query_confirm_intersection(query_id)); + + function.consume(generate_block, Instruction::branch(merge_label_id)); + function.consume(merge_block, Instruction::branch(final_label_id)); + + function.consume(final_block, Instruction::return_void()); + + self.ray_query_functions + .insert(LookupRayQueryFunction::ConfirmIntersection, func_id); + + function.to_words(&mut self.logical_layout.function_definitions); + + func_id + } + + fn write_ray_query_get_vertex_positions( + &mut self, + is_committed: bool, + ir_module: &crate::Module, + ) -> spirv::Word { + if let Some(&word) = + self.ray_query_functions + .get(&LookupRayQueryFunction::GetVertexPositions { + committed: is_committed, + }) + { + return word; + } + + let (committed_ty, committed_tri_ty) = if is_committed { + ( + spirv::RayQueryIntersection::RayQueryCommittedIntersectionKHR as u32, + spirv::RayQueryCommittedIntersectionType::RayQueryCommittedIntersectionTriangleKHR + as u32, + ) + } else { + ( + spirv::RayQueryIntersection::RayQueryCandidateIntersectionKHR as u32, + spirv::RayQueryCandidateIntersectionType::RayQueryCandidateIntersectionTriangleKHR + as u32, + ) + }; + + let ray_query_type_id = self.get_ray_query_pointer_id(); + + let u32_ty = self.get_u32_type_id(); + let u32_ptr_ty = self.get_pointer_type_id(u32_ty, spirv::StorageClass::Function); + + let rq_get_vertex_positions_ty_id = self.get_handle_type_id( + *ir_module + .special_types + .ray_vertex_return + .as_ref() + .expect("must be generated when reading in get vertex position"), + ); + let ptr_return_ty = + self.get_pointer_type_id(rq_get_vertex_positions_ty_id, spirv::StorageClass::Function); + + let bool_type_id = self.get_bool_type_id(); + + let (func_id, mut function, arg_ids) = self.write_function_signature( + &[ray_query_type_id, u32_ptr_ty], + rq_get_vertex_positions_ty_id, + ); + + let query_id = arg_ids[0]; + let init_tracker_id = arg_ids[1]; + + let block_id = self.id_gen.next(); + let mut block = Block::new(block_id); + + let return_id = self.id_gen.next(); + block.body.push(Instruction::variable( + ptr_return_ty, + return_id, + spirv::StorageClass::Function, + Some(self.get_constant_null(rq_get_vertex_positions_ty_id)), + )); + + let valid_id = self.id_gen.next(); + let mut valid_block = Block::new(valid_id); + + let final_label_id = self.id_gen.next(); + let mut final_block = Block::new(final_label_id); + + let instruction = if self.ray_query_initialization_tracking { + let initialized_tracker_id = self.id_gen.next(); + block.body.push(Instruction::load( + u32_ty, + initialized_tracker_id, + init_tracker_id, + None, + )); + + let proceeded_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::PROCEED.bits(), + ); + let finished_proceed_id = write_ray_flags_contains_flags( + self, + &mut block, + initialized_tracker_id, + super::RayQueryPoint::FINISHED_TRAVERSAL.bits(), + ); + + let correct_finish_id = if is_committed { + finished_proceed_id + } else { + let not_finished_id = self.id_gen.next(); + block.body.push(Instruction::unary( + spirv::Op::LogicalNot, + bool_type_id, + not_finished_id, + finished_proceed_id, + )); + not_finished_id + }; + + let is_valid_id = self.write_logical_and(&mut block, correct_finish_id, proceeded_id); + block.body.push(Instruction::selection_merge( + final_label_id, + spirv::SelectionControl::NONE, + )); + Instruction::branch_conditional(is_valid_id, valid_id, final_label_id) + } else { + Instruction::branch(valid_id) + }; + + function.consume(block, instruction); + + let intersection_id = self.get_constant_scalar(crate::Literal::U32(committed_ty)); + let raw_kind_id = self.id_gen.next(); + valid_block + .body + .push(Instruction::ray_query_get_intersection( + spirv::Op::RayQueryGetIntersectionTypeKHR, + u32_ty, + raw_kind_id, + query_id, + intersection_id, + )); + + let candidate_tri_id = self.get_constant_scalar(crate::Literal::U32(committed_tri_ty)); + let intersection_tri_id = self.id_gen.next(); + valid_block.body.push(Instruction::binary( + spirv::Op::IEqual, + bool_type_id, + intersection_tri_id, + raw_kind_id, + candidate_tri_id, + )); + + let generate_label_id = self.id_gen.next(); + let mut vertex_return_block = Block::new(generate_label_id); + + let merge_label_id = self.id_gen.next(); + let merge_block = Block::new(merge_label_id); + + valid_block.body.push(Instruction::selection_merge( + merge_label_id, + spirv::SelectionControl::NONE, + )); + function.consume( + valid_block, + Instruction::branch_conditional(intersection_tri_id, generate_label_id, merge_label_id), + ); + + let vertices_id = self.id_gen.next(); + vertex_return_block + .body + .push(Instruction::ray_query_return_vertex_position( + rq_get_vertex_positions_ty_id, + vertices_id, + query_id, + intersection_id, + )); + vertex_return_block + .body + .push(Instruction::store(return_id, vertices_id, None)); + + function.consume(vertex_return_block, Instruction::branch(merge_label_id)); + function.consume(merge_block, Instruction::branch(final_label_id)); + + let loaded_pos_id = self.id_gen.next(); + final_block.body.push(Instruction::load( + rq_get_vertex_positions_ty_id, + loaded_pos_id, + return_id, + None, + )); + + function.consume(final_block, Instruction::return_value(loaded_pos_id)); + + self.ray_query_functions.insert( + LookupRayQueryFunction::GetVertexPositions { + committed: is_committed, + }, + func_id, + ); + + function.to_words(&mut self.logical_layout.function_definitions); + + func_id + } +} + +impl BlockContext<'_> { + pub(super) fn write_ray_query_function( + &mut self, + query: Handle<crate::Expression>, + function: &crate::RayQueryFunction, + block: &mut Block, + ) { + let query_id = self.cached[query]; + let tracker_ids = *self + .ray_query_tracker_expr + .get(&query) + .expect("not a cached ray query"); + + match *function { + crate::RayQueryFunction::Initialize { + acceleration_structure, + descriptor, + } => { + let desc_id = self.cached[descriptor]; + let acc_struct_id = self.get_handle_id(acceleration_structure); + + let func = self.writer.write_ray_query_initialize(self.ir_module); + + let func_id = self.gen_id(); + block.body.push(Instruction::function_call( + self.writer.void_type, + func_id, + func, + &[ + query_id, + acc_struct_id, + desc_id, + tracker_ids.initialized_tracker, + tracker_ids.t_max_tracker, + ], + )); + } + crate::RayQueryFunction::Proceed { result } => { + let id = self.gen_id(); + self.cached[result] = id; + + let bool_ty = self.writer.get_bool_type_id(); + + let func_id = self.writer.write_ray_query_proceed(); + block.body.push(Instruction::function_call( + bool_ty, + id, + func_id, + &[query_id, tracker_ids.initialized_tracker], + )); + } + crate::RayQueryFunction::GenerateIntersection { hit_t } => { + let hit_id = self.cached[hit_t]; + + let func_id = self.writer.write_ray_query_generate_intersection(); + + let func_call_id = self.gen_id(); + block.body.push(Instruction::function_call( + self.writer.void_type, + func_call_id, + func_id, + &[ + query_id, + tracker_ids.initialized_tracker, + hit_id, + tracker_ids.t_max_tracker, + ], + )); + } + crate::RayQueryFunction::ConfirmIntersection => { + let func_id = self.writer.write_ray_query_confirm_intersection(); + + let func_call_id = self.gen_id(); + block.body.push(Instruction::function_call( + self.writer.void_type, + func_call_id, + func_id, + &[query_id, tracker_ids.initialized_tracker], + )); + } + crate::RayQueryFunction::Terminate => {} + } + } + + pub(super) fn write_ray_query_return_vertex_position( + &mut self, + query: Handle<crate::Expression>, + block: &mut Block, + is_committed: bool, + ) -> spirv::Word { + let fn_id = self + .writer + .write_ray_query_get_vertex_positions(is_committed, self.ir_module); + + let query_id = self.cached[query]; + let tracker_id = *self + .ray_query_tracker_expr + .get(&query) + .expect("not a cached ray query"); + + let rq_get_vertex_positions_ty_id = self.get_handle_type_id( + *self + .ir_module + .special_types + .ray_vertex_return + .as_ref() + .expect("must be generated when reading in get vertex position"), + ); + + let func_call_id = self.gen_id(); + block.body.push(Instruction::function_call( + rq_get_vertex_positions_ty_id, + func_call_id, + fn_id, + &[query_id, tracker_id.initialized_tracker], + )); + func_call_id } } diff --git a/third_party/rust/naga/src/back/spv/writer.rs b/third_party/rust/naga/src/back/spv/writer.rs @@ -35,6 +35,12 @@ impl Function { for local_var in self.variables.values() { local_var.instruction.to_words(sink); } + for local_var in self.ray_query_initialization_tracker_variables.values() { + local_var.instruction.to_words(sink); + } + for local_var in self.ray_query_t_max_tracker_variables.values() { + local_var.instruction.to_words(sink); + } for local_var in self.force_loop_bounding_vars.iter() { local_var.instruction.to_words(sink); } @@ -71,12 +77,14 @@ impl Writer { capabilities_available: options.capabilities.clone(), capabilities_used, extensions_used: crate::FastIndexSet::default(), + debug_strings: vec![], debugs: vec![], annotations: vec![], flags: options.flags, bounds_check_policies: options.bounds_check_policies, zero_initialize_workgroup_memory: options.zero_initialize_workgroup_memory, force_loop_bounding: options.force_loop_bounding, + ray_query_initialization_tracking: options.ray_query_initialization_tracking, use_storage_input_output_16: options.use_storage_input_output_16, void_type, lookup_type: crate::FastHashMap::default(), @@ -91,11 +99,11 @@ impl Writer { saved_cached: CachedExpressions::default(), gl450_ext_inst_id, temp_list: Vec::new(), - ray_get_committed_intersection_function: None, - ray_get_candidate_intersection_function: None, + ray_query_functions: crate::FastHashMap::default(), io_f16_polyfills: super::f16_polyfill::F16IoPolyfill::new( options.use_storage_input_output_16, ), + debug_printf: None, }) } @@ -147,6 +155,7 @@ impl Writer { bounds_check_policies: self.bounds_check_policies, zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory, force_loop_bounding: self.force_loop_bounding, + ray_query_initialization_tracking: self.ray_query_initialization_tracking, use_storage_input_output_16: self.use_storage_input_output_16, capabilities_available: take(&mut self.capabilities_available), fake_missing_bindings: self.fake_missing_bindings, @@ -162,6 +171,7 @@ impl Writer { extensions_used: take(&mut self.extensions_used).recycle(), physical_layout: self.physical_layout.clone().recycle(), logical_layout: take(&mut self.logical_layout).recycle(), + debug_strings: take(&mut self.debug_strings).recycle(), debugs: take(&mut self.debugs).recycle(), annotations: take(&mut self.annotations).recycle(), lookup_type: take(&mut self.lookup_type).recycle(), @@ -173,9 +183,9 @@ impl Writer { global_variables: take(&mut self.global_variables).recycle(), saved_cached: take(&mut self.saved_cached).recycle(), temp_list: take(&mut self.temp_list).recycle(), - ray_get_candidate_intersection_function: None, - ray_get_committed_intersection_function: None, + ray_query_functions: take(&mut self.ray_query_functions).recycle(), io_f16_polyfills: take(&mut self.io_f16_polyfills).recycle(), + debug_printf: None, }; *self = fresh; @@ -1022,6 +1032,7 @@ impl Writer { expression_constness: super::ExpressionConstnessTracker::from_arena( &ir_function.expressions, ), + ray_query_tracker_expr: crate::FastHashMap::default(), }; // fill up the pre-emitted and const expressions @@ -1063,6 +1074,58 @@ impl Writer { .function .variables .insert(handle, LocalVariable { id, instruction }); + + if let crate::TypeInner::RayQuery { .. } = ir_module.types[variable.ty].inner { + // Don't refactor this into a struct: Although spirv itself allows opaque types in structs, + // the vulkan environment for spirv does not. Putting ray queries into structs can cause + // confusing bugs. + let u32_type_id = context.writer.get_u32_type_id(); + let ptr_u32_type_id = context + .writer + .get_pointer_type_id(u32_type_id, spirv::StorageClass::Function); + let tracker_id = context.gen_id(); + let tracker_init_id = context + .writer + .get_constant_scalar(crate::Literal::U32(super::RayQueryPoint::empty().bits())); + let tracker_instruction = Instruction::variable( + ptr_u32_type_id, + tracker_id, + spirv::StorageClass::Function, + Some(tracker_init_id), + ); + + context + .function + .ray_query_initialization_tracker_variables + .insert( + handle, + LocalVariable { + id: tracker_id, + instruction: tracker_instruction, + }, + ); + let f32_type_id = context.writer.get_f32_type_id(); + let ptr_f32_type_id = context + .writer + .get_pointer_type_id(f32_type_id, spirv::StorageClass::Function); + let t_max_tracker_id = context.gen_id(); + let t_max_tracker_init_id = + context.writer.get_constant_scalar(crate::Literal::F32(0.0)); + let t_max_tracker_instruction = Instruction::variable( + ptr_f32_type_id, + t_max_tracker_id, + spirv::StorageClass::Function, + Some(t_max_tracker_init_id), + ); + + context.function.ray_query_t_max_tracker_variables.insert( + handle, + LocalVariable { + id: t_max_tracker_id, + instruction: t_max_tracker_instruction, + }, + ); + } } for (handle, expr) in ir_function.expressions.iter() { @@ -2156,7 +2219,11 @@ impl Writer { | Bi::CullPrimitive | Bi::PointIndex | Bi::LineIndices - | Bi::TriangleIndices => unreachable!(), + | Bi::TriangleIndices + | Bi::VertexCount + | Bi::PrimitiveCount + | Bi::Vertices + | Bi::Primitives => unreachable!(), }; self.decorate(id, Decoration::BuiltIn, &[built_in as u32]); @@ -2651,6 +2718,10 @@ impl Writer { Instruction::memory_model(addressing_model, memory_model) .to_words(&mut self.logical_layout.memory_model); + for debug_string in self.debug_strings.iter() { + debug_string.to_words(&mut self.logical_layout.debugs); + } + if self.flags.contains(WriterFlags::DEBUG) { for debug in self.debugs.iter() { debug.to_words(&mut self.logical_layout.debugs); @@ -2710,6 +2781,40 @@ impl Writer { pub(super) fn needs_f16_polyfill(&self, ty_inner: &crate::TypeInner) -> bool { self.io_f16_polyfills.needs_polyfill(ty_inner) } + + pub(super) fn write_debug_printf( + &mut self, + block: &mut Block, + string: &str, + format_params: &[Word], + ) { + if self.debug_printf.is_none() { + self.use_extension("SPV_KHR_non_semantic_info"); + let import_id = self.id_gen.next(); + Instruction::ext_inst_import(import_id, "NonSemantic.DebugPrintf") + .to_words(&mut self.logical_layout.ext_inst_imports); + self.debug_printf = Some(import_id) + } + + let import_id = self.debug_printf.unwrap(); + + let string_id = self.id_gen.next(); + self.debug_strings + .push(Instruction::string(string, string_id)); + + let mut operands = Vec::with_capacity(1 + format_params.len()); + operands.push(string_id); + operands.extend(format_params.iter()); + + let print_id = self.id_gen.next(); + block.body.push(Instruction::ext_inst( + import_id, + 1, + self.void_type, + print_id, + &operands, + )); + } } #[test] diff --git a/third_party/rust/naga/src/back/wgsl/writer.rs b/third_party/rust/naga/src/back/wgsl/writer.rs @@ -856,7 +856,6 @@ impl<W: Write> Writer<W> { } } Statement::RayQuery { .. } => unreachable!(), - Statement::MeshFunction(..) => unreachable!(), Statement::SubgroupBallot { result, predicate } => { write!(self.out, "{level}")?; let res_name = Baked(result).to_string(); diff --git a/third_party/rust/naga/src/common/wgsl/to_wgsl.rs b/third_party/rust/naga/src/common/wgsl/to_wgsl.rs @@ -194,7 +194,11 @@ impl TryToWgsl for crate::BuiltIn { | Bi::TriangleIndices | Bi::LineIndices | Bi::MeshTaskSize - | Bi::PointIndex => return None, + | Bi::PointIndex + | Bi::VertexCount + | Bi::PrimitiveCount + | Bi::Vertices + | Bi::Primitives => return None, }) } } diff --git a/third_party/rust/naga/src/compact/mod.rs b/third_party/rust/naga/src/compact/mod.rs @@ -132,6 +132,46 @@ pub fn compact(module: &mut crate::Module, keep_unused: KeepUnused) { } } + if let Some(task_payload) = e.task_payload { + module_tracer.global_variables_used.insert(task_payload); + } + if let Some(ref mesh_info) = e.mesh_info { + module_tracer + .global_variables_used + .insert(mesh_info.output_variable); + module_tracer + .types_used + .insert(mesh_info.vertex_output_type); + module_tracer + .types_used + .insert(mesh_info.primitive_output_type); + if let Some(max_vertices_override) = mesh_info.max_vertices_override { + module_tracer + .global_expressions_used + .insert(max_vertices_override); + } + if let Some(max_primitives_override) = mesh_info.max_primitives_override { + module_tracer + .global_expressions_used + .insert(max_primitives_override); + } + } + if e.stage == crate::ShaderStage::Task || e.stage == crate::ShaderStage::Mesh { + // u32 should always be there if the module is valid, as it is e.g. the type of some expressions + let u32_type = module + .types + .iter() + .find_map(|tuple| { + if tuple.1.inner == crate::TypeInner::Scalar(crate::Scalar::U32) { + Some(tuple.0) + } else { + None + } + }) + .unwrap(); + module_tracer.types_used.insert(u32_type); + } + let mut used = module_tracer.as_function(&e.function); used.trace(); FunctionMap::from(used) @@ -221,45 +261,6 @@ pub fn compact(module: &mut crate::Module, keep_unused: KeepUnused) { } } - for entry in &module.entry_points { - if let Some(task_payload) = entry.task_payload { - module_tracer.global_variables_used.insert(task_payload); - } - if let Some(ref mesh_info) = entry.mesh_info { - module_tracer - .types_used - .insert(mesh_info.vertex_output_type); - module_tracer - .types_used - .insert(mesh_info.primitive_output_type); - if let Some(max_vertices_override) = mesh_info.max_vertices_override { - module_tracer - .global_expressions_used - .insert(max_vertices_override); - } - if let Some(max_primitives_override) = mesh_info.max_primitives_override { - module_tracer - .global_expressions_used - .insert(max_primitives_override); - } - } - if entry.stage == crate::ShaderStage::Task || entry.stage == crate::ShaderStage::Mesh { - // u32 should always be there if the module is valid, as it is e.g. the type of some expressions - let u32_type = module - .types - .iter() - .find_map(|tuple| { - if tuple.1.inner == crate::TypeInner::Scalar(crate::Scalar::U32) { - Some(tuple.0) - } else { - None - } - }) - .unwrap(); - module_tracer.types_used.insert(u32_type); - } - } - module_tracer.type_expression_tandem(); // Now that we know what is used and what is never touched, @@ -385,6 +386,7 @@ pub fn compact(module: &mut crate::Module, keep_unused: KeepUnused) { module_map.globals.adjust(task_payload); } if let Some(ref mut mesh_info) = entry.mesh_info { + module_map.globals.adjust(&mut mesh_info.output_variable); module_map.types.adjust(&mut mesh_info.vertex_output_type); module_map .types diff --git a/third_party/rust/naga/src/compact/statements.rs b/third_party/rust/naga/src/compact/statements.rs @@ -117,20 +117,6 @@ impl FunctionTracer<'_> { self.expressions_used.insert(query); self.trace_ray_query_function(fun); } - St::MeshFunction(crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - }) => { - self.expressions_used.insert(vertex_count); - self.expressions_used.insert(primitive_count); - } - St::MeshFunction( - crate::MeshFunction::SetPrimitive { index, value } - | crate::MeshFunction::SetVertex { index, value }, - ) => { - self.expressions_used.insert(index); - self.expressions_used.insert(value); - } St::SubgroupBallot { result, predicate } => { if let Some(predicate) = predicate { self.expressions_used.insert(predicate); @@ -349,26 +335,6 @@ impl FunctionMap { adjust(query); self.adjust_ray_query_function(fun); } - St::MeshFunction(crate::MeshFunction::SetMeshOutputs { - ref mut vertex_count, - ref mut primitive_count, - }) => { - adjust(vertex_count); - adjust(primitive_count); - } - St::MeshFunction( - crate::MeshFunction::SetVertex { - ref mut index, - ref mut value, - } - | crate::MeshFunction::SetPrimitive { - ref mut index, - ref mut value, - }, - ) => { - adjust(index); - adjust(value); - } St::SubgroupBallot { ref mut result, ref mut predicate, diff --git a/third_party/rust/naga/src/front/spv/mod.rs b/third_party/rust/naga/src/front/spv/mod.rs @@ -4661,7 +4661,6 @@ impl<I: Iterator<Item = u32>> Frontend<I> { | S::Atomic { .. } | S::ImageAtomic { .. } | S::RayQuery { .. } - | S::MeshFunction(..) | S::SubgroupBallot { .. } | S::SubgroupCollectiveOperation { .. } | S::SubgroupGather { .. } => {} diff --git a/third_party/rust/naga/src/front/wgsl/error.rs b/third_party/rust/naga/src/front/wgsl/error.rs @@ -406,6 +406,9 @@ pub(crate) enum Error<'a> { accept_span: Span, accept_type: String, }, + ExpectedGlobalVariable { + name_span: Span, + }, StructMemberTooLarge { member_name_span: Span, }, @@ -1370,6 +1373,11 @@ impl<'a> Error<'a> { ], notes: vec![], }, + Error::ExpectedGlobalVariable { name_span } => ParseError { + message: "expected global variable".to_string(), + labels: vec![(name_span, "variable used here".into())], + notes: vec![], + }, Error::StructMemberTooLarge { member_name_span } => ParseError { message: "struct member is too large".into(), labels: vec![(member_name_span, "this member exceeds the maximum size".into())], diff --git a/third_party/rust/naga/src/front/wgsl/lower/mod.rs b/third_party/rust/naga/src/front/wgsl/lower/mod.rs @@ -1479,47 +1479,93 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .collect(); if let Some(ref entry) = f.entry_point { - let workgroup_size_info = if let Some(workgroup_size) = entry.workgroup_size { - // TODO: replace with try_map once stabilized - let mut workgroup_size_out = [1; 3]; - let mut workgroup_size_overrides_out = [None; 3]; - for (i, size) in workgroup_size.into_iter().enumerate() { - if let Some(size_expr) = size { - match self.const_u32(size_expr, &mut ctx.as_const()) { - Ok(value) => { - workgroup_size_out[i] = value.0; - } - Err(err) => { - if let Error::ConstantEvaluatorError(ref ty, _) = *err { - match **ty { - proc::ConstantEvaluatorError::OverrideExpr => { - workgroup_size_overrides_out[i] = - Some(self.workgroup_size_override( - size_expr, - &mut ctx.as_override(), - )?); - } - _ => { - return Err(err); + let (workgroup_size, workgroup_size_overrides) = + if let Some(workgroup_size) = entry.workgroup_size { + // TODO: replace with try_map once stabilized + let mut workgroup_size_out = [1; 3]; + let mut workgroup_size_overrides_out = [None; 3]; + for (i, size) in workgroup_size.into_iter().enumerate() { + if let Some(size_expr) = size { + match self.const_u32(size_expr, &mut ctx.as_const()) { + Ok(value) => { + workgroup_size_out[i] = value.0; + } + Err(err) => { + if let Error::ConstantEvaluatorError(ref ty, _) = *err { + match **ty { + proc::ConstantEvaluatorError::OverrideExpr => { + workgroup_size_overrides_out[i] = + Some(self.workgroup_size_override( + size_expr, + &mut ctx.as_override(), + )?); + } + _ => { + return Err(err); + } } + } else { + return Err(err); } - } else { - return Err(err); } } } } - } - if workgroup_size_overrides_out.iter().all(|x| x.is_none()) { - (workgroup_size_out, None) + if workgroup_size_overrides_out.iter().all(|x| x.is_none()) { + (workgroup_size_out, None) + } else { + (workgroup_size_out, Some(workgroup_size_overrides_out)) + } } else { - (workgroup_size_out, Some(workgroup_size_overrides_out)) + ([0; 3], None) + }; + + let mesh_info = if let Some((var_name, var_span)) = entry.mesh_output_variable { + let var = match ctx.globals.get(var_name) { + Some(&LoweredGlobalDecl::Var(handle)) => handle, + Some(_) => { + return Err(Box::new(Error::ExpectedGlobalVariable { + name_span: var_span, + })) + } + None => return Err(Box::new(Error::UnknownIdent(var_span, var_name))), + }; + + let mut info = ctx.module.analyze_mesh_shader_info(var); + if let Some(h) = info.1[0] { + info.0.max_vertices_override = Some( + ctx.module + .global_expressions + .append(crate::Expression::Override(h), Span::UNDEFINED), + ); + } + if let Some(h) = info.1[1] { + info.0.max_primitives_override = Some( + ctx.module + .global_expressions + .append(crate::Expression::Override(h), Span::UNDEFINED), + ); } + + Some(info.0) + } else { + None + }; + + let task_payload = if let Some((var_name, var_span)) = entry.task_payload { + Some(match ctx.globals.get(var_name) { + Some(&LoweredGlobalDecl::Var(handle)) => handle, + Some(_) => { + return Err(Box::new(Error::ExpectedGlobalVariable { + name_span: var_span, + })) + } + None => return Err(Box::new(Error::UnknownIdent(var_span, var_name))), + }) } else { - ([0; 3], None) + None }; - let (workgroup_size, workgroup_size_overrides) = workgroup_size_info; ctx.module.entry_points.push(ir::EntryPoint { name: f.name.name.to_string(), stage: entry.stage, @@ -1527,8 +1573,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { workgroup_size, workgroup_size_overrides, function, - mesh_info: None, - task_payload: None, + mesh_info, + task_payload, }); Ok(LoweredGlobalDecl::EntryPoint( ctx.module.entry_points.len() - 1, @@ -4059,6 +4105,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { interpolation, sampling, blend_src, + per_primitive, }) => { let blend_src = if let Some(blend_src) = blend_src { Some(self.const_u32(blend_src, &mut ctx.as_const())?.0) @@ -4071,7 +4118,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { interpolation, sampling, blend_src, - per_primitive: false, + per_primitive, }; binding.apply_default_interpolation(&ctx.module.types[ty].inner); Some(binding) diff --git a/third_party/rust/naga/src/front/wgsl/parse/ast.rs b/third_party/rust/naga/src/front/wgsl/parse/ast.rs @@ -128,6 +128,8 @@ pub struct EntryPoint<'a> { pub stage: crate::ShaderStage, pub early_depth_test: Option<crate::EarlyDepthTest>, pub workgroup_size: Option<[Option<Handle<Expression<'a>>>; 3]>, + pub mesh_output_variable: Option<(&'a str, Span)>, + pub task_payload: Option<(&'a str, Span)>, } #[cfg(doc)] @@ -152,6 +154,7 @@ pub enum Binding<'a> { interpolation: Option<crate::Interpolation>, sampling: Option<crate::Sampling>, blend_src: Option<Handle<Expression<'a>>>, + per_primitive: bool, }, } diff --git a/third_party/rust/naga/src/front/wgsl/parse/conv.rs b/third_party/rust/naga/src/front/wgsl/parse/conv.rs @@ -6,7 +6,11 @@ use crate::Span; use alloc::boxed::Box; -pub fn map_address_space(word: &str, span: Span) -> Result<'_, crate::AddressSpace> { +pub fn map_address_space<'a>( + word: &str, + span: Span, + enable_extensions: &EnableExtensions, +) -> Result<'a, crate::AddressSpace> { match word { "private" => Ok(crate::AddressSpace::Private), "workgroup" => Ok(crate::AddressSpace::WorkGroup), @@ -16,6 +20,16 @@ pub fn map_address_space(word: &str, span: Span) -> Result<'_, crate::AddressSpa }), "push_constant" => Ok(crate::AddressSpace::PushConstant), "function" => Ok(crate::AddressSpace::Function), + "task_payload" => { + if enable_extensions.contains(ImplementedEnableExtension::WgpuMeshShader) { + Ok(crate::AddressSpace::TaskPayload) + } else { + Err(Box::new(Error::EnableExtensionNotEnabled { + span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })) + } + } _ => Err(Box::new(Error::UnknownAddressSpace(span))), } } @@ -50,6 +64,17 @@ pub fn map_built_in( "subgroup_id" => crate::BuiltIn::SubgroupId, "subgroup_size" => crate::BuiltIn::SubgroupSize, "subgroup_invocation_id" => crate::BuiltIn::SubgroupInvocationId, + // mesh + "cull_primitive" => crate::BuiltIn::CullPrimitive, + "point_index" => crate::BuiltIn::PointIndex, + "line_indices" => crate::BuiltIn::LineIndices, + "triangle_indices" => crate::BuiltIn::TriangleIndices, + "mesh_task_size" => crate::BuiltIn::MeshTaskSize, + // mesh global variable + "vertex_count" => crate::BuiltIn::VertexCount, + "vertices" => crate::BuiltIn::Vertices, + "primitive_count" => crate::BuiltIn::PrimitiveCount, + "primitives" => crate::BuiltIn::Primitives, _ => return Err(Box::new(Error::UnknownBuiltin(span))), }; match built_in { @@ -61,6 +86,21 @@ pub fn map_built_in( })); } } + crate::BuiltIn::CullPrimitive + | crate::BuiltIn::PointIndex + | crate::BuiltIn::LineIndices + | crate::BuiltIn::TriangleIndices + | crate::BuiltIn::VertexCount + | crate::BuiltIn::Vertices + | crate::BuiltIn::PrimitiveCount + | crate::BuiltIn::Primitives => { + if !enable_extensions.contains(ImplementedEnableExtension::WgpuMeshShader) { + return Err(Box::new(Error::EnableExtensionNotEnabled { + span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })); + } + } _ => {} } Ok(built_in) diff --git a/third_party/rust/naga/src/front/wgsl/parse/directive/enable_extension.rs b/third_party/rust/naga/src/front/wgsl/parse/directive/enable_extension.rs @@ -10,6 +10,7 @@ use alloc::boxed::Box; /// Tracks the status of every enable-extension known to Naga. #[derive(Clone, Debug, Eq, PartialEq)] pub struct EnableExtensions { + wgpu_mesh_shader: bool, dual_source_blending: bool, /// Whether `enable f16;` was written earlier in the shader module. f16: bool, @@ -19,6 +20,7 @@ pub struct EnableExtensions { impl EnableExtensions { pub(crate) const fn empty() -> Self { Self { + wgpu_mesh_shader: false, f16: false, dual_source_blending: false, clip_distances: false, @@ -28,6 +30,7 @@ impl EnableExtensions { /// Add an enable-extension to the set requested by a module. pub(crate) fn add(&mut self, ext: ImplementedEnableExtension) { let field = match ext { + ImplementedEnableExtension::WgpuMeshShader => &mut self.wgpu_mesh_shader, ImplementedEnableExtension::DualSourceBlending => &mut self.dual_source_blending, ImplementedEnableExtension::F16 => &mut self.f16, ImplementedEnableExtension::ClipDistances => &mut self.clip_distances, @@ -38,6 +41,7 @@ impl EnableExtensions { /// Query whether an enable-extension tracked here has been requested. pub(crate) const fn contains(&self, ext: ImplementedEnableExtension) -> bool { match ext { + ImplementedEnableExtension::WgpuMeshShader => self.wgpu_mesh_shader, ImplementedEnableExtension::DualSourceBlending => self.dual_source_blending, ImplementedEnableExtension::F16 => self.f16, ImplementedEnableExtension::ClipDistances => self.clip_distances, @@ -70,6 +74,7 @@ impl EnableExtension { const F16: &'static str = "f16"; const CLIP_DISTANCES: &'static str = "clip_distances"; const DUAL_SOURCE_BLENDING: &'static str = "dual_source_blending"; + const MESH_SHADER: &'static str = "wgpu_mesh_shader"; const SUBGROUPS: &'static str = "subgroups"; const PRIMITIVE_INDEX: &'static str = "primitive_index"; @@ -81,6 +86,7 @@ impl EnableExtension { Self::DUAL_SOURCE_BLENDING => { Self::Implemented(ImplementedEnableExtension::DualSourceBlending) } + Self::MESH_SHADER => Self::Implemented(ImplementedEnableExtension::WgpuMeshShader), Self::SUBGROUPS => Self::Unimplemented(UnimplementedEnableExtension::Subgroups), Self::PRIMITIVE_INDEX => { Self::Unimplemented(UnimplementedEnableExtension::PrimitiveIndex) @@ -93,6 +99,7 @@ impl EnableExtension { pub const fn to_ident(self) -> &'static str { match self { Self::Implemented(kind) => match kind { + ImplementedEnableExtension::WgpuMeshShader => Self::MESH_SHADER, ImplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING, ImplementedEnableExtension::F16 => Self::F16, ImplementedEnableExtension::ClipDistances => Self::CLIP_DISTANCES, @@ -126,6 +133,8 @@ pub enum ImplementedEnableExtension { /// /// [`enable clip_distances;`]: https://www.w3.org/TR/WGSL/#extension-clip_distances ClipDistances, + /// Enables the `wgpu_mesh_shader` extension, native only + WgpuMeshShader, } /// A variant of [`EnableExtension::Unimplemented`]. diff --git a/third_party/rust/naga/src/front/wgsl/parse/mod.rs b/third_party/rust/naga/src/front/wgsl/parse/mod.rs @@ -178,6 +178,7 @@ struct BindingParser<'a> { sampling: ParsedAttribute<crate::Sampling>, invariant: ParsedAttribute<bool>, blend_src: ParsedAttribute<Handle<ast::Expression<'a>>>, + per_primitive: ParsedAttribute<()>, } impl<'a> BindingParser<'a> { @@ -238,6 +239,18 @@ impl<'a> BindingParser<'a> { lexer.skip(Token::Separator(',')); lexer.expect(Token::Paren(')'))?; } + "per_primitive" => { + if !lexer + .enable_extensions + .contains(ImplementedEnableExtension::WgpuMeshShader) + { + return Err(Box::new(Error::EnableExtensionNotEnabled { + span: name_span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })); + } + self.per_primitive.set((), name_span)?; + } _ => return Err(Box::new(Error::UnknownAttribute(name_span))), } Ok(()) @@ -251,9 +264,10 @@ impl<'a> BindingParser<'a> { self.sampling.value, self.invariant.value.unwrap_or_default(), self.blend_src.value, + self.per_primitive.value, ) { - (None, None, None, None, false, None) => Ok(None), - (Some(location), None, interpolation, sampling, false, blend_src) => { + (None, None, None, None, false, None, None) => Ok(None), + (Some(location), None, interpolation, sampling, false, blend_src, per_primitive) => { // Before handing over the completed `Module`, we call // `apply_default_interpolation` to ensure that the interpolation and // sampling have been explicitly specified on all vertex shader output and fragment @@ -263,17 +277,18 @@ impl<'a> BindingParser<'a> { interpolation, sampling, blend_src, + per_primitive: per_primitive.is_some(), })) } - (None, Some(crate::BuiltIn::Position { .. }), None, None, invariant, None) => { + (None, Some(crate::BuiltIn::Position { .. }), None, None, invariant, None, None) => { Ok(Some(ast::Binding::BuiltIn(crate::BuiltIn::Position { invariant, }))) } - (None, Some(built_in), None, None, false, None) => { + (None, Some(built_in), None, None, false, None, None) => { Ok(Some(ast::Binding::BuiltIn(built_in))) } - (_, _, _, _, _, _) => Err(Box::new(Error::InconsistentBinding(span))), + (_, _, _, _, _, _, _) => Err(Box::new(Error::InconsistentBinding(span))), } } } @@ -1318,7 +1333,7 @@ impl Parser { }; crate::AddressSpace::Storage { access } } - _ => conv::map_address_space(class_str, span)?, + _ => conv::map_address_space(class_str, span, &lexer.enable_extensions)?, }; lexer.expect(Token::Paren('>'))?; } @@ -1691,7 +1706,7 @@ impl Parser { "ptr" => { lexer.expect_generic_paren('<')?; let (ident, span) = lexer.next_ident_with_span()?; - let mut space = conv::map_address_space(ident, span)?; + let mut space = conv::map_address_space(ident, span, &lexer.enable_extensions)?; lexer.expect(Token::Separator(','))?; let base = self.type_decl(lexer, ctx)?; if let crate::AddressSpace::Storage { ref mut access } = space { @@ -2790,12 +2805,14 @@ impl Parser { // read attributes let mut binding = None; let mut stage = ParsedAttribute::default(); - let mut compute_span = Span::new(0, 0); + let mut compute_like_span = Span::new(0, 0); let mut workgroup_size = ParsedAttribute::default(); let mut early_depth_test = ParsedAttribute::default(); let (mut bind_index, mut bind_group) = (ParsedAttribute::default(), ParsedAttribute::default()); let mut id = ParsedAttribute::default(); + let mut payload = ParsedAttribute::default(); + let mut mesh_output = ParsedAttribute::default(); let mut must_use: ParsedAttribute<Span> = ParsedAttribute::default(); @@ -2854,7 +2871,51 @@ impl Parser { } "compute" => { stage.set(ShaderStage::Compute, name_span)?; - compute_span = name_span; + compute_like_span = name_span; + } + "task" => { + if !lexer + .enable_extensions + .contains(ImplementedEnableExtension::WgpuMeshShader) + { + return Err(Box::new(Error::EnableExtensionNotEnabled { + span: name_span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })); + } + stage.set(ShaderStage::Task, name_span)?; + compute_like_span = name_span; + } + "mesh" => { + if !lexer + .enable_extensions + .contains(ImplementedEnableExtension::WgpuMeshShader) + { + return Err(Box::new(Error::EnableExtensionNotEnabled { + span: name_span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })); + } + stage.set(ShaderStage::Mesh, name_span)?; + compute_like_span = name_span; + + lexer.expect(Token::Paren('('))?; + mesh_output.set(lexer.next_ident_with_span()?, name_span)?; + lexer.expect(Token::Paren(')'))?; + } + "payload" => { + if !lexer + .enable_extensions + .contains(ImplementedEnableExtension::WgpuMeshShader) + { + return Err(Box::new(Error::EnableExtensionNotEnabled { + span: name_span, + kind: ImplementedEnableExtension::WgpuMeshShader.into(), + })); + } + lexer.expect(Token::Paren('('))?; + payload.set(lexer.next_ident_with_span()?, name_span)?; + lexer.expect(Token::Paren(')'))?; } "workgroup_size" => { lexer.expect(Token::Paren('('))?; @@ -3020,13 +3081,16 @@ impl Parser { )?; Some(ast::GlobalDeclKind::Fn(ast::Function { entry_point: if let Some(stage) = stage.value { - if stage == ShaderStage::Compute && workgroup_size.value.is_none() { - return Err(Box::new(Error::MissingWorkgroupSize(compute_span))); + if stage.compute_like() && workgroup_size.value.is_none() { + return Err(Box::new(Error::MissingWorkgroupSize(compute_like_span))); } + Some(ast::EntryPoint { stage, early_depth_test: early_depth_test.value, workgroup_size: workgroup_size.value, + mesh_output_variable: mesh_output.value, + task_payload: payload.value, }) } else { None diff --git a/third_party/rust/naga/src/ir/mod.rs b/third_party/rust/naga/src/ir/mod.rs @@ -409,7 +409,7 @@ pub enum BuiltIn { PointCoord, /// Read in fragment shaders FrontFacing, - /// Read in fragment shaders, in the future may written in mesh shaders + /// Read in fragment shaders, written in mesh shaders PrimitiveIndex, /// Read in fragment shaders Barycentric, @@ -450,6 +450,15 @@ pub enum BuiltIn { LineIndices, /// Written in mesh shaders TriangleIndices, + + /// Written to a workgroup variable in mesh shaders + VertexCount, + /// Written to a workgroup variable in mesh shaders + Vertices, + /// Written to a workgroup variable in mesh shaders + PrimitiveCount, + /// Written to a workgroup variable in mesh shaders + Primitives, } /// Number of bytes per scalar. @@ -2211,8 +2220,6 @@ pub enum Statement { /// The specific operation we're performing on `query`. fun: RayQueryFunction, }, - /// A mesh shader intrinsic. - MeshFunction(MeshFunction), /// Calculate a bitmask using a boolean from each active thread in the subgroup SubgroupBallot { /// The [`SubgroupBallotResult`] expression representing this load's result. @@ -2569,7 +2576,7 @@ pub struct DocComments { } /// The output topology for a mesh shader. Note that mesh shaders don't allow things like triangle-strips. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2583,7 +2590,7 @@ pub enum MeshOutputTopology { } /// Information specific to mesh shader entry points. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] @@ -2603,29 +2610,8 @@ pub struct MeshStageInfo { pub vertex_output_type: Handle<Type>, /// The type used by primitive outputs, i.e. what is passed to `setPrimitive`. pub primitive_output_type: Handle<Type>, -} - -/// Mesh shader intrinsics -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "serialize", derive(Serialize))] -#[cfg_attr(feature = "deserialize", derive(Deserialize))] -#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -pub enum MeshFunction { - /// Sets the number of vertices and primitives that will be outputted. - SetMeshOutputs { - vertex_count: Handle<Expression>, - primitive_count: Handle<Expression>, - }, - /// Sets the output vertex at a given index. - SetVertex { - index: Handle<Expression>, - value: Handle<Expression>, - }, - /// Sets the output primitive at a given index. - SetPrimitive { - index: Handle<Expression>, - value: Handle<Expression>, - }, + /// The global variable holding the outputted vertices, primitives, and counts + pub output_variable: Handle<GlobalVariable>, } /// Shader module. diff --git a/third_party/rust/naga/src/proc/mod.rs b/third_party/rust/naga/src/proc/mod.rs @@ -27,6 +27,8 @@ use thiserror::Error; pub use type_methods::min_max_float_representable_by; pub use typifier::{compare_types, ResolveContext, ResolveError, TypeResolution}; +use crate::non_max_u32::NonMaxU32; + impl From<super::StorageFormat> for super::Scalar { fn from(format: super::StorageFormat) -> Self { use super::{ScalarKind as Sk, StorageFormat as Sf}; @@ -653,3 +655,178 @@ fn test_matrix_size() { 48, ); } + +impl crate::Module { + /// Extracts mesh shader info from a mesh output global variable. Used in frontends + /// and by validators. This only validates the output variable itself, and not the + /// vertex and primitive output types. + /// + /// The output contains the extracted mesh stage info, with overrides unset, + /// and then the overrides separately. This is because the overrides should be + /// treated as expressions elsewhere, but that requires mutably modifying the + /// module and the expressions should only be created at parse time, not validation + /// time. + #[allow(clippy::type_complexity)] + pub fn analyze_mesh_shader_info( + &self, + gv: crate::Handle<crate::GlobalVariable>, + ) -> ( + crate::MeshStageInfo, + [Option<crate::Handle<crate::Override>>; 2], + Option<crate::WithSpan<crate::valid::EntryPointError>>, + ) { + use crate::span::AddSpan; + use crate::valid::EntryPointError; + #[derive(Default)] + struct OutError { + pub inner: Option<EntryPointError>, + } + impl OutError { + pub fn set(&mut self, err: EntryPointError) { + if self.inner.is_none() { + self.inner = Some(err); + } + } + } + + // Used to temporarily initialize stuff + let null_type = crate::Handle::new(NonMaxU32::new(0).unwrap()); + let mut output = crate::MeshStageInfo { + topology: crate::MeshOutputTopology::Triangles, + max_vertices: 0, + max_vertices_override: None, + max_primitives: 0, + max_primitives_override: None, + vertex_output_type: null_type, + primitive_output_type: null_type, + output_variable: gv, + }; + // Stores the error to output, if any. + let mut error = OutError::default(); + let r#type = &self.types[self.global_variables[gv].ty].inner; + + let mut topology = output.topology; + // Max, max override, type + let mut vertex_info = (0, None, null_type); + let mut primitive_info = (0, None, null_type); + + match r#type { + &crate::TypeInner::Struct { ref members, .. } => { + let mut builtins = crate::FastHashSet::default(); + for member in members { + match member.binding { + Some(crate::Binding::BuiltIn(crate::BuiltIn::VertexCount)) => { + // Must have type u32 + if self.types[member.ty].inner.scalar() != Some(crate::Scalar::U32) { + error.set(EntryPointError::BadMeshOutputVariableField); + } + // Each builtin should only occur once + if builtins.contains(&crate::BuiltIn::VertexCount) { + error.set(EntryPointError::BadMeshOutputVariableType); + } + builtins.insert(crate::BuiltIn::VertexCount); + } + Some(crate::Binding::BuiltIn(crate::BuiltIn::PrimitiveCount)) => { + // Must have type u32 + if self.types[member.ty].inner.scalar() != Some(crate::Scalar::U32) { + error.set(EntryPointError::BadMeshOutputVariableField); + } + // Each builtin should only occur once + if builtins.contains(&crate::BuiltIn::PrimitiveCount) { + error.set(EntryPointError::BadMeshOutputVariableType); + } + builtins.insert(crate::BuiltIn::PrimitiveCount); + } + Some(crate::Binding::BuiltIn( + crate::BuiltIn::Vertices | crate::BuiltIn::Primitives, + )) => { + let ty = &self.types[member.ty].inner; + // Analyze the array type to determine size and vertex/primitive type + let (a, b, c) = match ty { + &crate::TypeInner::Array { base, size, .. } => { + let ty = base; + let (max, max_override) = match size { + crate::ArraySize::Constant(a) => (a.get(), None), + crate::ArraySize::Pending(o) => (0, Some(o)), + crate::ArraySize::Dynamic => { + error.set(EntryPointError::BadMeshOutputVariableField); + (0, None) + } + }; + (max, max_override, ty) + } + _ => { + error.set(EntryPointError::BadMeshOutputVariableField); + (0, None, null_type) + } + }; + if matches!( + member.binding, + Some(crate::Binding::BuiltIn(crate::BuiltIn::Primitives)) + ) { + // Primitives require special analysis to determine topology + primitive_info = (a, b, c); + match self.types[c].inner { + crate::TypeInner::Struct { ref members, .. } => { + for member in members { + match member.binding { + Some(crate::Binding::BuiltIn( + crate::BuiltIn::PointIndex, + )) => { + topology = crate::MeshOutputTopology::Points; + } + Some(crate::Binding::BuiltIn( + crate::BuiltIn::LineIndices, + )) => { + topology = crate::MeshOutputTopology::Lines; + } + Some(crate::Binding::BuiltIn( + crate::BuiltIn::TriangleIndices, + )) => { + topology = crate::MeshOutputTopology::Triangles; + } + _ => (), + } + } + } + _ => (), + } + // Each builtin should only occur once + if builtins.contains(&crate::BuiltIn::Primitives) { + error.set(EntryPointError::BadMeshOutputVariableType); + } + builtins.insert(crate::BuiltIn::Primitives); + } else { + vertex_info = (a, b, c); + // Each builtin should only occur once + if builtins.contains(&crate::BuiltIn::Vertices) { + error.set(EntryPointError::BadMeshOutputVariableType); + } + builtins.insert(crate::BuiltIn::Vertices); + } + } + _ => error.set(EntryPointError::BadMeshOutputVariableType), + } + } + output = crate::MeshStageInfo { + topology, + max_vertices: vertex_info.0, + max_vertices_override: None, + vertex_output_type: vertex_info.2, + max_primitives: primitive_info.0, + max_primitives_override: None, + primitive_output_type: primitive_info.2, + ..output + } + } + _ => error.set(EntryPointError::BadMeshOutputVariableType), + } + ( + output, + [vertex_info.1, primitive_info.1], + error + .inner + .map(|a| a.with_span_handle(self.global_variables[gv].ty, &self.types)), + ) + } +} diff --git a/third_party/rust/naga/src/proc/terminator.rs b/third_party/rust/naga/src/proc/terminator.rs @@ -36,7 +36,6 @@ pub fn ensure_block_returns(block: &mut crate::Block) { | S::ImageStore { .. } | S::Call { .. } | S::RayQuery { .. } - | S::MeshFunction(..) | S::Atomic { .. } | S::ImageAtomic { .. } | S::WorkGroupUniformLoad { .. } diff --git a/third_party/rust/naga/src/valid/analyzer.rs b/third_party/rust/naga/src/valid/analyzer.rs @@ -85,25 +85,6 @@ struct FunctionUniformity { exit: ExitFlags, } -/// Mesh shader related characteristics of a function. -#[derive(Debug, Clone, Default)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] -#[cfg_attr(test, derive(PartialEq))] -pub struct FunctionMeshShaderInfo { - /// The type of value this function passes to [`SetVertex`], and the - /// expression that first established it. - /// - /// [`SetVertex`]: crate::ir::MeshFunction::SetVertex - pub vertex_type: Option<(Handle<crate::Type>, Handle<crate::Expression>)>, - - /// The type of value this function passes to [`SetPrimitive`], and the - /// expression that first established it. - /// - /// [`SetPrimitive`]: crate::ir::MeshFunction::SetPrimitive - pub primitive_type: Option<(Handle<crate::Type>, Handle<crate::Expression>)>, -} - impl ops::BitOr for FunctionUniformity { type Output = Self; fn bitor(self, other: Self) -> Self { @@ -321,9 +302,6 @@ pub struct FunctionInfo { /// See [`DiagnosticFilterNode`] for details on how the tree is represented and used in /// validation. diagnostic_filter_leaf: Option<Handle<DiagnosticFilterNode>>, - - /// Mesh shader info for this function and its callees. - pub mesh_shader_info: FunctionMeshShaderInfo, } impl FunctionInfo { @@ -520,9 +498,6 @@ impl FunctionInfo { *mine |= *other; } - // Inherit mesh output types from our callees. - self.try_update_mesh_info(&callee.mesh_shader_info)?; - Ok(FunctionUniformity { result: callee.uniformity.clone(), exit: if callee.may_kill { @@ -1155,36 +1130,6 @@ impl FunctionInfo { } FunctionUniformity::new() } - S::MeshFunction(func) => { - self.available_stages |= ShaderStages::MESH; - match &func { - // TODO: double check all of this uniformity stuff. I frankly don't fully understand all of it. - &crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - } => { - let _ = self.add_ref(vertex_count); - let _ = self.add_ref(primitive_count); - FunctionUniformity::new() - } - &crate::MeshFunction::SetVertex { index, value } - | &crate::MeshFunction::SetPrimitive { index, value } => { - let _ = self.add_ref(index); - let _ = self.add_ref(value); - let ty = self.expressions[value.index()].ty.handle().ok_or( - FunctionError::InvalidMeshShaderOutputType(value).with_span(), - )?; - - if matches!(func, crate::MeshFunction::SetVertex { .. }) { - self.try_update_mesh_vertex_type(ty, value)?; - } else { - self.try_update_mesh_primitive_type(ty, value)?; - }; - - FunctionUniformity::new() - } - } - } S::SubgroupBallot { result: _, predicate, @@ -1230,72 +1175,6 @@ impl FunctionInfo { } Ok(combined_uniformity) } - - /// Note the type of value passed to [`SetVertex`]. - /// - /// Record that this function passed a value of type `ty` as the second - /// argument to the [`SetVertex`] builtin function. All calls to - /// `SetVertex` must pass the same type, and this must match the - /// function's [`vertex_output_type`]. - /// - /// [`SetVertex`]: crate::ir::MeshFunction::SetVertex - /// [`vertex_output_type`]: crate::ir::MeshStageInfo::vertex_output_type - fn try_update_mesh_vertex_type( - &mut self, - ty: Handle<crate::Type>, - value: Handle<crate::Expression>, - ) -> Result<(), WithSpan<FunctionError>> { - if let &Some(ref existing) = &self.mesh_shader_info.vertex_type { - if existing.0 != ty { - return Err( - FunctionError::ConflictingMeshOutputTypes(existing.1, value).with_span() - ); - } - } else { - self.mesh_shader_info.vertex_type = Some((ty, value)); - } - Ok(()) - } - - /// Note the type of value passed to [`SetPrimitive`]. - /// - /// Record that this function passed a value of type `ty` as the second - /// argument to the [`SetPrimitive`] builtin function. All calls to - /// `SetPrimitive` must pass the same type, and this must match the - /// function's [`primitive_output_type`]. - /// - /// [`SetPrimitive`]: crate::ir::MeshFunction::SetPrimitive - /// [`primitive_output_type`]: crate::ir::MeshStageInfo::primitive_output_type - fn try_update_mesh_primitive_type( - &mut self, - ty: Handle<crate::Type>, - value: Handle<crate::Expression>, - ) -> Result<(), WithSpan<FunctionError>> { - if let &Some(ref existing) = &self.mesh_shader_info.primitive_type { - if existing.0 != ty { - return Err( - FunctionError::ConflictingMeshOutputTypes(existing.1, value).with_span() - ); - } - } else { - self.mesh_shader_info.primitive_type = Some((ty, value)); - } - Ok(()) - } - - /// Update this function's mesh shader info, given that it calls `callee`. - fn try_update_mesh_info( - &mut self, - callee: &FunctionMeshShaderInfo, - ) -> Result<(), WithSpan<FunctionError>> { - if let &Some(ref other_vertex) = &callee.vertex_type { - self.try_update_mesh_vertex_type(other_vertex.0, other_vertex.1)?; - } - if let &Some(ref other_primitive) = &callee.primitive_type { - self.try_update_mesh_primitive_type(other_primitive.0, other_primitive.1)?; - } - Ok(()) - } } impl ModuleInfo { @@ -1331,7 +1210,6 @@ impl ModuleInfo { sampling: crate::FastHashSet::default(), dual_source_blending: false, diagnostic_filter_leaf: fun.diagnostic_filter_leaf, - mesh_shader_info: FunctionMeshShaderInfo::default(), }; let resolve_context = ResolveContext::with_locals(module, &fun.local_variables, &fun.arguments); @@ -1465,7 +1343,6 @@ fn uniform_control_flow() { sampling: crate::FastHashSet::default(), dual_source_blending: false, diagnostic_filter_leaf: None, - mesh_shader_info: FunctionMeshShaderInfo::default(), }; let resolve_context = ResolveContext { constants: &Arena::new(), diff --git a/third_party/rust/naga/src/valid/function.rs b/third_party/rust/naga/src/valid/function.rs @@ -1547,41 +1547,6 @@ impl super::Validator { crate::RayQueryFunction::Terminate => {} } } - S::MeshFunction(func) => { - let ensure_u32 = - |expr: Handle<crate::Expression>| -> Result<(), WithSpan<FunctionError>> { - let u32_ty = TypeResolution::Value(Ti::Scalar(crate::Scalar::U32)); - let ty = context - .resolve_type_impl(expr, &self.valid_expression_set) - .map_err_inner(|source| { - FunctionError::Expression { - source, - handle: expr, - } - .with_span_handle(expr, context.expressions) - })?; - if !context.compare_types(&u32_ty, ty) { - return Err(FunctionError::InvalidMeshFunctionCall(expr) - .with_span_handle(expr, context.expressions)); - } - Ok(()) - }; - match func { - crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - } => { - ensure_u32(vertex_count)?; - ensure_u32(primitive_count)?; - } - crate::MeshFunction::SetVertex { index, value: _ } - | crate::MeshFunction::SetPrimitive { index, value: _ } => { - ensure_u32(index)?; - // Value is validated elsewhere (since the value type isn't known ahead of time but must match for all calls - // in a function or the function's called functions) - } - } - } S::SubgroupBallot { result, predicate } => { stages &= self.subgroup_stages; if !self.capabilities.contains(super::Capabilities::SUBGROUP) { diff --git a/third_party/rust/naga/src/valid/handles.rs b/third_party/rust/naga/src/valid/handles.rs @@ -237,6 +237,7 @@ impl super::Validator { Self::validate_global_variable_handle(task_payload, global_variables)?; } if let Some(ref mesh_info) = entry_point.mesh_info { + Self::validate_global_variable_handle(mesh_info.output_variable, global_variables)?; validate_type(mesh_info.vertex_output_type)?; validate_type(mesh_info.primitive_output_type)?; for ov in mesh_info @@ -815,22 +816,6 @@ impl super::Validator { } Ok(()) } - crate::Statement::MeshFunction(func) => match func { - crate::MeshFunction::SetMeshOutputs { - vertex_count, - primitive_count, - } => { - validate_expr(vertex_count)?; - validate_expr(primitive_count)?; - Ok(()) - } - crate::MeshFunction::SetVertex { index, value } - | crate::MeshFunction::SetPrimitive { index, value } => { - validate_expr(index)?; - validate_expr(value)?; - Ok(()) - } - }, crate::Statement::SubgroupBallot { result, predicate } => { validate_expr_opt(predicate)?; validate_expr(result)?; diff --git a/third_party/rust/naga/src/valid/interface.rs b/third_party/rust/naga/src/valid/interface.rs @@ -98,8 +98,6 @@ pub enum VaryingError { InvalidPerPrimitive, #[error("Non-builtin members of a mesh primitive output struct must be decorated with `@per_primitive`")] MissingPerPrimitive, - #[error("The `MESH_SHADER` capability must be enabled to use per-primitive fragment inputs.")] - PerPrimitiveNotAllowed, } #[derive(Clone, Debug, thiserror::Error)] @@ -131,6 +129,9 @@ pub enum EntryPointError { InvalidIntegerInterpolation { location: u32 }, #[error(transparent)] Function(#[from] FunctionError), + #[error("Capability {0:?} is not supported")] + UnsupportedCapability(Capabilities), + #[error("mesh shader entry point missing mesh shader attributes")] ExpectedMeshShaderAttributes, #[error("Non mesh shader entry point cannot have mesh shader attributes")] @@ -141,24 +142,28 @@ pub enum EntryPointError { TaskPayloadWrongAddressSpace, #[error("For a task payload to be used, it must be declared with @payload")] WrongTaskPayloadUsed, - #[error("A function can only set vertex and primitive types that correspond to the mesh shader attributes")] - WrongMeshOutputType, - #[error("Only mesh shader entry points can write to mesh output vertices and primitives")] - UnexpectedMeshShaderOutput, - #[error("Mesh shader entry point cannot have a return type")] - UnexpectedMeshShaderEntryResult, #[error("Task shader entry point must return @builtin(mesh_task_size) vec3<u32>")] WrongTaskShaderEntryResult, - #[error("Mesh output type must be a user-defined struct.")] - InvalidMeshOutputType, - #[error("Mesh primitive outputs must have exactly one of `@builtin(triangle_indices)`, `@builtin(line_indices)`, or `@builtin(point_index)`")] - InvalidMeshPrimitiveOutputType, #[error("Task shaders must declare a task payload output")] ExpectedTaskPayload, #[error( - "The `MESH_SHADER` capability must be enabled to compile mesh shaders and task shaders." + "Mesh shader output variable must be a struct with fields that are all allowed builtins" )] - MeshShaderCapabilityDisabled, + BadMeshOutputVariableType, + #[error("Mesh shader output variable fields must have types that are in accordance with the mesh shader spec")] + BadMeshOutputVariableField, + #[error("Mesh shader entry point cannot have a return type")] + UnexpectedMeshShaderEntryResult, + #[error( + "Mesh output type must be a user-defined struct with fields in alignment with the mesh shader spec" + )] + InvalidMeshOutputType, + #[error("Mesh primitive outputs must have exactly one of `@builtin(triangle_indices)`, `@builtin(line_indices)`, or `@builtin(point_index)`")] + InvalidMeshPrimitiveOutputType, + #[error("Mesh output global variable must live in the workgroup address space")] + WrongMeshOutputAddressSpace, + #[error("Task payload must be at least 4 bytes, but is {0} bytes")] + TaskPayloadTooSmall(u32), } fn storage_usage(access: crate::StorageAccess) -> GlobalUse { @@ -312,7 +317,10 @@ impl VaryingContext<'_> { *ty_inner == Ti::Scalar(crate::Scalar::BOOL), ), Bi::PrimitiveIndex => ( - self.stage == St::Fragment && !self.output, + (self.stage == St::Fragment && !self.output) + || (self.stage == St::Mesh + && self.output + && self.mesh_output_type == MeshOutputType::PrimitiveOutput), *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::Barycentric => ( @@ -390,7 +398,29 @@ impl VaryingContext<'_> { scalar: crate::Scalar::U32, }, ), + // Validated elsewhere, shouldn't be here + Bi::VertexCount | Bi::PrimitiveCount | Bi::Vertices | Bi::Primitives => { + (false, true) + } }; + match built_in { + Bi::CullPrimitive + | Bi::PointIndex + | Bi::LineIndices + | Bi::TriangleIndices + | Bi::MeshTaskSize + | Bi::VertexCount + | Bi::PrimitiveCount + | Bi::Vertices + | Bi::Primitives => { + if !self.capabilities.contains(Capabilities::MESH_SHADER) { + return Err(VaryingError::UnsupportedCapability( + Capabilities::MESH_SHADER, + )); + } + } + _ => (), + } if !visible { return Err(VaryingError::InvalidBuiltInStage(built_in)); @@ -408,7 +438,9 @@ impl VaryingContext<'_> { per_primitive, } => { if per_primitive && !self.capabilities.contains(Capabilities::MESH_SHADER) { - return Err(VaryingError::PerPrimitiveNotAllowed); + return Err(VaryingError::UnsupportedCapability( + Capabilities::MESH_SHADER, + )); } // Only IO-shareable types may be stored in locations. if !self.type_info[ty.index()] @@ -549,47 +581,45 @@ impl VaryingContext<'_> { .validate_impl(ep, ty, binding) .map_err(|e| e.with_span_context(span_context)), None => { - match self.types[ty].inner { - crate::TypeInner::Struct { ref members, .. } => { - for (index, member) in members.iter().enumerate() { - let span_context = self.types.get_span_context(ty); - match member.binding { - None => { - if self.flags.contains(super::ValidationFlags::BINDINGS) { - return Err(VaryingError::MemberMissingBinding( - index as u32, - ) - .with_span_context(span_context)); - } - } - Some(ref binding) => self - .validate_impl(ep, member.ty, binding) - .map_err(|e| e.with_span_context(span_context))?, - } - } - - if !self.blend_src_mask.is_empty() { - let span_context = self.types.get_span_context(ty); + let crate::TypeInner::Struct { ref members, .. } = self.types[ty].inner else { + if self.flags.contains(super::ValidationFlags::BINDINGS) { + return Err(VaryingError::MissingBinding.with_span()); + } else { + return Ok(()); + } + }; - // If there's any blend_src usage, it must apply to all members of which there must be exactly 2. - if members.len() != 2 || self.blend_src_mask.len() != 2 { - return Err(VaryingError::IncompleteBlendSrcUsage + for (index, member) in members.iter().enumerate() { + let span_context = self.types.get_span_context(ty); + match member.binding { + None => { + if self.flags.contains(super::ValidationFlags::BINDINGS) { + return Err(VaryingError::MemberMissingBinding(index as u32) .with_span_context(span_context)); } - // Also, all members must have the same type. - if members[0].ty != members[1].ty { - return Err(VaryingError::BlendSrcOutputTypeMismatch { - blend_src_0_type: members[0].ty, - blend_src_1_type: members[1].ty, - } - .with_span_context(span_context)); - } } + Some(ref binding) => self + .validate_impl(ep, member.ty, binding) + .map_err(|e| e.with_span_context(span_context))?, } - _ => { - if self.flags.contains(super::ValidationFlags::BINDINGS) { - return Err(VaryingError::MissingBinding.with_span()); + } + + if !self.blend_src_mask.is_empty() { + let span_context = self.types.get_span_context(ty); + + // If there's any blend_src usage, it must apply to all members of which there must be exactly 2. + if members.len() != 2 || self.blend_src_mask.len() != 2 { + return Err( + VaryingError::IncompleteBlendSrcUsage.with_span_context(span_context) + ); + } + // Also, all members must have the same type. + if members[0].ty != members[1].ty { + return Err(VaryingError::BlendSrcOutputTypeMismatch { + blend_src_0_type: members[0].ty, + blend_src_1_type: members[1].ty, } + .with_span_context(span_context)); } } Ok(()) @@ -838,7 +868,9 @@ impl super::Validator { crate::ShaderStage::Task | crate::ShaderStage::Mesh ) && !self.capabilities.contains(Capabilities::MESH_SHADER) { - return Err(EntryPointError::MeshShaderCapabilityDisabled.with_span()); + return Err( + EntryPointError::UnsupportedCapability(Capabilities::MESH_SHADER).with_span(), + ); } if ep.early_depth_test.is_some() { let required = Capabilities::EARLY_DEPTH_TEST; @@ -870,6 +902,7 @@ impl super::Validator { (crate::ShaderStage::Mesh, &None) => { return Err(EntryPointError::ExpectedMeshShaderAttributes.with_span()); } + (crate::ShaderStage::Mesh, &Some(..)) => {} (_, &Some(_)) => { return Err(EntryPointError::UnexpectedMeshShaderAttributes.with_span()); } @@ -903,6 +936,9 @@ impl super::Validator { } info.insert_global_use(GlobalUse::READ, handle); } + if let Some(ref mesh_info) = ep.mesh_info { + info.insert_global_use(GlobalUse::READ, mesh_info.output_variable); + } } // Other stages must not have a payload. @@ -1022,6 +1058,11 @@ impl super::Validator { return Err(EntryPointError::WrongTaskPayloadUsed .with_span_handle(var_handle, &module.global_variables)); } + let size = module.types[var.ty].inner.size(module.to_ctx()); + if size < 4 { + return Err(EntryPointError::TaskPayloadTooSmall(size) + .with_span_handle(var_handle, &module.global_variables)); + } } let allowed_usage = match var.space { @@ -1076,21 +1117,48 @@ impl super::Validator { // If this is a `Mesh` entry point, check its vertex and primitive output types. // We verified previously that only mesh shaders can have `mesh_info`. if let &Some(ref mesh_info) = &ep.mesh_info { - // Mesh shaders don't return any value. All their results are supplied through - // [`SetVertex`] and [`SetPrimitive`] calls. - if let Some((used_vertex_type, _)) = info.mesh_shader_info.vertex_type { - if used_vertex_type != mesh_info.vertex_output_type { - return Err(EntryPointError::WrongMeshOutputType - .with_span_handle(mesh_info.vertex_output_type, &module.types)); + if module.global_variables[mesh_info.output_variable].space + != crate::AddressSpace::WorkGroup + { + return Err(EntryPointError::WrongMeshOutputAddressSpace.with_span()); + } + + let mut implied = module.analyze_mesh_shader_info(mesh_info.output_variable); + if let Some(e) = implied.2 { + return Err(e); + } + + if let Some(e) = mesh_info.max_vertices_override { + if let crate::Expression::Override(o) = module.global_expressions[e] { + if implied.1[0] != Some(o) { + return Err(EntryPointError::BadMeshOutputVariableType.with_span()); + } } } - if let Some((used_primitive_type, _)) = info.mesh_shader_info.primitive_type { - if used_primitive_type != mesh_info.primitive_output_type { - return Err(EntryPointError::WrongMeshOutputType - .with_span_handle(mesh_info.primitive_output_type, &module.types)); + if let Some(e) = mesh_info.max_primitives_override { + if let crate::Expression::Override(o) = module.global_expressions[e] { + if implied.1[1] != Some(o) { + return Err(EntryPointError::BadMeshOutputVariableType.with_span()); + } } } + implied.0.max_vertices_override = mesh_info.max_vertices_override; + implied.0.max_primitives_override = mesh_info.max_primitives_override; + if implied.0 != *mesh_info { + return Err(EntryPointError::BadMeshOutputVariableType.with_span()); + } + if mesh_info.topology == crate::MeshOutputTopology::Points + && !self + .capabilities + .contains(Capabilities::MESH_SHADER_POINT_TOPOLOGY) + { + return Err(EntryPointError::UnsupportedCapability( + Capabilities::MESH_SHADER_POINT_TOPOLOGY, + ) + .with_span()); + } + self.validate_mesh_output_type( ep, module, @@ -1103,14 +1171,6 @@ impl super::Validator { mesh_info.primitive_output_type, MeshOutputType::PrimitiveOutput, )?; - } else { - // This is not a `Mesh` entry point, so ensure that it never tries to produce - // vertices or primitives. - if info.mesh_shader_info.vertex_type.is_some() - || info.mesh_shader_info.primitive_type.is_some() - { - return Err(EntryPointError::UnexpectedMeshShaderOutput.with_span()); - } } Ok(info) diff --git a/third_party/rust/naga/src/valid/mod.rs b/third_party/rust/naga/src/valid/mod.rs @@ -190,6 +190,8 @@ bitflags::bitflags! { const SHADER_BARYCENTRICS = 1 << 29; /// Support for task shaders, mesh shaders, and per-primitive fragment inputs const MESH_SHADER = 1 << 30; + /// Support for mesh shaders which output points. + const MESH_SHADER_POINT_TOPOLOGY = 1 << 30; } } diff --git a/third_party/rust/wgpu-core/.cargo-checksum.json b/third_party/rust/wgpu-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"9f8b834d9d755f2d8cfa4b8164a6156292ba849b1d4a464f849ae3f843b2ba8e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","build.rs":"5e3619e28faeac243cbae1a5f739ad15035dc9e1254957b64fd1deed6f393c8a","src/as_hal.rs":"5d08d8e49b016abb662957d8e42ab748d580a2f3e449caeeb7311f222b8818f6","src/binding_model.rs":"c18ea748797610688abbfee42e8b58343a8f5f96ad6db87dacddbfa72d082cb3","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"198c23d5d5a0012a0aac58d4a42e7fd5c69776e7b19309720fbb85e699347d0d","src/command/bundle.rs":"899faaf507c4b998e5b801bc3f7e8eed617f5aa36686f43af8f613c0308bb87b","src/command/clear.rs":"d9f0b9ba00e568a4948990b8968a50fd10145c8eff6b7fcecf9df866c91f7c7f","src/command/compute.rs":"d3c6039d002a7feedc00ceea433ebe8f63d847238f84300b72ca3dcd628c9331","src/command/compute_command.rs":"6096eeca3b273005a6d2825a39f3c7beea4ef5104c2ff32b528bff76bef81a42","src/command/draw.rs":"5721868b0aa265037c843c4b4a4487a4f2827efbd65cab5046b9fbf4c54f6892","src/command/encoder.rs":"7655f8c248120f39e37f3ad0f84bd9816df78a75657790ab12d5aba144fef65f","src/command/encoder_command.rs":"41c15cf29ec11859bf7fcbd8e0d9908fdea5e5f8e678e5ebaa7aa2e80cf71926","src/command/ffi.rs":"4924adbb42a670b5e9827c0f2175939981e8fc78a36b2fe370426e8c550a4ce7","src/command/memory_init.rs":"f68a796c4262d261620cf85e5762e267dee013f4ef5d61f67fcb173b59048983","src/command/mod.rs":"38c6adb4ff8dc901efd3e757ac44f97bee76dc59d49022e34f6322c798f96951","src/command/pass.rs":"e92efb6eef955cc329e5c5d2aa49e5be78e42dc82ed62e6878b005f4450e9e80","src/command/query.rs":"dfea49ddf018d506882bb88d7763e808e293530f74749dce5bc5c902286467d1","src/command/ray_tracing.rs":"03d1984cfd365b457355a97d6366f8e32debebb538229dc44431f30b2d967c54","src/command/render.rs":"bc81666e95a2eb2fd042f5dfda6c434f94c7bbef52890fd1054f6525c549df75","src/command/render_command.rs":"032b2913e46cf27ede689278ddbe8255c3c2b6b24ff68559c82d25fc1913d36c","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"96aec060c615a376308ffb42d66969ba6265932869dbdcf1ea6b72e26160951f","src/command/transition_resources.rs":"753cb02adfee4758404c403d19fd76e6c8de77de01435a2cbe2f60bdbe44bde1","src/conv.rs":"6b7e448bb4bae9ec58fc7738e7d5fb77bb28baa0402052d8a47b8dadf95c71d3","src/device/bgl.rs":"b081fe1393f1dd917151efc3a10ee0269fecd3920eac3b45411c1197a98c5a06","src/device/global.rs":"3c11d7ddfa4530bbee4aba7a3ad2fc2dfd812b1d8c1b8bada7882cd4b8abee31","src/device/life.rs":"44bd34cf5ab1c1a21729f2188df6d2ca0238f11c5f723380c8a4a16fbbd90b88","src/device/mod.rs":"08233c44c074a2fb53d402b367293e836008e7049b5641a44802214e4db63114","src/device/queue.rs":"5efe0feb801694293fcc7956565b86c291225b960c5d2e9e80fdd1fef53a4d03","src/device/ray_tracing.rs":"6f8df97f9fb1a3405a651d96619760ba7cf14830e28f65e824413a4f922abd95","src/device/resource.rs":"03ec6c646420bf59c434aa173ee6eeab7419b212c7007d668232bab075b58724","src/device/trace.rs":"022df1e97641b3e615f2974c297ff2c589c61bf1e2a2828236e101165eefa069","src/device/trace/record.rs":"2de83ec5be6e8cae928fe633f527b3eb654e3e58417b31f2c4a7235f8a80102e","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"bd76f9552496996f9eba6502e5caf1bcd6ca33bf3d5008795b5335f74e56fd55","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"308c53e05134e5a48294c61511e43077adfdb5c334237de2016ed4537d562382","src/id.rs":"ec20d5b995178c0e731b1b8cecfd90772ee18dd4d91c28de434039e9c9e50486","src/identity.rs":"712ccda267eb602655c53672a94346aa4c9f88c0044ae6edcd658a814c9a50cf","src/indirect_validation/dispatch.rs":"b15d926e0de732c3c39c965f168f99598fa508ca4b0883061993d99dd644b31a","src/indirect_validation/draw.rs":"6d8338f37f406c6e2cf89713e8493f167e1d8e999737f2976de298810c2ada76","src/indirect_validation/mod.rs":"79466e4f9a59386e833958b3537beed6ffb6a7ee62aaabcf35382c2683998e43","src/indirect_validation/utils.rs":"e6a3b636dd71ff6b01d5abd5a589a0136fb30aa1d517a43f45cf2e5ad54da245","src/indirect_validation/validate_draw.wgsl":"fa7bba5f28c6c181f2d55ecfe386a5e5cd276bcb3c36aa7f963f43c535a9bf9a","src/init_tracker/buffer.rs":"6167a400ab271ba857f1c507e60a46fbd318c185aff87eecf7eb05f7f09b6963","src/init_tracker/mod.rs":"aa87df3428e3b23507377c71eae92dc1dd9f5d5374aa0b03906fb81507fc6ce6","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"e7b9a20e070cc401f75dfe07aceb8f2950a4d99ed8a7d4413ef9f0813f5a8ca1","src/lib.rs":"57d2562e33b04113cc6c2ca3bc9a215ec779a291be82b680ff037fac7d7a8a15","src/lock/mod.rs":"8d3ae3f8d004d7f7d8a3aefe9f30b35669cb8e2409f5fba27b1fcb116b2429c4","src/lock/observing.rs":"5bf62cef9f3ae67e99af640442fadd4e1f762480d990ee69ed9924c9e94a8dce","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"a95d6bf7f2ef510047a4c33687076beccf38a0148aac3261bd29fa7555e3f488","src/lock/vanilla.rs":"ca8156d4c981473d437db1056487a44c714760d685819eaff8cf82fb0098a608","src/pipeline.rs":"d84fbf90eda12f4acbb0ff8f8166a6b498ce89da52beacf5b81a6b06afa907c9","src/pipeline_cache.rs":"f6a82de6cf362be50335d26e8eed983b53812a8444dff9c8c988a075f3325f8f","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"edd9ce3be749a380c99be8e517963844ac04e3320085e7367a5e3a11e28efad9","src/ray_tracing.rs":"ae43907290f003f6247bb599927401bd768865f7773a41c327dc73fade014ede","src/registry.rs":"2a76c6397998d263b6f6347299f04a8d27ea4df7dda200e98f205cfa3850dadb","src/resource.rs":"59a2b8093790d85724960ceec5a421905e20b665c9e9b1b231b079cccbc51291","src/scratch.rs":"ea5c40e4d18a12f09cc1038f2dcdddb69b13e99275ac987d826658229a39b326","src/snatch.rs":"bf422810afd952894e365cd397763d42d6365ce3c5a5b4c1170566432f462939","src/storage.rs":"1a5bbf125a1cf65a36d8580e426ef1847c1638003fea0c6f76e309f5923b7692","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"89444ad79900c12c2dc44780f1525cd0554d6ed1d9038938dd0075e8173ae59d","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"7f2393d16d0e8f624327c7a3a1de7176f945f3d33bfd3e12640faddc5c2c9f83","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"c28de55e31cdde3feb067945a04446dc5343a39418c4b9c2c76148172e7ba855","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"34e72a20364d3ce642c21b29a089811503aa2fb4e7dab1a1e20d8ddd598742d7","src/validation.rs":"1c2e91bcf5863b1ec00b85dd10588a8772b620d44e36b762f069d35b59a84ae4","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"9f8b834d9d755f2d8cfa4b8164a6156292ba849b1d4a464f849ae3f843b2ba8e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","build.rs":"5e3619e28faeac243cbae1a5f739ad15035dc9e1254957b64fd1deed6f393c8a","src/as_hal.rs":"5d08d8e49b016abb662957d8e42ab748d580a2f3e449caeeb7311f222b8818f6","src/binding_model.rs":"bef3fa63ac64093f496bb2c192f9a54919ceec560c04d5de5a57dd090b4902e6","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"550a1bb23d6082fc9a83ebaf6b5deeab15b33ebb764ff9f9fe866b172423b0f6","src/command/bundle.rs":"899faaf507c4b998e5b801bc3f7e8eed617f5aa36686f43af8f613c0308bb87b","src/command/clear.rs":"d9f0b9ba00e568a4948990b8968a50fd10145c8eff6b7fcecf9df866c91f7c7f","src/command/compute.rs":"d3c6039d002a7feedc00ceea433ebe8f63d847238f84300b72ca3dcd628c9331","src/command/compute_command.rs":"6096eeca3b273005a6d2825a39f3c7beea4ef5104c2ff32b528bff76bef81a42","src/command/draw.rs":"5721868b0aa265037c843c4b4a4487a4f2827efbd65cab5046b9fbf4c54f6892","src/command/encoder.rs":"7655f8c248120f39e37f3ad0f84bd9816df78a75657790ab12d5aba144fef65f","src/command/encoder_command.rs":"41c15cf29ec11859bf7fcbd8e0d9908fdea5e5f8e678e5ebaa7aa2e80cf71926","src/command/ffi.rs":"4924adbb42a670b5e9827c0f2175939981e8fc78a36b2fe370426e8c550a4ce7","src/command/memory_init.rs":"f68a796c4262d261620cf85e5762e267dee013f4ef5d61f67fcb173b59048983","src/command/mod.rs":"38c6adb4ff8dc901efd3e757ac44f97bee76dc59d49022e34f6322c798f96951","src/command/pass.rs":"e92efb6eef955cc329e5c5d2aa49e5be78e42dc82ed62e6878b005f4450e9e80","src/command/query.rs":"dfea49ddf018d506882bb88d7763e808e293530f74749dce5bc5c902286467d1","src/command/ray_tracing.rs":"03d1984cfd365b457355a97d6366f8e32debebb538229dc44431f30b2d967c54","src/command/render.rs":"bc81666e95a2eb2fd042f5dfda6c434f94c7bbef52890fd1054f6525c549df75","src/command/render_command.rs":"032b2913e46cf27ede689278ddbe8255c3c2b6b24ff68559c82d25fc1913d36c","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"a96400b752ae00060d4d3dd82ac68bec1a2a7ee35505b9b760f9851c0fee95dd","src/command/transition_resources.rs":"753cb02adfee4758404c403d19fd76e6c8de77de01435a2cbe2f60bdbe44bde1","src/conv.rs":"6b7e448bb4bae9ec58fc7738e7d5fb77bb28baa0402052d8a47b8dadf95c71d3","src/device/bgl.rs":"b081fe1393f1dd917151efc3a10ee0269fecd3920eac3b45411c1197a98c5a06","src/device/global.rs":"3c11d7ddfa4530bbee4aba7a3ad2fc2dfd812b1d8c1b8bada7882cd4b8abee31","src/device/life.rs":"44bd34cf5ab1c1a21729f2188df6d2ca0238f11c5f723380c8a4a16fbbd90b88","src/device/mod.rs":"61bd158c41bd1b759f6e748c0c39eae2a2bde7ed6faf6bf9c4fb86d81a5f5948","src/device/queue.rs":"fe7043aaf4eded0813c37991bb03c0a7cda5c3f9677e2e37881f574f57753450","src/device/ray_tracing.rs":"6f8df97f9fb1a3405a651d96619760ba7cf14830e28f65e824413a4f922abd95","src/device/resource.rs":"fef53ca7c80b98dbbbdcfd09ff9e0912f6b0ef0915e62006841149b569af0198","src/device/trace.rs":"022df1e97641b3e615f2974c297ff2c589c61bf1e2a2828236e101165eefa069","src/device/trace/record.rs":"2de83ec5be6e8cae928fe633f527b3eb654e3e58417b31f2c4a7235f8a80102e","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"bd76f9552496996f9eba6502e5caf1bcd6ca33bf3d5008795b5335f74e56fd55","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"308c53e05134e5a48294c61511e43077adfdb5c334237de2016ed4537d562382","src/id.rs":"ec20d5b995178c0e731b1b8cecfd90772ee18dd4d91c28de434039e9c9e50486","src/identity.rs":"712ccda267eb602655c53672a94346aa4c9f88c0044ae6edcd658a814c9a50cf","src/indirect_validation/dispatch.rs":"b15d926e0de732c3c39c965f168f99598fa508ca4b0883061993d99dd644b31a","src/indirect_validation/draw.rs":"6d8338f37f406c6e2cf89713e8493f167e1d8e999737f2976de298810c2ada76","src/indirect_validation/mod.rs":"79466e4f9a59386e833958b3537beed6ffb6a7ee62aaabcf35382c2683998e43","src/indirect_validation/utils.rs":"e6a3b636dd71ff6b01d5abd5a589a0136fb30aa1d517a43f45cf2e5ad54da245","src/indirect_validation/validate_draw.wgsl":"fa7bba5f28c6c181f2d55ecfe386a5e5cd276bcb3c36aa7f963f43c535a9bf9a","src/init_tracker/buffer.rs":"6167a400ab271ba857f1c507e60a46fbd318c185aff87eecf7eb05f7f09b6963","src/init_tracker/mod.rs":"aa87df3428e3b23507377c71eae92dc1dd9f5d5374aa0b03906fb81507fc6ce6","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"e7b9a20e070cc401f75dfe07aceb8f2950a4d99ed8a7d4413ef9f0813f5a8ca1","src/lib.rs":"57d2562e33b04113cc6c2ca3bc9a215ec779a291be82b680ff037fac7d7a8a15","src/lock/mod.rs":"8d3ae3f8d004d7f7d8a3aefe9f30b35669cb8e2409f5fba27b1fcb116b2429c4","src/lock/observing.rs":"5bf62cef9f3ae67e99af640442fadd4e1f762480d990ee69ed9924c9e94a8dce","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"a95d6bf7f2ef510047a4c33687076beccf38a0148aac3261bd29fa7555e3f488","src/lock/vanilla.rs":"ca8156d4c981473d437db1056487a44c714760d685819eaff8cf82fb0098a608","src/pipeline.rs":"d84fbf90eda12f4acbb0ff8f8166a6b498ce89da52beacf5b81a6b06afa907c9","src/pipeline_cache.rs":"f6a82de6cf362be50335d26e8eed983b53812a8444dff9c8c988a075f3325f8f","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"edd9ce3be749a380c99be8e517963844ac04e3320085e7367a5e3a11e28efad9","src/ray_tracing.rs":"ae43907290f003f6247bb599927401bd768865f7773a41c327dc73fade014ede","src/registry.rs":"2a76c6397998d263b6f6347299f04a8d27ea4df7dda200e98f205cfa3850dadb","src/resource.rs":"59a2b8093790d85724960ceec5a421905e20b665c9e9b1b231b079cccbc51291","src/scratch.rs":"ea5c40e4d18a12f09cc1038f2dcdddb69b13e99275ac987d826658229a39b326","src/snatch.rs":"bf422810afd952894e365cd397763d42d6365ce3c5a5b4c1170566432f462939","src/storage.rs":"1a5bbf125a1cf65a36d8580e426ef1847c1638003fea0c6f76e309f5923b7692","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"89444ad79900c12c2dc44780f1525cd0554d6ed1d9038938dd0075e8173ae59d","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"7f2393d16d0e8f624327c7a3a1de7176f945f3d33bfd3e12640faddc5c2c9f83","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"c28de55e31cdde3feb067945a04446dc5343a39418c4b9c2c76148172e7ba855","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"34e72a20364d3ce642c21b29a089811503aa2fb4e7dab1a1e20d8ddd598742d7","src/validation.rs":"1c2e91bcf5863b1ec00b85dd10588a8772b620d44e36b762f069d35b59a84ae4","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/wgpu-core/src/binding_model.rs b/third_party/rust/wgpu-core/src/binding_model.rs @@ -1165,6 +1165,14 @@ pub(crate) fn buffer_binding_type_bounds_check_alignment( } #[derive(Debug)] +pub(crate) struct BindGroupLateBufferBindingInfo { + /// The normal binding index in the bind group. + pub binding_index: u32, + /// The size that exists at bind time. + pub size: wgt::BufferSize, +} + +#[derive(Debug)] pub struct BindGroup { pub(crate) raw: Snatchable<Box<dyn hal::DynBindGroup>>, pub(crate) device: Arc<Device>, @@ -1178,7 +1186,7 @@ pub struct BindGroup { pub(crate) dynamic_binding_info: Vec<BindGroupDynamicBindingData>, /// Actual binding sizes for buffers that don't have `min_binding_size` /// specified in BGL. Listed in the order of iteration of `BGL.entries`. - pub(crate) late_buffer_binding_sizes: Vec<wgt::BufferSize>, + pub(crate) late_buffer_binding_infos: Vec<BindGroupLateBufferBindingInfo>, } impl Drop for BindGroup { @@ -1289,10 +1297,13 @@ impl WebGpuError for GetBindGroupLayoutError { } #[derive(Clone, Debug, Error, Eq, PartialEq)] -#[error("Buffer is bound with size {bound_size} where the shader expects {shader_size} in group[{group_index}] compact index {compact_index}")] +#[error( + "In bind group index {group_index}, the buffer bound at binding index {binding_index} \ + is bound with size {bound_size} where the shader expects {shader_size}." +)] pub struct LateMinBufferBindingSizeMismatch { pub group_index: u32, - pub compact_index: usize, + pub binding_index: u32, pub shader_size: wgt::BufferAddress, pub bound_size: wgt::BufferAddress, } diff --git a/third_party/rust/wgpu-core/src/command/bind.rs b/third_party/rust/wgpu-core/src/command/bind.rs @@ -291,6 +291,7 @@ pub enum BinderError { #[derive(Debug)] struct LateBufferBinding { + binding_index: u32, shader_expect_size: wgt::BufferAddress, bound_size: wgt::BufferAddress, } @@ -347,8 +348,11 @@ impl Binder { self.manager.update_expectations(&new.bind_group_layouts); // Update the buffer binding sizes that are required by shaders. + for (payload, late_group) in self.payloads.iter_mut().zip(late_sized_buffer_groups) { payload.late_bindings_effective_count = late_group.shader_sizes.len(); + // Update entries that already exist as the bind group was bound before the pipeline + // was bound. for (late_binding, &shader_expect_size) in payload .late_buffer_bindings .iter_mut() @@ -356,11 +360,13 @@ impl Binder { { late_binding.shader_expect_size = shader_expect_size; } + // Add new entries for the bindings that were not known when the bind group was bound. if late_group.shader_sizes.len() > payload.late_buffer_bindings.len() { for &shader_expect_size in late_group.shader_sizes[payload.late_buffer_bindings.len()..].iter() { payload.late_buffer_bindings.push(LateBufferBinding { + binding_index: 0, shader_expect_size, bound_size: 0, }); @@ -389,20 +395,27 @@ impl Binder { // Fill out the actual binding sizes for buffers, // whose layout doesn't specify `min_binding_size`. - for (late_binding, late_size) in payload + + // Update entries that already exist as the pipeline was bound before the group + // was bound. + for (late_binding, late_info) in payload .late_buffer_bindings .iter_mut() - .zip(bind_group.late_buffer_binding_sizes.iter()) + .zip(bind_group.late_buffer_binding_infos.iter()) { - late_binding.bound_size = late_size.get(); + late_binding.binding_index = late_info.binding_index; + late_binding.bound_size = late_info.size.get(); } - if bind_group.late_buffer_binding_sizes.len() > payload.late_buffer_bindings.len() { - for late_size in - bind_group.late_buffer_binding_sizes[payload.late_buffer_bindings.len()..].iter() + + // Add new entries for the bindings that were not known when the pipeline was bound. + if bind_group.late_buffer_binding_infos.len() > payload.late_buffer_bindings.len() { + for late_info in + bind_group.late_buffer_binding_infos[payload.late_buffer_bindings.len()..].iter() { payload.late_buffer_bindings.push(LateBufferBinding { + binding_index: late_info.binding_index, shader_expect_size: 0, - bound_size: late_size.get(), + bound_size: late_info.size.get(), }); } } @@ -469,15 +482,13 @@ impl Binder { ) -> Result<(), LateMinBufferBindingSizeMismatch> { for group_index in self.manager.list_active() { let payload = &self.payloads[group_index]; - for (compact_index, late_binding) in payload.late_buffer_bindings - [..payload.late_bindings_effective_count] - .iter() - .enumerate() + for late_binding in + &payload.late_buffer_bindings[..payload.late_bindings_effective_count] { if late_binding.bound_size < late_binding.shader_expect_size { return Err(LateMinBufferBindingSizeMismatch { group_index: group_index as u32, - compact_index, + binding_index: late_binding.binding_index, shader_size: late_binding.shader_expect_size, bound_size: late_binding.bound_size, }); diff --git a/third_party/rust/wgpu-core/src/command/transfer.rs b/third_party/rust/wgpu-core/src/command/transfer.rs @@ -170,6 +170,8 @@ pub enum TransferError { }, #[error("Requested mip level {requested} does not exist (count: {count})")] InvalidMipLevel { requested: u32, count: u32 }, + #[error("Buffer is expected to be unmapped, but was not")] + BufferNotAvailable, } impl WebGpuError for TransferError { @@ -211,7 +213,8 @@ impl WebGpuError for TransferError { | Self::InvalidSampleCount { .. } | Self::SampleCountNotEqual { .. } | Self::InvalidMipLevel { .. } - | Self::SameSourceDestinationBuffer => return ErrorType::Validation, + | Self::SameSourceDestinationBuffer + | Self::BufferNotAvailable => return ErrorType::Validation, }; e.webgpu_error_type() } diff --git a/third_party/rust/wgpu-core/src/device/mod.rs b/third_party/rust/wgpu-core/src/device/mod.rs @@ -514,6 +514,14 @@ pub fn create_validator( Caps::SHADER_BARYCENTRICS, features.intersects(wgt::Features::SHADER_BARYCENTRICS), ); + caps.set( + Caps::MESH_SHADER, + features.intersects(wgt::Features::EXPERIMENTAL_MESH_SHADER), + ); + caps.set( + Caps::MESH_SHADER_POINT_TOPOLOGY, + features.intersects(wgt::Features::EXPERIMENTAL_MESH_SHADER_POINTS), + ); naga::valid::Validator::new(flags, caps) } diff --git a/third_party/rust/wgpu-core/src/device/queue.rs b/third_party/rust/wgpu-core/src/device/queue.rs @@ -648,6 +648,9 @@ impl Queue { buffer_offset: u64, buffer_size: wgt::BufferSize, ) -> Result<(), TransferError> { + if !matches!(&*buffer.map_state.lock(), BufferMapState::Idle) { + return Err(TransferError::BufferNotAvailable); + } buffer.check_usage(wgt::BufferUsages::COPY_DST)?; if buffer_size.get() % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(TransferError::UnalignedCopySize(buffer_size.get())); diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs @@ -25,7 +25,9 @@ use wgt::{ use crate::device::trace; use crate::{ api_log, - binding_model::{self, BindGroup, BindGroupLayout, BindGroupLayoutEntryError}, + binding_model::{ + self, BindGroup, BindGroupLateBufferBindingInfo, BindGroupLayout, BindGroupLayoutEntryError, + }, command, conv, device::{ bgl, create_validator, life::WaitIdleError, map_buffer, AttachmentData, @@ -3279,10 +3281,16 @@ impl Device { .map_err(|e| self.handle_hal_error(e))?; // collect in the order of BGL iteration - let late_buffer_binding_sizes = layout + let late_buffer_binding_infos = layout .entries .indices() - .flat_map(|binding| late_buffer_binding_sizes.get(&binding).cloned()) + .flat_map(|binding| { + let size = late_buffer_binding_sizes.get(&binding).cloned()?; + Some(BindGroupLateBufferBindingInfo { + binding_index: binding, + size, + }) + }) .collect(); let bind_group = BindGroup { @@ -3295,7 +3303,7 @@ impl Device { used_buffer_ranges, used_texture_ranges, dynamic_binding_info, - late_buffer_binding_sizes, + late_buffer_binding_infos, }; let bind_group = Arc::new(bind_group); diff --git a/third_party/rust/wgpu-hal/.cargo-checksum.json b/third_party/rust/wgpu-hal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"4848d8ea1e40adb0bb6378bd2bf7fe0726dcf7f39b966003b4bef5a428a152a6","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"642f00cedd20c87d357e48fbc194af41731e75c12f626d3ecf9fdb5e3ae5ee0c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"a8fa13b191e1596f6895fa44fb7503638d818b8c373e4383247e82c23e5974da","examples/ray-traced-triangle/main.rs":"8cbfdf3e4cd29d23e2c9fd543a36976d849a7161670e094baeda390db9306b57","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"3ca856c93916c0be714924ff077aa1f366be5557cc164210154d252e7e49fb77","src/auxil/dxgi/exception.rs":"7138831914a59dc7cbb71512068e9134144b9bc8f43312682edccb0b3ee24a48","src/auxil/dxgi/factory.rs":"81e479e550a09127384d8080e43d5f5bae8e8dda6082fe41a87bea8f872eb0f1","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"e7a9dfb48d8ef8cbe58b28b1ace5caf7818ee50505ba3220bb0509e66ae469b7","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"94898f747476e269b2910d42e769f2bbb6be0cb466ad92f9d381f55799d2756e","src/dx12/adapter.rs":"1db86dceaedb7abf3259e63a6e6f56bd9a985a7dc68c0404177c1f3394cb0648","src/dx12/command.rs":"d0fa8baa2954f26521643caaee6e93801b58da7000b2527348361b6f25ec137a","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"053068fbd393a4b8610c7070a72e5887f0fe09b61d35d2be806083d800b48b08","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"8218a384d5cf904ddada7d99e8285e06e1604406af4ed6c11a3369ee054e3338","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"a8059953a6f371ac3caf11c712427204eaf458fd613b567f1a3b4fd241720000","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"6e0323277749a8bd9fb8a3cb458366d79a4c2f27f8210067026048eb65c4247e","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"f1615cc3cae357e0608adfd97106240fc7c77195e97d8dba44c71adfabf6229b","src/dynamic/device.rs":"d5f3c1374c7eb8c8c3737de2b22691c08385cb768d4aac34182feb4d314d7ec9","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"2577d3aef6441f5b42b427d80ba3cf7fee2a97b2fc12335a1fba383e8a79a9b2","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"335dc7fbfeb781cd61148b5f8dd653b1d0b0ba79ef552beddcaf772d28b14dda","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"6ffb8688de38c2fdd956571dd549535259e2811225adc1df02509e8e642ee775","src/gles/device.rs":"ebe95bea12b3e04792611d66deaa6b5e52ac73e39489a247f88a58fbcb30e0b5","src/gles/egl.rs":"2509e5a5c422e213a3050d852d70a13dfc06737c829a8fc169f45791d8e27fed","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"a2e7b6abd2fd4a438de90b9f58452c64cd8bba83999c90fd6390e3db128b9c6c","src/gles/mod.rs":"b6d80623eaf58719bafac26875fd0f75f8546b02c58b96a75d703e3a350e31df","src/gles/queue.rs":"5152f5698a2998a55125d13f04788b960726fd4b49ae4d2ec8f9642c8825c7fd","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"81b2a961fb92e22613224539f85fe982599bfdb6364457578c6b0d9778295d89","src/lib.rs":"acd981799345a8332dda471d5d17367c9d595dfb71946666c59ae5f141347061","src/metal/adapter.rs":"22be51defa39453de32ae4684450b551d64d154ea5cdd991fa0e2edc7d44efde","src/metal/command.rs":"60f5ed647a2b74303f031ce5f0854ecfdc0aaba6e8054d3028a24fbd8b721d16","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"332a1164ebdb5e701b07c0cd4efc54f261306d8d96e4b7787a2eebbc67b2f338","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"36fc4b1a1427d54024128832cbbcfd9d0ca1eaaf0437d24a02eb1116a0f0f37a","src/metal/surface.rs":"22dc6da86ac74b044b6498764920f0467bb5060f4dffb156b6c1e260db0c48b7","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"6e1d15602da06f63b790b938dff2c32cefa2a314e56ab116c9e80d54f8de753f","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"c5d3c0bd74d7790dab73d4a6c45777ff52f3f912d0371a2db031d9c4fa8ea876","src/vulkan/command.rs":"42a4d8e463d9a74f8000e691d36361f5c9adb792d18019deebefcd57ee9488ed","src/vulkan/conv.rs":"03eb28b81d3e41ccfcb2b3f7f029cd671ccdf9556594c6d8b6cc2b22144ec4f2","src/vulkan/device.rs":"5e13d496225f70311704439d0aa256b8feed7a6ab38e8b467f469acb26eacf7c","src/vulkan/drm.rs":"45f7bf1dd854688a65261e4674d80f90c997b193a162fd2ae658acf4e2003552","src/vulkan/instance.rs":"435fb4f22c3c39463f1a33f1a946180656cc7177eeb97035c0458f5d97a1591f","src/vulkan/mod.rs":"15771b5d598a2c675e9140c199bfcf3eacf2077918e6cee3d3db51805fb1df95","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"6e548d810d75daf5ed31b6e520ece32c8ef97e4b66926c17f0d4317f355802e5","src/vulkan/swapchain/mod.rs":"1baef6ef36d005fe03b27ea15a91d1c5c7114eb7f777a50e67ca5f448a53291b","src/vulkan/swapchain/native.rs":"6d9aadeeb1d6774afe070e0f5d995576c1d5c1097dfc471d914b2e16782a4d69"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"4848d8ea1e40adb0bb6378bd2bf7fe0726dcf7f39b966003b4bef5a428a152a6","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"642f00cedd20c87d357e48fbc194af41731e75c12f626d3ecf9fdb5e3ae5ee0c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"a8fa13b191e1596f6895fa44fb7503638d818b8c373e4383247e82c23e5974da","examples/ray-traced-triangle/main.rs":"8cbfdf3e4cd29d23e2c9fd543a36976d849a7161670e094baeda390db9306b57","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"3ca856c93916c0be714924ff077aa1f366be5557cc164210154d252e7e49fb77","src/auxil/dxgi/exception.rs":"7138831914a59dc7cbb71512068e9134144b9bc8f43312682edccb0b3ee24a48","src/auxil/dxgi/factory.rs":"81e479e550a09127384d8080e43d5f5bae8e8dda6082fe41a87bea8f872eb0f1","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"e7a9dfb48d8ef8cbe58b28b1ace5caf7818ee50505ba3220bb0509e66ae469b7","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"94898f747476e269b2910d42e769f2bbb6be0cb466ad92f9d381f55799d2756e","src/dx12/adapter.rs":"0473f3a57c534fec80e7788ac95b457f038ff47df2eada910c7fb09e52ff8c59","src/dx12/command.rs":"d0fa8baa2954f26521643caaee6e93801b58da7000b2527348361b6f25ec137a","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"053068fbd393a4b8610c7070a72e5887f0fe09b61d35d2be806083d800b48b08","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"f6c1c0d65bfb5f7b81ef9ab23fd936a4124fc2a1b43c1d5212a701cfa115409a","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"3bb54a4f423e49ec3df926c891340e439b27c28efe87ace0a4ece6c81745a591","src/dx12/pipeline_desc.rs":"631c72108f6735debe9f7059e22574ad50b11aca4dc0ca804e6d89b1373d19ff","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"a0ce9ca4b9143715ffc4b45a56a18182d54b118161553173c1a546cc6041560c","src/dx12/suballocation.rs":"6e0323277749a8bd9fb8a3cb458366d79a4c2f27f8210067026048eb65c4247e","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"f1615cc3cae357e0608adfd97106240fc7c77195e97d8dba44c71adfabf6229b","src/dynamic/device.rs":"d5f3c1374c7eb8c8c3737de2b22691c08385cb768d4aac34182feb4d314d7ec9","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"2577d3aef6441f5b42b427d80ba3cf7fee2a97b2fc12335a1fba383e8a79a9b2","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"335dc7fbfeb781cd61148b5f8dd653b1d0b0ba79ef552beddcaf772d28b14dda","src/gles/command.rs":"e8bcf8ffb42697abf1d64447b2c92075814e0a4956af41df5fa6ce5f093af155","src/gles/conv.rs":"6ffb8688de38c2fdd956571dd549535259e2811225adc1df02509e8e642ee775","src/gles/device.rs":"ebe95bea12b3e04792611d66deaa6b5e52ac73e39489a247f88a58fbcb30e0b5","src/gles/egl.rs":"2509e5a5c422e213a3050d852d70a13dfc06737c829a8fc169f45791d8e27fed","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"a2e7b6abd2fd4a438de90b9f58452c64cd8bba83999c90fd6390e3db128b9c6c","src/gles/mod.rs":"aad205606b61660a19e6de5c3a6b92b47000f36ad8bb07256056a059896951a8","src/gles/queue.rs":"17dfbc36cdd19958d842823109a398d35e771cb57e00a7cbbdafc488301fc0e4","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"81b2a961fb92e22613224539f85fe982599bfdb6364457578c6b0d9778295d89","src/lib.rs":"acd981799345a8332dda471d5d17367c9d595dfb71946666c59ae5f141347061","src/metal/adapter.rs":"1bdf6199693a960139a0c66b366efe5453525d7fab6dc8358009e6ea0159d46c","src/metal/command.rs":"6e2b5750192733d0f9b2b3188ea950f4db5a828e8ce1d23cc2336fb9cde8a131","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"7dac4f59a12c0695735ef4b0e9fd3fa1c257ccd32966399f1d12b14d425b34b4","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"3c39b76818584f734849538ccc8cb4dfde124d0d7d4de2759dcb583d501f089e","src/metal/surface.rs":"22dc6da86ac74b044b6498764920f0467bb5060f4dffb156b6c1e260db0c48b7","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"6e1d15602da06f63b790b938dff2c32cefa2a314e56ab116c9e80d54f8de753f","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"95693944091b494b1bfe26ca472b9dedc59782bec93ac561124c7d58b9e06087","src/vulkan/command.rs":"42a4d8e463d9a74f8000e691d36361f5c9adb792d18019deebefcd57ee9488ed","src/vulkan/conv.rs":"03eb28b81d3e41ccfcb2b3f7f029cd671ccdf9556594c6d8b6cc2b22144ec4f2","src/vulkan/device.rs":"fcaeb8b3d4ef914305519a4f10e16b2d4c2f6167eccd452c1298b7202cc02160","src/vulkan/drm.rs":"45f7bf1dd854688a65261e4674d80f90c997b193a162fd2ae658acf4e2003552","src/vulkan/instance.rs":"435fb4f22c3c39463f1a33f1a946180656cc7177eeb97035c0458f5d97a1591f","src/vulkan/mod.rs":"15771b5d598a2c675e9140c199bfcf3eacf2077918e6cee3d3db51805fb1df95","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"6e548d810d75daf5ed31b6e520ece32c8ef97e4b66926c17f0d4317f355802e5","src/vulkan/swapchain/mod.rs":"1baef6ef36d005fe03b27ea15a91d1c5c7114eb7f777a50e67ca5f448a53291b","src/vulkan/swapchain/native.rs":"6d9aadeeb1d6774afe070e0f5d995576c1d5c1097dfc471d914b2e16782a4d69"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/wgpu-hal/src/dx12/adapter.rs b/third_party/rust/wgpu-hal/src/dx12/adapter.rs @@ -116,8 +116,26 @@ impl super::Adapter { } .unwrap(); + let driver_version = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } + .ok() + .map(|i| { + const MASK: i64 = 0xFFFF; + (i >> 48, (i >> 32) & MASK, (i >> 16) & MASK, i & MASK) + }) + .unwrap_or((0, 0, 0, 0)); + let mut workarounds = super::Workarounds::default(); + let is_warp = device_name.contains("Microsoft Basic Render Driver"); + + // WARP uses two different versioning schemes. Versions that ship with windows + // use a version that starts with 10.x.x.x. Versions that ship from Nuget use 1.0.x.x. + // + // As far as we know, this is only an issue on the Nuget versions. + if is_warp && driver_version >= (1, 0, 13, 0) && driver_version.0 < 10 { + workarounds.avoid_shader_debug_info = true; + } + let info = wgt::AdapterInfo { backend: wgt::Backend::Dx12, name: device_name, @@ -126,7 +144,6 @@ impl super::Adapter { device_type: if Dxgi::DXGI_ADAPTER_FLAG(desc.Flags as i32) .contains(Dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) { - workarounds.avoid_cpu_descriptor_overwrites = true; wgt::DeviceType::Cpu } else if features_architecture.UMA.as_bool() { wgt::DeviceType::IntegratedGpu @@ -134,20 +151,10 @@ impl super::Adapter { wgt::DeviceType::DiscreteGpu }, device_pci_bus_id: get_adapter_pci_info(desc.VendorId, desc.DeviceId), - driver: { - if let Ok(i) = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } { - const MASK: i64 = 0xFFFF; - format!( - "{}.{}.{}.{}", - i >> 48, - (i >> 32) & MASK, - (i >> 16) & MASK, - i & MASK - ) - } else { - String::new() - } - }, + driver: format!( + "{}.{}.{}.{}", + driver_version.0, driver_version.1, driver_version.2, driver_version.3 + ), driver_info: String::new(), transient_saves_memory: false, }; @@ -319,6 +326,7 @@ impl super::Adapter { }; let private_caps = super::PrivateCapabilities { instance_flags, + workarounds, heterogeneous_resource_heaps: options.ResourceHeapTier != Direct3D12::D3D12_RESOURCE_HEAP_TIER_1, memory_architecture: if features_architecture.UMA.as_bool() { @@ -532,8 +540,8 @@ impl super::Adapter { .is_ok(); // Once ray tracing pipelines are supported they also will go here - let supports_ray_tracing = features5.RaytracingTier - == Direct3D12::D3D12_RAYTRACING_TIER_1_1 + let supports_ray_tracing = features5.RaytracingTier.0 + >= Direct3D12::D3D12_RAYTRACING_TIER_1_1.0 && shader_model >= naga::back::hlsl::ShaderModel::V6_5 && has_features5; features.set( @@ -593,13 +601,20 @@ impl super::Adapter { shader_barycentrics_supported, ); - // Re-enable this when multiview is supported on DX12 - // features.set(wgt::Features::MULTIVIEW, view_instancing); - // features.set(wgt::Features::SELECTIVE_MULTIVIEW, view_instancing); + features.set( + wgt::Features::MULTIVIEW, + view_instancing && shader_model >= naga::back::hlsl::ShaderModel::V6_1, + ); + features.set( + wgt::Features::SELECTIVE_MULTIVIEW, + view_instancing && shader_model >= naga::back::hlsl::ShaderModel::V6_1, + ); features.set( wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW, - mesh_shader_supported && view_instancing, + mesh_shader_supported + && view_instancing + && shader_model >= naga::back::hlsl::ShaderModel::V6_1, ); // TODO: Determine if IPresentationManager is supported @@ -639,7 +654,6 @@ impl super::Adapter { dcomp_lib: Arc::clone(dcomp_lib), private_caps, presentation_timer, - workarounds, memory_budget_thresholds, compiler_container, options: backend_options, diff --git a/third_party/rust/wgpu-hal/src/dx12/device.rs b/third_party/rust/wgpu-hal/src/dx12/device.rs @@ -5,6 +5,7 @@ use alloc::{ sync::Arc, vec::Vec, }; +use arrayvec::ArrayVec; use core::{ffi, num::NonZeroU32, ptr, time::Duration}; use std::time::Instant; @@ -26,8 +27,9 @@ use crate::{ dxgi::{name::ObjectExt as _, result::HResult as _}, }, dx12::{ - borrow_optional_interface_temporarily, shader_compilation, suballocation, DCompLib, - DynamicStorageBufferOffsets, Event, ShaderCacheKey, ShaderCacheValue, + borrow_optional_interface_temporarily, pipeline_desc::RenderPipelineStateStreamDesc, + shader_compilation, suballocation, DCompLib, DynamicStorageBufferOffsets, Event, + ShaderCacheKey, ShaderCacheValue, }, AccelerationStructureEntries, TlasInstance, }; @@ -290,6 +292,7 @@ impl super::Device { || stage.module.runtime_checks.bounds_checks != layout.naga_options.restrict_indexing || stage.module.runtime_checks.force_loop_bounding != layout.naga_options.force_loop_bounding; + // Note: ray query initialization tracking not yet implemented let mut temp_options; let naga_options = if needs_temp_options { temp_options = layout.naga_options.clone(); @@ -981,7 +984,7 @@ impl crate::Device for super::Device { let mut ranges = Vec::with_capacity(total_non_dynamic_entries); let mut bind_group_infos = - arrayvec::ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default(); + ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default(); for (index, bgl) in desc.bind_group_layouts.iter().enumerate() { let mut info = super::BindGroupInfo { tables: super::TableTypes::empty(), @@ -1865,8 +1868,6 @@ impl crate::Device for super::Device { >, ) -> Result<super::RenderPipeline, crate::PipelineError> { let mut shader_stages = wgt::ShaderStages::empty(); - let root_signature = - unsafe { borrow_optional_interface_temporarily(&desc.layout.shared.signature) }; let (topology_class, topology) = conv::map_topology(desc.primitive.topology); let mut rtv_formats = [Dxgi::Common::DXGI_FORMAT_UNKNOWN; Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; @@ -1906,6 +1907,7 @@ impl crate::Device for super::Device { Direct3D12::D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF }, }; + let blob_fs = match desc.fragment_stage { Some(ref stage) => { shader_stages |= wgt::ShaderStages::FRAGMENT; @@ -1917,7 +1919,6 @@ impl crate::Device for super::Device { Some(shader) => shader.create_native_shader(), None => Direct3D12::D3D12_SHADER_BYTECODE::default(), }; - let mut vertex_strides = [None; crate::MAX_VERTEX_BUFFERS]; let stream_output = Direct3D12::D3D12_STREAM_OUTPUT_DESC { pSODeclaration: ptr::null(), NumEntries: 0, @@ -1952,20 +1953,77 @@ impl crate::Device for super::Device { }; let flags = Direct3D12::D3D12_PIPELINE_STATE_FLAG_NONE; - let raw: Direct3D12::ID3D12PipelineState = match &desc.vertex_processor { + let mut view_instancing = + core::pin::pin!(ArrayVec::<Direct3D12::D3D12_VIEW_INSTANCE_LOCATION, 32>::new()); + if let Some(mask) = desc.multiview_mask { + let mask = mask.get(); + // This array is just what _could_ be rendered to. We actually apply the mask at + // renderpass creation time. The `view_index` passed to the shader depends on the + // view's index in this array, so if we include every view in this array, `view_index` + // actually the texture array layer, like in vulkan. + for i in 0..32 - mask.leading_zeros() { + view_instancing.push(Direct3D12::D3D12_VIEW_INSTANCE_LOCATION { + ViewportArrayIndex: 0, + RenderTargetArrayIndex: i, + }); + } + } + + let mut stream_desc = RenderPipelineStateStreamDesc { + // Shared by vertex and mesh pipelines + root_signature: desc.layout.shared.signature.as_ref(), + pixel_shader, + blend_state, + sample_mask: desc.multisample.mask as u32, + rasterizer_state, + depth_stencil_state, + primitive_topology_type: topology_class, + rtv_formats: Direct3D12::D3D12_RT_FORMAT_ARRAY { + RTFormats: rtv_formats, + NumRenderTargets: desc.color_targets.len() as u32, + }, + dsv_format, + sample_desc, + node_mask: 0, + cached_pso, + flags, + view_instancing: if !view_instancing.is_empty() { + Some(Direct3D12::D3D12_VIEW_INSTANCING_DESC { + ViewInstanceCount: view_instancing.len() as u32, + pViewInstanceLocations: view_instancing.as_ptr(), + // This lets us hide/mask certain values later, at renderpass creation time. + Flags: Direct3D12::D3D12_VIEW_INSTANCING_FLAG_ENABLE_VIEW_INSTANCE_MASKING, + }) + } else { + None + }, + + // Optional data that depends on the pipeline type (vertex vs mesh). + vertex_shader: Default::default(), + input_layout: Default::default(), + index_buffer_strip_cut_value: Default::default(), + stream_output, + task_shader: Default::default(), + mesh_shader: Default::default(), + }; + let mut input_element_descs = Vec::new(); + let blob_vs; + let blob_ts; + let blob_ms; + let mut vertex_strides = [None; crate::MAX_VERTEX_BUFFERS]; + match &desc.vertex_processor { &crate::VertexProcessor::Standard { vertex_buffers, ref vertex_stage, } => { shader_stages |= wgt::ShaderStages::VERTEX; - let blob_vs = self.load_shader( + blob_vs = Some(self.load_shader( vertex_stage, desc.layout, naga::ShaderStage::Vertex, desc.fragment_stage.as_ref(), - )?; + )?); - let mut input_element_descs = Vec::new(); for (i, (stride, vbuf)) in vertex_strides.iter_mut().zip(vertex_buffers).enumerate() { *stride = Some(vbuf.array_stride as u32); @@ -1989,54 +2047,37 @@ impl crate::Device for super::Device { }); } } - let raw_desc = Direct3D12::D3D12_GRAPHICS_PIPELINE_STATE_DESC { - pRootSignature: root_signature, - VS: blob_vs.create_native_shader(), - PS: pixel_shader, - GS: Direct3D12::D3D12_SHADER_BYTECODE::default(), - DS: Direct3D12::D3D12_SHADER_BYTECODE::default(), - HS: Direct3D12::D3D12_SHADER_BYTECODE::default(), - StreamOutput: stream_output, - BlendState: blend_state, - SampleMask: desc.multisample.mask as u32, - RasterizerState: rasterizer_state, - DepthStencilState: depth_stencil_state, - InputLayout: Direct3D12::D3D12_INPUT_LAYOUT_DESC { - pInputElementDescs: if input_element_descs.is_empty() { - ptr::null() - } else { - input_element_descs.as_ptr() - }, - NumElements: input_element_descs.len() as u32, - }, - IBStripCutValue: match desc.primitive.strip_index_format { - Some(wgt::IndexFormat::Uint16) => { - Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF - } - Some(wgt::IndexFormat::Uint32) => { - Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF - } - None => Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED, + stream_desc.vertex_shader = blob_vs.as_ref().unwrap().create_native_shader(); + stream_desc.input_layout = Direct3D12::D3D12_INPUT_LAYOUT_DESC { + pInputElementDescs: if input_element_descs.is_empty() { + ptr::null() + } else { + input_element_descs.as_ptr() }, - PrimitiveTopologyType: topology_class, - NumRenderTargets: desc.color_targets.len() as u32, - RTVFormats: rtv_formats, - DSVFormat: dsv_format, - SampleDesc: sample_desc, - NodeMask: 0, - CachedPSO: cached_pso, - Flags: flags, + NumElements: input_element_descs.len() as u32, + }; + stream_desc.index_buffer_strip_cut_value = match desc.primitive.strip_index_format { + Some(wgt::IndexFormat::Uint16) => { + Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF + } + Some(wgt::IndexFormat::Uint32) => { + Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF + } + None => Direct3D12::D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED, + }; + stream_desc.stream_output = Direct3D12::D3D12_STREAM_OUTPUT_DESC { + pSODeclaration: ptr::null(), + NumEntries: 0, + pBufferStrides: ptr::null(), + NumStrides: 0, + RasterizedStream: 0, }; - unsafe { - profiling::scope!("ID3D12Device::CreateGraphicsPipelineState"); - self.raw.CreateGraphicsPipelineState(&raw_desc) - } } crate::VertexProcessor::Mesh { task_stage, mesh_stage, } => { - let blob_ts = if let Some(ts) = task_stage { + blob_ts = if let Some(ts) = task_stage { shader_stages |= wgt::ShaderStages::TASK; Some(self.load_shader( ts, @@ -2053,48 +2094,36 @@ impl crate::Device for super::Device { Default::default() }; shader_stages |= wgt::ShaderStages::MESH; - let blob_ms = self.load_shader( + blob_ms = Some(self.load_shader( mesh_stage, desc.layout, naga::ShaderStage::Mesh, desc.fragment_stage.as_ref(), - )?; - let desc = super::MeshShaderPipelineStateStream { - root_signature: root_signature - .as_ref() - .map(|a| a.as_raw().cast()) - .unwrap_or(ptr::null_mut()), - task_shader, - pixel_shader, - mesh_shader: blob_ms.create_native_shader(), - blend_state, - sample_mask: desc.multisample.mask as u32, - rasterizer_state, - depth_stencil_state, - primitive_topology_type: topology_class, - rtv_formats: Direct3D12::D3D12_RT_FORMAT_ARRAY { - RTFormats: rtv_formats, - NumRenderTargets: desc.color_targets.len() as u32, - }, - dsv_format, - sample_desc, - node_mask: 0, - cached_pso, - flags, - }; - let mut raw_desc = unsafe { desc.to_bytes() }; - let stream_desc = Direct3D12::D3D12_PIPELINE_STATE_STREAM_DESC { - SizeInBytes: raw_desc.len(), - pPipelineStateSubobjectStream: raw_desc.as_mut_ptr().cast(), - }; - let device: Direct3D12::ID3D12Device2 = self.raw.cast().unwrap(); + )?); + stream_desc.task_shader = task_shader; + stream_desc.mesh_shader = blob_ms.as_ref().unwrap().create_native_shader(); + } + }; + let raw: Direct3D12::ID3D12PipelineState = + // If stream descriptors are available, use them as they are more flexible. + if let Ok(device) = self.raw.cast::<Direct3D12::ID3D12Device2>() { + // Prefer stream descs where possible + let mut stream = stream_desc.to_stream(); unsafe { profiling::scope!("ID3D12Device2::CreatePipelineState"); - device.CreatePipelineState(&stream_desc) + stream.create_pipeline_state(&device).map_err(|err| { + crate::PipelineError::Linkage(shader_stages, err.to_string()) + })? } - } - } - .map_err(|err| crate::PipelineError::Linkage(shader_stages, err.to_string()))?; + } else { + unsafe { + // Safety: `stream_desc` entirely outlives the `desc`. + let desc = stream_desc.to_graphics_pipeline_descriptor(); + self.raw.CreateGraphicsPipelineState(&desc).map_err(|err| { + crate::PipelineError::Linkage(shader_stages, err.to_string()) + })? + } + }; if let Some(label) = desc.label { raw.set_name(label)?; diff --git a/third_party/rust/wgpu-hal/src/dx12/mod.rs b/third_party/rust/wgpu-hal/src/dx12/mod.rs @@ -79,6 +79,7 @@ mod dcomp; mod descriptor; mod device; mod instance; +mod pipeline_desc; mod sampler; mod shader_compilation; mod suballocation; @@ -597,6 +598,7 @@ enum MemoryArchitecture { #[derive(Debug, Clone, Copy)] struct PrivateCapabilities { instance_flags: wgt::InstanceFlags, + workarounds: Workarounds, #[allow(unused)] heterogeneous_resource_heaps: bool, memory_architecture: MemoryArchitecture, @@ -618,11 +620,11 @@ impl PrivateCapabilities { } } -#[derive(Default)] +#[derive(Default, Debug, Copy, Clone)] struct Workarounds { - // On WARP, temporary CPU descriptors are still used by the runtime - // after we call `CopyDescriptors`. - avoid_cpu_descriptor_overwrites: bool, + // On WARP 1.0.13+, debug information in shaders in certain situations causes the device + // to hang. https://github.com/gfx-rs/wgpu/issues/8368 + avoid_shader_debug_info: bool, } pub struct Adapter { @@ -632,9 +634,6 @@ pub struct Adapter { dcomp_lib: Arc<DCompLib>, private_caps: PrivateCapabilities, presentation_timer: auxil::dxgi::time::PresentationTimer, - // Note: this isn't used right now, but we'll need it later. - #[allow(unused)] - workarounds: Workarounds, memory_budget_thresholds: wgt::MemoryBudgetThresholds, compiler_container: Arc<shader_compilation::CompilerContainer>, options: wgt::Dx12BackendOptions, @@ -1617,116 +1616,3 @@ pub enum ShaderModuleSource { DxilPassthrough(DxilPassthroughShader), HlslPassthrough(HlslPassthroughShader), } - -#[repr(C)] -#[derive(Debug)] -struct MeshShaderPipelineStateStream { - root_signature: *mut Direct3D12::ID3D12RootSignature, - task_shader: Direct3D12::D3D12_SHADER_BYTECODE, - mesh_shader: Direct3D12::D3D12_SHADER_BYTECODE, - pixel_shader: Direct3D12::D3D12_SHADER_BYTECODE, - blend_state: Direct3D12::D3D12_BLEND_DESC, - sample_mask: u32, - rasterizer_state: Direct3D12::D3D12_RASTERIZER_DESC, - depth_stencil_state: Direct3D12::D3D12_DEPTH_STENCIL_DESC, - primitive_topology_type: Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE, - rtv_formats: Direct3D12::D3D12_RT_FORMAT_ARRAY, - dsv_format: Dxgi::Common::DXGI_FORMAT, - sample_desc: Dxgi::Common::DXGI_SAMPLE_DESC, - node_mask: u32, - cached_pso: Direct3D12::D3D12_CACHED_PIPELINE_STATE, - flags: Direct3D12::D3D12_PIPELINE_STATE_FLAGS, -} -impl MeshShaderPipelineStateStream { - /// # Safety - /// - /// Returned bytes contain pointers into this struct, for them to be valid, - /// this struct may be at the same location. As if `as_bytes<'a>(&'a self) -> Vec<u8> + 'a` - pub unsafe fn to_bytes(&self) -> Vec<u8> { - use Direct3D12::*; - let mut bytes = Vec::new(); - - macro_rules! push_subobject { - ($subobject_type:expr, $data:expr) => {{ - // Ensure 8-byte alignment for the subobject start - let alignment = 8; - let aligned_length = bytes.len().next_multiple_of(alignment); - bytes.resize(aligned_length, 0); - - // Append the type tag (u32) - let tag: u32 = $subobject_type.0 as u32; - bytes.extend_from_slice(&tag.to_ne_bytes()); - - // Align the data - let obj_align = align_of_val(&$data); - let data_start = bytes.len().next_multiple_of(obj_align); - bytes.resize(data_start, 0); - - // Append the data itself - #[allow(clippy::ptr_as_ptr, trivial_casts)] - let data_ptr = &$data as *const _ as *const u8; - let data_size = size_of_val(&$data); - let slice = unsafe { core::slice::from_raw_parts(data_ptr, data_size) }; - bytes.extend_from_slice(slice); - }}; - } - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE, - self.root_signature - ); - if !self.task_shader.pShaderBytecode.is_null() { - push_subobject!(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS, self.task_shader); - } - push_subobject!(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS, self.mesh_shader); - if !self.pixel_shader.pShaderBytecode.is_null() { - push_subobject!(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS, self.pixel_shader); - } - push_subobject!(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND, self.blend_state); - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK, - self.sample_mask - ); - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER, - self.rasterizer_state - ); - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL, - self.depth_stencil_state - ); - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY, - self.primitive_topology_type - ); - if self.rtv_formats.NumRenderTargets != 0 { - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS, - self.rtv_formats - ); - } - if self.dsv_format != Dxgi::Common::DXGI_FORMAT_UNKNOWN { - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT, - self.dsv_format - ); - } - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC, - self.sample_desc - ); - if self.node_mask != 0 { - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK, - self.node_mask - ); - } - if !self.cached_pso.pCachedBlob.is_null() { - push_subobject!( - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO, - self.cached_pso - ); - } - push_subobject!(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS, self.flags); - bytes - } -} diff --git a/third_party/rust/wgpu-hal/src/dx12/pipeline_desc.rs b/third_party/rust/wgpu-hal/src/dx12/pipeline_desc.rs @@ -0,0 +1,344 @@ +//! We try to use pipeline stream descriptors where possible, but this isn't allowed +//! on some older windows 10 versions. Therefore, we also must have some logic to +//! convert such descriptors to the "traditional" equivalent, +//! `D3D12_GRAPHICS_PIPELINE_STATE_DESC`. +//! +//! Stream descriptors allow extending the pipeline, enabling more advanced features, +//! including mesh shaders and multiview/view instancing. Using a stream descriptor +//! is like using a vulkan descriptor with a `pNext` chain. It doesn't have direct +//! benefits to all use cases, but allows new use cases. +//! +//! The code for pipeline stream descriptors is very complicated, and can have bad +//! consequences if it is written incorrectly. It has been isolated to this file for +//! that reason. + +use core::{ffi::c_void, mem::ManuallyDrop, ptr::NonNull}; + +use alloc::vec::Vec; +use windows::Win32::Graphics::Direct3D12::*; +use windows::Win32::Graphics::Dxgi::Common::*; +use windows_core::Interface; + +use crate::dx12::borrow_interface_temporarily; + +// Wrapper newtypes for various pipeline subobjects which +// use complicated or non-unique representations. + +#[repr(transparent)] +#[derive(Copy, Clone)] +// Option<NonNull<c_void>> is guaranteed to have the same representation as a raw pointer. +struct RootSignature(Option<NonNull<c_void>>); + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct VertexShader(D3D12_SHADER_BYTECODE); +#[repr(transparent)] +#[derive(Copy, Clone)] +struct PixelShader(D3D12_SHADER_BYTECODE); + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct MeshShader(D3D12_SHADER_BYTECODE); + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct TaskShader(D3D12_SHADER_BYTECODE); + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct SampleMask(u32); + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct NodeMask(u32); + +/// Trait for types that can be used as subobjects in a pipeline state stream. +/// +/// Safety: +/// - The type must be the correct alignment and size for the subobject it represents. +/// - The type must map to exactly one `D3D12_PIPELINE_STATE_SUBOBJECT_TYPE` variant. +/// - The variant must correctly represent the type's role in the pipeline state stream. +/// - The type must be `Copy` to ensure safe duplication in the stream. +/// - The type must be valid to memcpy into the pipeline state stream. +unsafe trait RenderPipelineStreamObject: Copy { + const SUBOBJECT_TYPE: D3D12_PIPELINE_STATE_SUBOBJECT_TYPE; +} + +macro_rules! implement_stream_object { + (unsafe $ty:ty => $variant:expr) => { + unsafe impl RenderPipelineStreamObject for $ty { + const SUBOBJECT_TYPE: D3D12_PIPELINE_STATE_SUBOBJECT_TYPE = $variant; + } + }; +} + +implement_stream_object! { unsafe RootSignature => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE } +implement_stream_object! { unsafe VertexShader => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS } +implement_stream_object! { unsafe PixelShader => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS } +implement_stream_object! { unsafe MeshShader => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS } +implement_stream_object! { unsafe TaskShader => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS } +implement_stream_object! { unsafe D3D12_BLEND_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND } +implement_stream_object! { unsafe SampleMask => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK } +implement_stream_object! { unsafe D3D12_RASTERIZER_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER } +implement_stream_object! { unsafe D3D12_DEPTH_STENCIL_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL } +implement_stream_object! { unsafe D3D12_PRIMITIVE_TOPOLOGY_TYPE => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY } +implement_stream_object! { unsafe D3D12_RT_FORMAT_ARRAY => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS } +implement_stream_object! { unsafe DXGI_FORMAT => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT } +implement_stream_object! { unsafe DXGI_SAMPLE_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC } +implement_stream_object! { unsafe NodeMask => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK } +implement_stream_object! { unsafe D3D12_CACHED_PIPELINE_STATE => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO } +implement_stream_object! { unsafe D3D12_PIPELINE_STATE_FLAGS => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS } +implement_stream_object! { unsafe D3D12_INPUT_LAYOUT_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT } +implement_stream_object! { unsafe D3D12_INDEX_BUFFER_STRIP_CUT_VALUE => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE } +implement_stream_object! { unsafe D3D12_STREAM_OUTPUT_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT } +implement_stream_object! { unsafe D3D12_VIEW_INSTANCING_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING } + +/// Implementaation of a pipeline state stream, which is a sequence of subobjects put into +/// a byte array according to some basic alignment rules. +/// +/// Each subobject must start on an 8 byte boundary. Each subobject contains a 32 bit +/// type identifier, followed by the actual subobject data, aligned as required by the +/// subobject's structure. +/// +/// See <https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_pipeline_state_stream_desc> +/// for more information. +pub(super) struct RenderPipelineStateStream<'a> { + bytes: Vec<u8>, + _marker: core::marker::PhantomData<&'a ()>, +} + +impl<'a> RenderPipelineStateStream<'a> { + fn new() -> Self { + // Dynamic allocation is used here because the resulting stream can become very large. + // We pre-allocate the size based on an estimate of the size of the struct plus some extra space + // per member for tags and alignment padding. In practice this will always be too big, as not + // all members will be used. + let size_of_stream_desc = size_of::<RenderPipelineStateStreamDesc>(); + let members = 20; // Approximate number of members we might push + let capacity = size_of_stream_desc + members * 8; // Extra space for tags and alignment + Self { + bytes: Vec::with_capacity(capacity), + _marker: core::marker::PhantomData, + } + } + + /// Align the internal byte buffer to the given alignment, + /// padding with zeros as necessary. + fn align_to(&mut self, alignment: usize) { + let aligned_length = self.bytes.len().next_multiple_of(alignment); + self.bytes.resize(aligned_length, 0); + } + + /// Adds a subobject to the pipeline state stream. + fn add_object<T: RenderPipelineStreamObject>(&mut self, object: T) { + // Ensure 8-byte alignment for the subobject start. + self.align_to(8); + + // Append the type tag (u32) + let tag: u32 = T::SUBOBJECT_TYPE.0 as u32; + self.bytes.extend_from_slice(&tag.to_ne_bytes()); + + // Align the data to its natural alignment. + self.align_to(align_of_val::<T>(&object)); + + // Append the data itself, as raw bytes + let data_ptr: *const T = &object; + let data_u8_ptr: *const u8 = data_ptr.cast::<u8>(); + let data_size = size_of_val::<T>(&object); + let slice = unsafe { core::slice::from_raw_parts::<u8>(data_u8_ptr, data_size) }; + self.bytes.extend_from_slice(slice); + } + + /// Creates a pipeline state object from the stream. + /// + /// Safety: + /// - All unsafety invariants required by [`ID3D12Device2::CreatePipelineState`] must be upheld by the caller. + pub unsafe fn create_pipeline_state( + &mut self, + device: &ID3D12Device2, + ) -> windows::core::Result<ID3D12PipelineState> { + let stream_desc = D3D12_PIPELINE_STATE_STREAM_DESC { + SizeInBytes: self.bytes.len(), + pPipelineStateSubobjectStream: self.bytes.as_mut_ptr().cast(), + }; + + // Safety: lifetime on Self preserved the contents + // of the stream. Other unsafety invariants are upheld by the caller. + unsafe { device.CreatePipelineState(&stream_desc) } + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct RenderPipelineStateStreamDesc<'a> { + pub root_signature: Option<&'a ID3D12RootSignature>, + pub pixel_shader: D3D12_SHADER_BYTECODE, + pub blend_state: D3D12_BLEND_DESC, + pub sample_mask: u32, + pub rasterizer_state: D3D12_RASTERIZER_DESC, + pub depth_stencil_state: D3D12_DEPTH_STENCIL_DESC, + pub primitive_topology_type: D3D12_PRIMITIVE_TOPOLOGY_TYPE, + pub rtv_formats: D3D12_RT_FORMAT_ARRAY, + pub dsv_format: DXGI_FORMAT, + pub sample_desc: DXGI_SAMPLE_DESC, + pub node_mask: u32, + pub cached_pso: D3D12_CACHED_PIPELINE_STATE, + pub flags: D3D12_PIPELINE_STATE_FLAGS, + pub view_instancing: Option<D3D12_VIEW_INSTANCING_DESC>, + + // Vertex pipeline specific + pub vertex_shader: D3D12_SHADER_BYTECODE, + pub input_layout: D3D12_INPUT_LAYOUT_DESC, + pub index_buffer_strip_cut_value: D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, + pub stream_output: D3D12_STREAM_OUTPUT_DESC, + + // Mesh pipeline specific + pub task_shader: D3D12_SHADER_BYTECODE, + pub mesh_shader: D3D12_SHADER_BYTECODE, +} + +impl RenderPipelineStateStreamDesc<'_> { + pub fn to_stream(&self) -> RenderPipelineStateStream<'_> { + let mut stream = RenderPipelineStateStream::new(); + + // Importantly here, the ID3D12RootSignature _itself_ is the pointer we're + // trying to serialize into the stream, not a pointer to the pointer. + // + // This is correct because as_raw() returns turns that smart object into the raw + // pointer that _is_ the com object handle. + let root_sig_pointer = self + .root_signature + .map(|a| NonNull::new(a.as_raw()).unwrap()); + // Because the stream object borrows from self for its entire lifetime, + // it is safe to store the pointer into it. + stream.add_object(RootSignature(root_sig_pointer)); + + stream.add_object(self.blend_state); + stream.add_object(SampleMask(self.sample_mask)); + stream.add_object(self.rasterizer_state); + stream.add_object(self.depth_stencil_state); + stream.add_object(self.primitive_topology_type); + if self.rtv_formats.NumRenderTargets != 0 { + stream.add_object(self.rtv_formats); + } + if self.dsv_format != DXGI_FORMAT_UNKNOWN { + stream.add_object(self.dsv_format); + } + stream.add_object(self.sample_desc); + if self.node_mask != 0 { + stream.add_object(NodeMask(self.node_mask)); + } + if !self.cached_pso.pCachedBlob.is_null() { + stream.add_object(self.cached_pso); + } + stream.add_object(self.flags); + if let Some(view_instancing) = self.view_instancing { + stream.add_object(view_instancing); + } + if !self.pixel_shader.pShaderBytecode.is_null() { + stream.add_object(PixelShader(self.pixel_shader)); + } + if !self.vertex_shader.pShaderBytecode.is_null() { + stream.add_object(VertexShader(self.vertex_shader)); + stream.add_object(self.input_layout); + stream.add_object(self.index_buffer_strip_cut_value); + stream.add_object(self.stream_output); + } + if !self.task_shader.pShaderBytecode.is_null() { + stream.add_object(TaskShader(self.task_shader)); + } + if !self.mesh_shader.pShaderBytecode.is_null() { + stream.add_object(MeshShader(self.mesh_shader)); + } + + stream + } + + /// Returns a traditional D3D12_GRAPHICS_PIPELINE_STATE_DESC. + /// + /// Safety: + /// - This returned struct must not outlive self. + pub unsafe fn to_graphics_pipeline_descriptor(&self) -> D3D12_GRAPHICS_PIPELINE_STATE_DESC { + D3D12_GRAPHICS_PIPELINE_STATE_DESC { + pRootSignature: if let Some(rsig) = self.root_signature { + unsafe { borrow_interface_temporarily(rsig) } + } else { + ManuallyDrop::new(None) + }, + VS: self.vertex_shader, + PS: self.pixel_shader, + DS: D3D12_SHADER_BYTECODE::default(), + HS: D3D12_SHADER_BYTECODE::default(), + GS: D3D12_SHADER_BYTECODE::default(), + StreamOutput: self.stream_output, + BlendState: self.blend_state, + SampleMask: self.sample_mask, + RasterizerState: self.rasterizer_state, + DepthStencilState: self.depth_stencil_state, + InputLayout: self.input_layout, + IBStripCutValue: self.index_buffer_strip_cut_value, + PrimitiveTopologyType: self.primitive_topology_type, + NumRenderTargets: self.rtv_formats.NumRenderTargets, + RTVFormats: self.rtv_formats.RTFormats, + DSVFormat: self.dsv_format, + SampleDesc: self.sample_desc, + NodeMask: self.node_mask, + CachedPSO: self.cached_pso, + Flags: self.flags, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn wrappers() { + assert_eq!(size_of::<RootSignature>(), size_of::<ID3D12RootSignature>()); + assert_eq!( + align_of::<RootSignature>(), + align_of::<ID3D12RootSignature>() + ) + } + + implement_stream_object!(unsafe u16 => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE(1)); + implement_stream_object!(unsafe u32 => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE(2)); + implement_stream_object!(unsafe u64 => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE(3)); + + #[test] + fn stream() { + let mut stream = RenderPipelineStateStream::new(); + + stream.add_object(42u16); + stream.add_object(84u32); + stream.add_object(168u64); + + assert_eq!(stream.bytes.len(), 32); + + // Object 1: u16 + + // Tag at the beginning + assert_eq!(&stream.bytes[0..4], &1u32.to_ne_bytes()); + // Data tucked in, aligned to the natural alignment of u16 + assert_eq!(&stream.bytes[4..6], &42u16.to_ne_bytes()); + // Padding to align the next subobject to an 8 byte boundary. + assert_eq!(&stream.bytes[6..8], &[0, 0]); + + // Object 2: u32 + + // Tag at the beginning + assert_eq!(&stream.bytes[8..12], &2u32.to_ne_bytes()); + // Data tucked in, aligned to the natural alignment of u32 + assert_eq!(&stream.bytes[12..16], &84u32.to_ne_bytes()); + + // Object 3: u64 + + // Tag at the beginning + assert_eq!(&stream.bytes[16..20], &3u32.to_ne_bytes()); + // Padding to align the u64 to an 8 byte boundary. + assert_eq!(&stream.bytes[20..24], &[0, 0, 0, 0]); + // Data tucked in, aligned to the natural alignment of u64 + assert_eq!(&stream.bytes[24..32], &168u64.to_ne_bytes()); + } +} diff --git a/third_party/rust/wgpu-hal/src/dx12/shader_compilation.rs b/third_party/rust/wgpu-hal/src/dx12/shader_compilation.rs @@ -396,6 +396,11 @@ fn compile_dxc( .private_caps .instance_flags .contains(wgt::InstanceFlags::DEBUG) + && !device + .shared + .private_caps + .workarounds + .avoid_shader_debug_info { compile_args.push(Dxc::DXC_ARG_DEBUG); compile_args.push(Dxc::DXC_ARG_SKIP_OPTIMIZATIONS); diff --git a/third_party/rust/wgpu-hal/src/gles/command.rs b/third_party/rust/wgpu-hal/src/gles/command.rs @@ -311,11 +311,10 @@ impl crate::CommandEncoder for super::CommandEncoder { let mut combined_usage = wgt::TextureUses::empty(); for bar in barriers { // GLES only synchronizes storage -> anything explicitly - if !bar - .usage - .from - .contains(wgt::TextureUses::STORAGE_READ_WRITE) - { + // if shader writes to a texture then barriers should be placed + if !bar.usage.from.intersects( + wgt::TextureUses::STORAGE_READ_WRITE | wgt::TextureUses::STORAGE_WRITE_ONLY, + ) { continue; } // unlike buffers, there is no need for a concrete texture diff --git a/third_party/rust/wgpu-hal/src/gles/mod.rs b/third_party/rust/wgpu-hal/src/gles/mod.rs @@ -345,6 +345,7 @@ pub struct Buffer { raw: Option<glow::Buffer>, target: BindTarget, size: wgt::BufferAddress, + /// Flags to use within calls to [`Device::map_buffer`](crate::Device::map_buffer). map_flags: u32, data: Option<Arc<MaybeMutex<Vec<u8>>>>, offset_of_current_mapping: Arc<MaybeMutex<wgt::BufferAddress>>, diff --git a/third_party/rust/wgpu-hal/src/gles/queue.rs b/third_party/rust/wgpu-hal/src/gles/queue.rs @@ -1257,6 +1257,10 @@ impl super::Queue { } unsafe { gl.memory_barrier(flags) }; } + // because `STORAGE_WRITE_ONLY` and `STORAGE_READ_WRITE` are only states + // we can transit from due OpenGL memory barriers are used to make _subsequent_ + // operations see changes from the _shader_ side. We filter out usage changes that are + // does not comes from the shader side in `transition_textures` C::TextureBarrier(usage) => { let mut flags = 0; if usage.contains(wgt::TextureUses::RESOURCE) { @@ -1269,6 +1273,9 @@ impl super::Queue { ) { flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT; } + if usage.intersects(wgt::TextureUses::COPY_SRC) { + flags |= glow::PIXEL_BUFFER_BARRIER_BIT; + } if usage.contains(wgt::TextureUses::COPY_DST) { flags |= glow::TEXTURE_UPDATE_BARRIER_BIT; } diff --git a/third_party/rust/wgpu-hal/src/metal/adapter.rs b/third_party/rust/wgpu-hal/src/metal/adapter.rs @@ -607,6 +607,8 @@ impl super::PrivateCapabilities { let argument_buffers = device.argument_buffers_support(); + let is_virtual = device.name().to_lowercase().contains("virtual"); + Self { family_check, msl_version: if os_is_xr || version.at_least((14, 0), (17, 0), os_is_mac) { @@ -902,6 +904,12 @@ impl super::PrivateCapabilities { && (device.supports_family(MTLGPUFamily::Apple7) || device.supports_family(MTLGPUFamily::Mac2)), supports_shared_event: version.at_least((10, 14), (12, 0), os_is_mac), + mesh_shaders: family_check + && (device.supports_family(MTLGPUFamily::Metal3) + || device.supports_family(MTLGPUFamily::Apple7) + || device.supports_family(MTLGPUFamily::Mac2)) + // Mesh shaders don't work on virtual devices even if they should be supported. + && !is_virtual, supported_vertex_amplification_factor: { let mut factor = 1; // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=8 @@ -1023,6 +1031,8 @@ impl super::PrivateCapabilities { features.insert(F::SUBGROUP | F::SUBGROUP_BARRIER); } + features.set(F::EXPERIMENTAL_MESH_SHADER, self.mesh_shaders); + if self.supported_vertex_amplification_factor > 1 { features.insert(F::MULTIVIEW); } @@ -1102,10 +1112,11 @@ impl super::PrivateCapabilities { max_buffer_size: self.max_buffer_size, max_non_sampler_bindings: u32::MAX, - max_task_workgroup_total_count: 0, - max_task_workgroups_per_dimension: 0, + // See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf, Maximum threadgroups per mesh shader grid + max_task_workgroup_total_count: 1024, + max_task_workgroups_per_dimension: 1024, max_mesh_multiview_view_count: 0, - max_mesh_output_layers: 0, + max_mesh_output_layers: self.max_texture_layers as u32, max_blas_primitive_count: 0, // When added: 2^28 from https://developer.apple.com/documentation/metal/mtlaccelerationstructureusage/extendedlimits max_blas_geometry_count: 0, // When added: 2^24 diff --git a/third_party/rust/wgpu-hal/src/metal/command.rs b/third_party/rust/wgpu-hal/src/metal/command.rs @@ -22,11 +22,9 @@ impl Default for super::CommandState { compute: None, raw_primitive_type: MTLPrimitiveType::Point, index: None, - raw_wg_size: MTLSize::new(0, 0, 0), stage_infos: Default::default(), storage_buffer_length_map: Default::default(), vertex_buffer_size_map: Default::default(), - work_group_memory_sizes: Vec::new(), push_constants: Vec::new(), pending_timer_queries: Vec::new(), } @@ -146,6 +144,127 @@ impl super::CommandEncoder { self.state.reset(); self.leave_blit(); } + + /// Updates the bindings for a single shader stage, called in `set_bind_group`. + #[expect(clippy::too_many_arguments)] + fn update_bind_group_state( + &mut self, + stage: naga::ShaderStage, + render_encoder: Option<&metal::RenderCommandEncoder>, + compute_encoder: Option<&metal::ComputeCommandEncoder>, + index_base: super::ResourceData<u32>, + bg_info: &super::BindGroupLayoutInfo, + dynamic_offsets: &[wgt::DynamicOffset], + group_index: u32, + group: &super::BindGroup, + ) { + let resource_indices = match stage { + naga::ShaderStage::Vertex => &bg_info.base_resource_indices.vs, + naga::ShaderStage::Fragment => &bg_info.base_resource_indices.fs, + naga::ShaderStage::Task => &bg_info.base_resource_indices.ts, + naga::ShaderStage::Mesh => &bg_info.base_resource_indices.ms, + naga::ShaderStage::Compute => &bg_info.base_resource_indices.cs, + }; + let buffers = match stage { + naga::ShaderStage::Vertex => group.counters.vs.buffers, + naga::ShaderStage::Fragment => group.counters.fs.buffers, + naga::ShaderStage::Task => group.counters.ts.buffers, + naga::ShaderStage::Mesh => group.counters.ms.buffers, + naga::ShaderStage::Compute => group.counters.cs.buffers, + }; + let mut changes_sizes_buffer = false; + for index in 0..buffers { + let buf = &group.buffers[(index_base.buffers + index) as usize]; + let mut offset = buf.offset; + if let Some(dyn_index) = buf.dynamic_index { + offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; + } + let a1 = (resource_indices.buffers + index) as u64; + let a2 = Some(buf.ptr.as_native()); + let a3 = offset; + match stage { + naga::ShaderStage::Vertex => render_encoder.unwrap().set_vertex_buffer(a1, a2, a3), + naga::ShaderStage::Fragment => { + render_encoder.unwrap().set_fragment_buffer(a1, a2, a3) + } + naga::ShaderStage::Task => render_encoder.unwrap().set_object_buffer(a1, a2, a3), + naga::ShaderStage::Mesh => render_encoder.unwrap().set_mesh_buffer(a1, a2, a3), + naga::ShaderStage::Compute => compute_encoder.unwrap().set_buffer(a1, a2, a3), + } + if let Some(size) = buf.binding_size { + let br = naga::ResourceBinding { + group: group_index, + binding: buf.binding_location, + }; + self.state.storage_buffer_length_map.insert(br, size); + changes_sizes_buffer = true; + } + } + if changes_sizes_buffer { + if let Some((index, sizes)) = self + .state + .make_sizes_buffer_update(stage, &mut self.temp.binding_sizes) + { + let a1 = index as _; + let a2 = (sizes.len() * WORD_SIZE) as u64; + let a3 = sizes.as_ptr().cast(); + match stage { + naga::ShaderStage::Vertex => { + render_encoder.unwrap().set_vertex_bytes(a1, a2, a3) + } + naga::ShaderStage::Fragment => { + render_encoder.unwrap().set_fragment_bytes(a1, a2, a3) + } + naga::ShaderStage::Task => render_encoder.unwrap().set_object_bytes(a1, a2, a3), + naga::ShaderStage::Mesh => render_encoder.unwrap().set_mesh_bytes(a1, a2, a3), + naga::ShaderStage::Compute => compute_encoder.unwrap().set_bytes(a1, a2, a3), + } + } + } + let samplers = match stage { + naga::ShaderStage::Vertex => group.counters.vs.samplers, + naga::ShaderStage::Fragment => group.counters.fs.samplers, + naga::ShaderStage::Task => group.counters.ts.samplers, + naga::ShaderStage::Mesh => group.counters.ms.samplers, + naga::ShaderStage::Compute => group.counters.cs.samplers, + }; + for index in 0..samplers { + let res = group.samplers[(index_base.samplers + index) as usize]; + let a1 = (resource_indices.samplers + index) as u64; + let a2 = Some(res.as_native()); + match stage { + naga::ShaderStage::Vertex => { + render_encoder.unwrap().set_vertex_sampler_state(a1, a2) + } + naga::ShaderStage::Fragment => { + render_encoder.unwrap().set_fragment_sampler_state(a1, a2) + } + naga::ShaderStage::Task => render_encoder.unwrap().set_object_sampler_state(a1, a2), + naga::ShaderStage::Mesh => render_encoder.unwrap().set_mesh_sampler_state(a1, a2), + naga::ShaderStage::Compute => compute_encoder.unwrap().set_sampler_state(a1, a2), + } + } + + let textures = match stage { + naga::ShaderStage::Vertex => group.counters.vs.textures, + naga::ShaderStage::Fragment => group.counters.fs.textures, + naga::ShaderStage::Task => group.counters.ts.textures, + naga::ShaderStage::Mesh => group.counters.ms.textures, + naga::ShaderStage::Compute => group.counters.cs.textures, + }; + for index in 0..textures { + let res = group.textures[(index_base.textures + index) as usize]; + let a1 = (resource_indices.textures + index) as u64; + let a2 = Some(res.as_native()); + match stage { + naga::ShaderStage::Vertex => render_encoder.unwrap().set_vertex_texture(a1, a2), + naga::ShaderStage::Fragment => render_encoder.unwrap().set_fragment_texture(a1, a2), + naga::ShaderStage::Task => render_encoder.unwrap().set_object_texture(a1, a2), + naga::ShaderStage::Mesh => render_encoder.unwrap().set_mesh_texture(a1, a2), + naga::ShaderStage::Compute => compute_encoder.unwrap().set_texture(a1, a2), + } + } + } } impl super::CommandState { @@ -155,7 +274,8 @@ impl super::CommandState { self.stage_infos.vs.clear(); self.stage_infos.fs.clear(); self.stage_infos.cs.clear(); - self.work_group_memory_sizes.clear(); + self.stage_infos.ts.clear(); + self.stage_infos.ms.clear(); self.push_constants.clear(); } @@ -702,168 +822,90 @@ impl crate::CommandEncoder for super::CommandEncoder { dynamic_offsets: &[wgt::DynamicOffset], ) { let bg_info = &layout.bind_group_infos[group_index as usize]; - - if let Some(ref encoder) = self.state.render { - let mut changes_sizes_buffer = false; - for index in 0..group.counters.vs.buffers { - let buf = &group.buffers[index as usize]; - let mut offset = buf.offset; - if let Some(dyn_index) = buf.dynamic_index { - offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; - } - encoder.set_vertex_buffer( - (bg_info.base_resource_indices.vs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, - ); - if let Some(size) = buf.binding_size { - let br = naga::ResourceBinding { - group: group_index, - binding: buf.binding_location, - }; - self.state.storage_buffer_length_map.insert(br, size); - changes_sizes_buffer = true; - } - } - if changes_sizes_buffer { - if let Some((index, sizes)) = self.state.make_sizes_buffer_update( - naga::ShaderStage::Vertex, - &mut self.temp.binding_sizes, - ) { - encoder.set_vertex_bytes( - index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), - ); - } - } - - changes_sizes_buffer = false; - for index in 0..group.counters.fs.buffers { - let buf = &group.buffers[(group.counters.vs.buffers + index) as usize]; - let mut offset = buf.offset; - if let Some(dyn_index) = buf.dynamic_index { - offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; - } - encoder.set_fragment_buffer( - (bg_info.base_resource_indices.fs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, - ); - if let Some(size) = buf.binding_size { - let br = naga::ResourceBinding { - group: group_index, - binding: buf.binding_location, - }; - self.state.storage_buffer_length_map.insert(br, size); - changes_sizes_buffer = true; - } - } - if changes_sizes_buffer { - if let Some((index, sizes)) = self.state.make_sizes_buffer_update( - naga::ShaderStage::Fragment, - &mut self.temp.binding_sizes, - ) { - encoder.set_fragment_bytes( - index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), - ); - } - } - - for index in 0..group.counters.vs.samplers { - let res = group.samplers[index as usize]; - encoder.set_vertex_sampler_state( - (bg_info.base_resource_indices.vs.samplers + index) as u64, - Some(res.as_native()), - ); - } - for index in 0..group.counters.fs.samplers { - let res = group.samplers[(group.counters.vs.samplers + index) as usize]; - encoder.set_fragment_sampler_state( - (bg_info.base_resource_indices.fs.samplers + index) as u64, - Some(res.as_native()), - ); - } - - for index in 0..group.counters.vs.textures { - let res = group.textures[index as usize]; - encoder.set_vertex_texture( - (bg_info.base_resource_indices.vs.textures + index) as u64, - Some(res.as_native()), - ); - } - for index in 0..group.counters.fs.textures { - let res = group.textures[(group.counters.vs.textures + index) as usize]; - encoder.set_fragment_texture( - (bg_info.base_resource_indices.fs.textures + index) as u64, - Some(res.as_native()), - ); - } - + let render_encoder = self.state.render.clone(); + let compute_encoder = self.state.compute.clone(); + if let Some(encoder) = render_encoder { + self.update_bind_group_state( + naga::ShaderStage::Vertex, + Some(&encoder), + None, + // All zeros, as vs comes first + super::ResourceData::default(), + bg_info, + dynamic_offsets, + group_index, + group, + ); + self.update_bind_group_state( + naga::ShaderStage::Task, + Some(&encoder), + None, + // All zeros, as ts comes first + super::ResourceData::default(), + bg_info, + dynamic_offsets, + group_index, + group, + ); + self.update_bind_group_state( + naga::ShaderStage::Mesh, + Some(&encoder), + None, + group.counters.ts.clone(), + bg_info, + dynamic_offsets, + group_index, + group, + ); + self.update_bind_group_state( + naga::ShaderStage::Fragment, + Some(&encoder), + None, + super::ResourceData { + buffers: group.counters.vs.buffers + + group.counters.ts.buffers + + group.counters.ms.buffers, + textures: group.counters.vs.textures + + group.counters.ts.textures + + group.counters.ms.textures, + samplers: group.counters.vs.samplers + + group.counters.ts.samplers + + group.counters.ms.samplers, + }, + bg_info, + dynamic_offsets, + group_index, + group, + ); // Call useResource on all textures and buffers used indirectly so they are alive for (resource, use_info) in group.resources_to_use.iter() { encoder.use_resource_at(resource.as_native(), use_info.uses, use_info.stages); } } - - if let Some(ref encoder) = self.state.compute { - let index_base = super::ResourceData { - buffers: group.counters.vs.buffers + group.counters.fs.buffers, - samplers: group.counters.vs.samplers + group.counters.fs.samplers, - textures: group.counters.vs.textures + group.counters.fs.textures, - }; - - let mut changes_sizes_buffer = false; - for index in 0..group.counters.cs.buffers { - let buf = &group.buffers[(index_base.buffers + index) as usize]; - let mut offset = buf.offset; - if let Some(dyn_index) = buf.dynamic_index { - offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; - } - encoder.set_buffer( - (bg_info.base_resource_indices.cs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, - ); - if let Some(size) = buf.binding_size { - let br = naga::ResourceBinding { - group: group_index, - binding: buf.binding_location, - }; - self.state.storage_buffer_length_map.insert(br, size); - changes_sizes_buffer = true; - } - } - if changes_sizes_buffer { - if let Some((index, sizes)) = self.state.make_sizes_buffer_update( - naga::ShaderStage::Compute, - &mut self.temp.binding_sizes, - ) { - encoder.set_bytes( - index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), - ); - } - } - - for index in 0..group.counters.cs.samplers { - let res = group.samplers[(index_base.samplers + index) as usize]; - encoder.set_sampler_state( - (bg_info.base_resource_indices.cs.samplers + index) as u64, - Some(res.as_native()), - ); - } - for index in 0..group.counters.cs.textures { - let res = group.textures[(index_base.textures + index) as usize]; - encoder.set_texture( - (bg_info.base_resource_indices.cs.textures + index) as u64, - Some(res.as_native()), - ); - } - + if let Some(encoder) = compute_encoder { + self.update_bind_group_state( + naga::ShaderStage::Compute, + None, + Some(&encoder), + super::ResourceData { + buffers: group.counters.vs.buffers + + group.counters.ts.buffers + + group.counters.ms.buffers + + group.counters.fs.buffers, + textures: group.counters.vs.textures + + group.counters.ts.textures + + group.counters.ms.textures + + group.counters.fs.textures, + samplers: group.counters.vs.samplers + + group.counters.ts.samplers + + group.counters.ms.samplers + + group.counters.fs.samplers, + }, + bg_info, + dynamic_offsets, + group_index, + group, + ); // Call useResource on all textures and buffers used indirectly so they are alive for (resource, use_info) in group.resources_to_use.iter() { if !use_info.visible_in_compute { @@ -911,6 +953,20 @@ impl crate::CommandEncoder for super::CommandEncoder { state_pc.as_ptr().cast(), ) } + if stages.contains(wgt::ShaderStages::TASK) { + self.state.render.as_ref().unwrap().set_object_bytes( + layout.push_constants_infos.ts.unwrap().buffer_index as _, + (layout.total_push_constants as usize * WORD_SIZE) as _, + state_pc.as_ptr().cast(), + ) + } + if stages.contains(wgt::ShaderStages::MESH) { + self.state.render.as_ref().unwrap().set_object_bytes( + layout.push_constants_infos.ms.unwrap().buffer_index as _, + (layout.total_push_constants as usize * WORD_SIZE) as _, + state_pc.as_ptr().cast(), + ) + } } unsafe fn insert_debug_marker(&mut self, label: &str) { @@ -935,11 +991,22 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { self.state.raw_primitive_type = pipeline.raw_primitive_type; - self.state.stage_infos.vs.assign_from(&pipeline.vs_info); + match pipeline.vs_info { + Some(ref info) => self.state.stage_infos.vs.assign_from(info), + None => self.state.stage_infos.vs.clear(), + } match pipeline.fs_info { Some(ref info) => self.state.stage_infos.fs.assign_from(info), None => self.state.stage_infos.fs.clear(), } + match pipeline.ts_info { + Some(ref info) => self.state.stage_infos.ts.assign_from(info), + None => self.state.stage_infos.ts.clear(), + } + match pipeline.ms_info { + Some(ref info) => self.state.stage_infos.ms.assign_from(info), + None => self.state.stage_infos.ms.clear(), + } let encoder = self.state.render.as_ref().unwrap(); encoder.set_render_pipeline_state(&pipeline.raw); @@ -954,7 +1021,7 @@ impl crate::CommandEncoder for super::CommandEncoder { encoder.set_depth_bias(bias.constant as f32, bias.slope_scale, bias.clamp); } - { + if pipeline.vs_info.is_some() { if let Some((index, sizes)) = self .state .make_sizes_buffer_update(naga::ShaderStage::Vertex, &mut self.temp.binding_sizes) @@ -966,7 +1033,7 @@ impl crate::CommandEncoder for super::CommandEncoder { ); } } - if pipeline.fs_lib.is_some() { + if pipeline.fs_info.is_some() { if let Some((index, sizes)) = self .state .make_sizes_buffer_update(naga::ShaderStage::Fragment, &mut self.temp.binding_sizes) @@ -978,6 +1045,56 @@ impl crate::CommandEncoder for super::CommandEncoder { ); } } + if let Some(ts_info) = &pipeline.ts_info { + // update the threadgroup memory sizes + while self.state.stage_infos.ms.work_group_memory_sizes.len() + < ts_info.work_group_memory_sizes.len() + { + self.state.stage_infos.ms.work_group_memory_sizes.push(0); + } + for (index, (cur_size, pipeline_size)) in self + .state + .stage_infos + .ms + .work_group_memory_sizes + .iter_mut() + .zip(ts_info.work_group_memory_sizes.iter()) + .enumerate() + { + let size = pipeline_size.next_multiple_of(16); + if *cur_size != size { + *cur_size = size; + encoder.set_object_threadgroup_memory_length(index as _, size as _); + } + } + if let Some((index, sizes)) = self + .state + .make_sizes_buffer_update(naga::ShaderStage::Task, &mut self.temp.binding_sizes) + { + encoder.set_object_bytes( + index as _, + (sizes.len() * WORD_SIZE) as u64, + sizes.as_ptr().cast(), + ); + } + } + if let Some(_ms_info) = &pipeline.ms_info { + // So there isn't an equivalent to + // https://developer.apple.com/documentation/metal/mtlrendercommandencoder/setthreadgroupmemorylength(_:offset:index:) + // for mesh shaders. This is probably because the CPU has less control over the dispatch sizes and such. Interestingly + // it also affects mesh shaders without task/object shaders, even though none of compute, task or fragment shaders + // behave this way. + if let Some((index, sizes)) = self + .state + .make_sizes_buffer_update(naga::ShaderStage::Mesh, &mut self.temp.binding_sizes) + { + encoder.set_mesh_bytes( + index as _, + (sizes.len() * WORD_SIZE) as u64, + sizes.as_ptr().cast(), + ); + } + } } unsafe fn set_index_buffer<'a>( @@ -1140,11 +1257,21 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn draw_mesh_tasks( &mut self, - _group_count_x: u32, - _group_count_y: u32, - _group_count_z: u32, + group_count_x: u32, + group_count_y: u32, + group_count_z: u32, ) { - unreachable!() + let encoder = self.state.render.as_ref().unwrap(); + let size = MTLSize { + width: group_count_x as u64, + height: group_count_y as u64, + depth: group_count_z as u64, + }; + encoder.draw_mesh_threadgroups( + size, + self.state.stage_infos.ts.raw_wg_size, + self.state.stage_infos.ms.raw_wg_size, + ); } unsafe fn draw_indirect( @@ -1183,11 +1310,20 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn draw_mesh_tasks_indirect( &mut self, - _buffer: &<Self::A as crate::Api>::Buffer, - _offset: wgt::BufferAddress, - _draw_count: u32, + buffer: &<Self::A as crate::Api>::Buffer, + mut offset: wgt::BufferAddress, + draw_count: u32, ) { - unreachable!() + let encoder = self.state.render.as_ref().unwrap(); + for _ in 0..draw_count { + encoder.draw_mesh_threadgroups_with_indirect_buffer( + &buffer.raw, + offset, + self.state.stage_infos.ts.raw_wg_size, + self.state.stage_infos.ms.raw_wg_size, + ); + offset += size_of::<wgt::DispatchIndirectArgs>() as wgt::BufferAddress; + } } unsafe fn draw_indirect_count( @@ -1295,7 +1431,8 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { - self.state.raw_wg_size = pipeline.work_group_size; + let previous_sizes = + core::mem::take(&mut self.state.stage_infos.cs.work_group_memory_sizes); self.state.stage_infos.cs.assign_from(&pipeline.cs_info); let encoder = self.state.compute.as_ref().unwrap(); @@ -1313,20 +1450,23 @@ impl crate::CommandEncoder for super::CommandEncoder { } // update the threadgroup memory sizes - while self.state.work_group_memory_sizes.len() < pipeline.work_group_memory_sizes.len() { - self.state.work_group_memory_sizes.push(0); - } - for (index, (cur_size, pipeline_size)) in self + for (i, current_size) in self .state + .stage_infos + .cs .work_group_memory_sizes .iter_mut() - .zip(pipeline.work_group_memory_sizes.iter()) .enumerate() { - let size = pipeline_size.next_multiple_of(16); - if *cur_size != size { - *cur_size = size; - encoder.set_threadgroup_memory_length(index as _, size as _); + let prev_size = if i < previous_sizes.len() { + previous_sizes[i] + } else { + u32::MAX + }; + let size: u32 = current_size.next_multiple_of(16); + *current_size = size; + if size != prev_size { + encoder.set_threadgroup_memory_length(i as _, size as _); } } } @@ -1339,13 +1479,17 @@ impl crate::CommandEncoder for super::CommandEncoder { height: count[1] as u64, depth: count[2] as u64, }; - encoder.dispatch_thread_groups(raw_count, self.state.raw_wg_size); + encoder.dispatch_thread_groups(raw_count, self.state.stage_infos.cs.raw_wg_size); } } unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { let encoder = self.state.compute.as_ref().unwrap(); - encoder.dispatch_thread_groups_indirect(&buffer.raw, offset, self.state.raw_wg_size); + encoder.dispatch_thread_groups_indirect( + &buffer.raw, + offset, + self.state.stage_infos.cs.raw_wg_size, + ); } unsafe fn build_acceleration_structures<'a, T>( diff --git a/third_party/rust/wgpu-hal/src/metal/device.rs b/third_party/rust/wgpu-hal/src/metal/device.rs @@ -1113,96 +1113,273 @@ impl crate::Device for super::Device { super::PipelineCache, >, ) -> Result<super::RenderPipeline, crate::PipelineError> { - let (desc_vertex_stage, desc_vertex_buffers) = match &desc.vertex_processor { - crate::VertexProcessor::Standard { - vertex_buffers, - vertex_stage, - } => (vertex_stage, *vertex_buffers), - crate::VertexProcessor::Mesh { .. } => unreachable!(), - }; - objc::rc::autoreleasepool(|| { - let descriptor = metal::RenderPipelineDescriptor::new(); - - let raw_triangle_fill_mode = match desc.primitive.polygon_mode { - wgt::PolygonMode::Fill => MTLTriangleFillMode::Fill, - wgt::PolygonMode::Line => MTLTriangleFillMode::Lines, - wgt::PolygonMode::Point => panic!( - "{:?} is not enabled for this backend", - wgt::Features::POLYGON_MODE_POINT - ), - }; + enum MetalGenericRenderPipelineDescriptor { + Standard(metal::RenderPipelineDescriptor), + Mesh(metal::MeshRenderPipelineDescriptor), + } + macro_rules! descriptor_fn { + ($descriptor:ident . $method:ident $( ( $($args:expr),* ) )? ) => { + match $descriptor { + MetalGenericRenderPipelineDescriptor::Standard(ref inner) => inner.$method$(($($args),*))?, + MetalGenericRenderPipelineDescriptor::Mesh(ref inner) => inner.$method$(($($args),*))?, + } + }; + } + impl MetalGenericRenderPipelineDescriptor { + fn set_fragment_function(&self, function: Option<&metal::FunctionRef>) { + descriptor_fn!(self.set_fragment_function(function)); + } + fn fragment_buffers(&self) -> Option<&metal::PipelineBufferDescriptorArrayRef> { + descriptor_fn!(self.fragment_buffers()) + } + fn set_depth_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + descriptor_fn!(self.set_depth_attachment_pixel_format(pixel_format)); + } + fn color_attachments( + &self, + ) -> &metal::RenderPipelineColorAttachmentDescriptorArrayRef { + descriptor_fn!(self.color_attachments()) + } + fn set_stencil_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + descriptor_fn!(self.set_stencil_attachment_pixel_format(pixel_format)); + } + fn set_alpha_to_coverage_enabled(&self, enabled: bool) { + descriptor_fn!(self.set_alpha_to_coverage_enabled(enabled)); + } + fn set_label(&self, label: &str) { + descriptor_fn!(self.set_label(label)); + } + fn set_max_vertex_amplification_count(&self, count: metal::NSUInteger) { + descriptor_fn!(self.set_max_vertex_amplification_count(count)) + } + } let (primitive_class, raw_primitive_type) = conv::map_primitive_topology(desc.primitive.topology); - // Vertex shader - let (vs_lib, vs_info) = { - let mut vertex_buffer_mappings = Vec::<naga::back::msl::VertexBufferMapping>::new(); - for (i, vbl) in desc_vertex_buffers.iter().enumerate() { - let mut attributes = Vec::<naga::back::msl::AttributeMapping>::new(); - for attribute in vbl.attributes.iter() { - attributes.push(naga::back::msl::AttributeMapping { - shader_location: attribute.shader_location, - offset: attribute.offset as u32, - format: convert_vertex_format_to_naga(attribute.format), + let vs_info; + let ts_info; + let ms_info; + + // Create the pipeline descriptor and do vertex/mesh pipeline specific setup + let descriptor = match desc.vertex_processor { + crate::VertexProcessor::Standard { + vertex_buffers, + ref vertex_stage, + } => { + // Vertex pipeline specific setup + + let descriptor = metal::RenderPipelineDescriptor::new(); + ts_info = None; + ms_info = None; + + // Collect vertex buffer mappings + let mut vertex_buffer_mappings = + Vec::<naga::back::msl::VertexBufferMapping>::new(); + for (i, vbl) in vertex_buffers.iter().enumerate() { + let mut attributes = Vec::<naga::back::msl::AttributeMapping>::new(); + for attribute in vbl.attributes.iter() { + attributes.push(naga::back::msl::AttributeMapping { + shader_location: attribute.shader_location, + offset: attribute.offset as u32, + format: convert_vertex_format_to_naga(attribute.format), + }); + } + + let mapping = naga::back::msl::VertexBufferMapping { + id: self.shared.private_caps.max_vertex_buffers - 1 - i as u32, + stride: if vbl.array_stride > 0 { + vbl.array_stride.try_into().unwrap() + } else { + vbl.attributes + .iter() + .map(|attribute| attribute.offset + attribute.format.size()) + .max() + .unwrap_or(0) + .try_into() + .unwrap() + }, + step_mode: match (vbl.array_stride == 0, vbl.step_mode) { + (true, _) => naga::back::msl::VertexBufferStepMode::Constant, + (false, wgt::VertexStepMode::Vertex) => { + naga::back::msl::VertexBufferStepMode::ByVertex + } + (false, wgt::VertexStepMode::Instance) => { + naga::back::msl::VertexBufferStepMode::ByInstance + } + }, + attributes, + }; + vertex_buffer_mappings.push(mapping); + } + + // Setup vertex shader + { + let vs = self.load_shader( + vertex_stage, + &vertex_buffer_mappings, + desc.layout, + primitive_class, + naga::ShaderStage::Vertex, + )?; + + descriptor.set_vertex_function(Some(&vs.function)); + if self.shared.private_caps.supports_mutability { + Self::set_buffers_mutability( + descriptor.vertex_buffers().unwrap(), + vs.immutable_buffer_mask, + ); + } + + vs_info = Some(super::PipelineStageInfo { + push_constants: desc.layout.push_constants_infos.vs, + sizes_slot: desc.layout.per_stage_map.vs.sizes_buffer, + sized_bindings: vs.sized_bindings, + vertex_buffer_mappings, + library: Some(vs.library), + raw_wg_size: Default::default(), + work_group_memory_sizes: vec![], }); } - vertex_buffer_mappings.push(naga::back::msl::VertexBufferMapping { - id: self.shared.private_caps.max_vertex_buffers - 1 - i as u32, - stride: if vbl.array_stride > 0 { - vbl.array_stride.try_into().unwrap() - } else { - vbl.attributes - .iter() - .map(|attribute| attribute.offset + attribute.format.size()) - .max() - .unwrap_or(0) - .try_into() - .unwrap() - }, - step_mode: match (vbl.array_stride == 0, vbl.step_mode) { - (true, _) => naga::back::msl::VertexBufferStepMode::Constant, - (false, wgt::VertexStepMode::Vertex) => { - naga::back::msl::VertexBufferStepMode::ByVertex + // Validate vertex buffer count + if desc.layout.total_counters.vs.buffers + (vertex_buffers.len() as u32) + > self.shared.private_caps.max_vertex_buffers + { + let msg = format!( + "pipeline needs too many buffers in the vertex stage: {} vertex and {} layout", + vertex_buffers.len(), + desc.layout.total_counters.vs.buffers + ); + return Err(crate::PipelineError::Linkage( + wgt::ShaderStages::VERTEX, + msg, + )); + } + + // Set the pipeline vertex buffer info + if !vertex_buffers.is_empty() { + let vertex_descriptor = metal::VertexDescriptor::new(); + for (i, vb) in vertex_buffers.iter().enumerate() { + let buffer_index = + self.shared.private_caps.max_vertex_buffers as u64 - 1 - i as u64; + let buffer_desc = + vertex_descriptor.layouts().object_at(buffer_index).unwrap(); + + // Metal expects the stride to be the actual size of the attributes. + // The semantics of array_stride == 0 can be achieved by setting + // the step function to constant and rate to 0. + if vb.array_stride == 0 { + let stride = vb + .attributes + .iter() + .map(|attribute| attribute.offset + attribute.format.size()) + .max() + .unwrap_or(0); + buffer_desc.set_stride(wgt::math::align_to(stride, 4)); + buffer_desc.set_step_function(MTLVertexStepFunction::Constant); + buffer_desc.set_step_rate(0); + } else { + buffer_desc.set_stride(vb.array_stride); + buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode)); } - (false, wgt::VertexStepMode::Instance) => { - naga::back::msl::VertexBufferStepMode::ByInstance + + for at in vb.attributes { + let attribute_desc = vertex_descriptor + .attributes() + .object_at(at.shader_location as u64) + .unwrap(); + attribute_desc.set_format(conv::map_vertex_format(at.format)); + attribute_desc.set_buffer_index(buffer_index); + attribute_desc.set_offset(at.offset); } - }, - attributes, - }); - } + } + descriptor.set_vertex_descriptor(Some(vertex_descriptor)); + } - let vs = self.load_shader( - desc_vertex_stage, - &vertex_buffer_mappings, - desc.layout, - primitive_class, - naga::ShaderStage::Vertex, - )?; - - descriptor.set_vertex_function(Some(&vs.function)); - if self.shared.private_caps.supports_mutability { - Self::set_buffers_mutability( - descriptor.vertex_buffers().unwrap(), - vs.immutable_buffer_mask, - ); + MetalGenericRenderPipelineDescriptor::Standard(descriptor) } + crate::VertexProcessor::Mesh { + ref task_stage, + ref mesh_stage, + } => { + // Mesh pipeline specific setup + + vs_info = None; + let descriptor = metal::MeshRenderPipelineDescriptor::new(); + + // Setup task stage + if let Some(ref task_stage) = task_stage { + let ts = self.load_shader( + task_stage, + &[], + desc.layout, + primitive_class, + naga::ShaderStage::Task, + )?; + descriptor.set_object_function(Some(&ts.function)); + if self.shared.private_caps.supports_mutability { + Self::set_buffers_mutability( + descriptor.mesh_buffers().unwrap(), + ts.immutable_buffer_mask, + ); + } + ts_info = Some(super::PipelineStageInfo { + push_constants: desc.layout.push_constants_infos.ts, + sizes_slot: desc.layout.per_stage_map.ts.sizes_buffer, + sized_bindings: ts.sized_bindings, + vertex_buffer_mappings: vec![], + library: Some(ts.library), + raw_wg_size: ts.wg_size, + work_group_memory_sizes: ts.wg_memory_sizes, + }); + } else { + ts_info = None; + } - let info = super::PipelineStageInfo { - push_constants: desc.layout.push_constants_infos.vs, - sizes_slot: desc.layout.per_stage_map.vs.sizes_buffer, - sized_bindings: vs.sized_bindings, - vertex_buffer_mappings, - }; + // Setup mesh stage + { + let ms = self.load_shader( + mesh_stage, + &[], + desc.layout, + primitive_class, + naga::ShaderStage::Mesh, + )?; + descriptor.set_mesh_function(Some(&ms.function)); + if self.shared.private_caps.supports_mutability { + Self::set_buffers_mutability( + descriptor.mesh_buffers().unwrap(), + ms.immutable_buffer_mask, + ); + } + ms_info = Some(super::PipelineStageInfo { + push_constants: desc.layout.push_constants_infos.ms, + sizes_slot: desc.layout.per_stage_map.ms.sizes_buffer, + sized_bindings: ms.sized_bindings, + vertex_buffer_mappings: vec![], + library: Some(ms.library), + raw_wg_size: ms.wg_size, + work_group_memory_sizes: ms.wg_memory_sizes, + }); + } - (vs.library, info) + MetalGenericRenderPipelineDescriptor::Mesh(descriptor) + } + }; + + let raw_triangle_fill_mode = match desc.primitive.polygon_mode { + wgt::PolygonMode::Fill => MTLTriangleFillMode::Fill, + wgt::PolygonMode::Line => MTLTriangleFillMode::Lines, + wgt::PolygonMode::Point => panic!( + "{:?} is not enabled for this backend", + wgt::Features::POLYGON_MODE_POINT + ), }; // Fragment shader - let (fs_lib, fs_info) = match desc.fragment_stage { + let fs_info = match desc.fragment_stage { Some(ref stage) => { let fs = self.load_shader( stage, @@ -1220,14 +1397,15 @@ impl crate::Device for super::Device { ); } - let info = super::PipelineStageInfo { + Some(super::PipelineStageInfo { push_constants: desc.layout.push_constants_infos.fs, sizes_slot: desc.layout.per_stage_map.fs.sizes_buffer, sized_bindings: fs.sized_bindings, vertex_buffer_mappings: vec![], - }; - - (Some(fs.library), Some(info)) + library: Some(fs.library), + raw_wg_size: Default::default(), + work_group_memory_sizes: vec![], + }) } None => { // TODO: This is a workaround for what appears to be a Metal validation bug @@ -1235,10 +1413,11 @@ impl crate::Device for super::Device { if desc.color_targets.is_empty() && desc.depth_stencil.is_none() { descriptor.set_depth_attachment_pixel_format(MTLPixelFormat::Depth32Float); } - (None, None) + None } }; + // Setup pipeline color attachments for (i, ct) in desc.color_targets.iter().enumerate() { let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap(); let ct = if let Some(color_target) = ct.as_ref() { @@ -1267,6 +1446,7 @@ impl crate::Device for super::Device { } } + // Setup depth stencil state let depth_stencil = match desc.depth_stencil { Some(ref ds) => { let raw_format = self.shared.private_caps.map_format(ds.format); @@ -1289,94 +1469,54 @@ impl crate::Device for super::Device { None => None, }; - if desc.layout.total_counters.vs.buffers + (desc_vertex_buffers.len() as u32) - > self.shared.private_caps.max_vertex_buffers - { - let msg = format!( - "pipeline needs too many buffers in the vertex stage: {} vertex and {} layout", - desc_vertex_buffers.len(), - desc.layout.total_counters.vs.buffers - ); - return Err(crate::PipelineError::Linkage( - wgt::ShaderStages::VERTEX, - msg, - )); - } - - if !desc_vertex_buffers.is_empty() { - let vertex_descriptor = metal::VertexDescriptor::new(); - for (i, vb) in desc_vertex_buffers.iter().enumerate() { - let buffer_index = - self.shared.private_caps.max_vertex_buffers as u64 - 1 - i as u64; - let buffer_desc = vertex_descriptor.layouts().object_at(buffer_index).unwrap(); - - // Metal expects the stride to be the actual size of the attributes. - // The semantics of array_stride == 0 can be achieved by setting - // the step function to constant and rate to 0. - if vb.array_stride == 0 { - let stride = vb - .attributes - .iter() - .map(|attribute| attribute.offset + attribute.format.size()) - .max() - .unwrap_or(0); - buffer_desc.set_stride(wgt::math::align_to(stride, 4)); - buffer_desc.set_step_function(MTLVertexStepFunction::Constant); - buffer_desc.set_step_rate(0); - } else { - buffer_desc.set_stride(vb.array_stride); - buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode)); + // Setup multisample state + if desc.multisample.count != 1 { + //TODO: handle sample mask + match descriptor { + MetalGenericRenderPipelineDescriptor::Standard(ref inner) => { + inner.set_sample_count(desc.multisample.count as u64); } - - for at in vb.attributes { - let attribute_desc = vertex_descriptor - .attributes() - .object_at(at.shader_location as u64) - .unwrap(); - attribute_desc.set_format(conv::map_vertex_format(at.format)); - attribute_desc.set_buffer_index(buffer_index); - attribute_desc.set_offset(at.offset); + MetalGenericRenderPipelineDescriptor::Mesh(ref inner) => { + inner.set_raster_sample_count(desc.multisample.count as u64); } } - descriptor.set_vertex_descriptor(Some(vertex_descriptor)); - } - - if desc.multisample.count != 1 { - //TODO: handle sample mask - descriptor.set_sample_count(desc.multisample.count as u64); descriptor .set_alpha_to_coverage_enabled(desc.multisample.alpha_to_coverage_enabled); //descriptor.set_alpha_to_one_enabled(desc.multisample.alpha_to_one_enabled); } + // Set debug label if let Some(name) = desc.label { descriptor.set_label(name); } - if let Some(mv) = desc.multiview_mask { descriptor.set_max_vertex_amplification_count(mv.get().count_ones() as u64); } - let raw = self - .shared - .device - .lock() - .new_render_pipeline_state(&descriptor) - .map_err(|e| { - crate::PipelineError::Linkage( - wgt::ShaderStages::VERTEX | wgt::ShaderStages::FRAGMENT, - format!("new_render_pipeline_state: {e:?}"), - ) - })?; + // Create the pipeline from descriptor + let raw = match descriptor { + MetalGenericRenderPipelineDescriptor::Standard(d) => { + self.shared.device.lock().new_render_pipeline_state(&d) + } + MetalGenericRenderPipelineDescriptor::Mesh(d) => { + self.shared.device.lock().new_mesh_render_pipeline_state(&d) + } + } + .map_err(|e| { + crate::PipelineError::Linkage( + wgt::ShaderStages::VERTEX | wgt::ShaderStages::FRAGMENT, + format!("new_render_pipeline_state: {e:?}"), + ) + })?; self.counters.render_pipelines.add(1); Ok(super::RenderPipeline { raw, - vs_lib, - fs_lib, vs_info, fs_info, + ts_info, + ms_info, raw_primitive_type, raw_triangle_fill_mode, raw_front_winding: conv::map_winding(desc.primitive.front_face), @@ -1444,10 +1584,13 @@ impl crate::Device for super::Device { } let cs_info = super::PipelineStageInfo { + library: Some(cs.library), push_constants: desc.layout.push_constants_infos.cs, sizes_slot: desc.layout.per_stage_map.cs.sizes_buffer, sized_bindings: cs.sized_bindings, vertex_buffer_mappings: vec![], + raw_wg_size: cs.wg_size, + work_group_memory_sizes: cs.wg_memory_sizes, }; if let Some(name) = desc.label { @@ -1468,13 +1611,7 @@ impl crate::Device for super::Device { self.counters.compute_pipelines.add(1); - Ok(super::ComputePipeline { - raw, - cs_info, - cs_lib: cs.library, - work_group_size: cs.wg_size, - work_group_memory_sizes: cs.wg_memory_sizes, - }) + Ok(super::ComputePipeline { raw, cs_info }) }) } diff --git a/third_party/rust/wgpu-hal/src/metal/mod.rs b/third_party/rust/wgpu-hal/src/metal/mod.rs @@ -302,6 +302,7 @@ struct PrivateCapabilities { int64_atomics: bool, float_atomics: bool, supports_shared_event: bool, + mesh_shaders: bool, supported_vertex_amplification_factor: u32, shader_barycentrics: bool, supports_memoryless_storage: bool, @@ -609,12 +610,16 @@ struct MultiStageData<T> { vs: T, fs: T, cs: T, + ts: T, + ms: T, } const NAGA_STAGES: MultiStageData<naga::ShaderStage> = MultiStageData { vs: naga::ShaderStage::Vertex, fs: naga::ShaderStage::Fragment, cs: naga::ShaderStage::Compute, + ts: naga::ShaderStage::Task, + ms: naga::ShaderStage::Mesh, }; impl<T> ops::Index<naga::ShaderStage> for MultiStageData<T> { @@ -624,7 +629,8 @@ impl<T> ops::Index<naga::ShaderStage> for MultiStageData<T> { naga::ShaderStage::Vertex => &self.vs, naga::ShaderStage::Fragment => &self.fs, naga::ShaderStage::Compute => &self.cs, - naga::ShaderStage::Task | naga::ShaderStage::Mesh => unreachable!(), + naga::ShaderStage::Task => &self.ts, + naga::ShaderStage::Mesh => &self.ms, } } } @@ -635,6 +641,8 @@ impl<T> MultiStageData<T> { vs: fun(&self.vs), fs: fun(&self.fs), cs: fun(&self.cs), + ts: fun(&self.ts), + ms: fun(&self.ms), } } fn map<Y>(self, fun: impl Fn(T) -> Y) -> MultiStageData<Y> { @@ -642,17 +650,23 @@ impl<T> MultiStageData<T> { vs: fun(self.vs), fs: fun(self.fs), cs: fun(self.cs), + ts: fun(self.ts), + ms: fun(self.ms), } } fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> { iter::once(&self.vs) .chain(iter::once(&self.fs)) .chain(iter::once(&self.cs)) + .chain(iter::once(&self.ts)) + .chain(iter::once(&self.ms)) } fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> { iter::once(&mut self.vs) .chain(iter::once(&mut self.fs)) .chain(iter::once(&mut self.cs)) + .chain(iter::once(&mut self.ts)) + .chain(iter::once(&mut self.ms)) } } @@ -816,6 +830,8 @@ impl crate::DynShaderModule for ShaderModule {} #[derive(Debug, Default)] struct PipelineStageInfo { + #[allow(dead_code)] + library: Option<metal::Library>, push_constants: Option<PushConstantsInfo>, /// The buffer argument table index at which we pass runtime-sized arrays' buffer sizes. @@ -830,6 +846,12 @@ struct PipelineStageInfo { /// Info on all bound vertex buffers. vertex_buffer_mappings: Vec<naga::back::msl::VertexBufferMapping>, + + /// The workgroup size for compute, task or mesh stages + raw_wg_size: MTLSize, + + /// The workgroup memory sizes for compute task or mesh stages + work_group_memory_sizes: Vec<u32>, } impl PipelineStageInfo { @@ -838,6 +860,9 @@ impl PipelineStageInfo { self.sizes_slot = None; self.sized_bindings.clear(); self.vertex_buffer_mappings.clear(); + self.library = None; + self.work_group_memory_sizes.clear(); + self.raw_wg_size = Default::default(); } fn assign_from(&mut self, other: &Self) { @@ -848,18 +873,21 @@ impl PipelineStageInfo { self.vertex_buffer_mappings.clear(); self.vertex_buffer_mappings .extend_from_slice(&other.vertex_buffer_mappings); + self.library = Some(other.library.as_ref().unwrap().clone()); + self.raw_wg_size = other.raw_wg_size; + self.work_group_memory_sizes.clear(); + self.work_group_memory_sizes + .extend_from_slice(&other.work_group_memory_sizes); } } #[derive(Debug)] pub struct RenderPipeline { raw: metal::RenderPipelineState, - #[allow(dead_code)] - vs_lib: metal::Library, - #[allow(dead_code)] - fs_lib: Option<metal::Library>, - vs_info: PipelineStageInfo, + vs_info: Option<PipelineStageInfo>, fs_info: Option<PipelineStageInfo>, + ts_info: Option<PipelineStageInfo>, + ms_info: Option<PipelineStageInfo>, raw_primitive_type: MTLPrimitiveType, raw_triangle_fill_mode: MTLTriangleFillMode, raw_front_winding: MTLWinding, @@ -876,11 +904,7 @@ impl crate::DynRenderPipeline for RenderPipeline {} #[derive(Debug)] pub struct ComputePipeline { raw: metal::ComputePipelineState, - #[allow(dead_code)] - cs_lib: metal::Library, cs_info: PipelineStageInfo, - work_group_size: MTLSize, - work_group_memory_sizes: Vec<u32>, } unsafe impl Send for ComputePipeline {} @@ -954,7 +978,6 @@ struct CommandState { compute: Option<metal::ComputeCommandEncoder>, raw_primitive_type: MTLPrimitiveType, index: Option<IndexState>, - raw_wg_size: MTLSize, stage_infos: MultiStageData<PipelineStageInfo>, /// Sizes of currently bound [`wgt::BufferBindingType::Storage`] buffers. @@ -980,7 +1003,6 @@ struct CommandState { vertex_buffer_size_map: FastHashMap<u64, wgt::BufferSize>, - work_group_memory_sizes: Vec<u32>, push_constants: Vec<u32>, /// Timer query that should be executed when the next pass starts. diff --git a/third_party/rust/wgpu-hal/src/vulkan/adapter.rs b/third_party/rust/wgpu-hal/src/vulkan/adapter.rs @@ -917,6 +917,10 @@ impl PhysicalDeviceFeatures { F::EXPERIMENTAL_MESH_SHADER, caps.supports_extension(ext::mesh_shader::NAME), ); + features.set( + F::EXPERIMENTAL_MESH_SHADER_POINTS, + caps.supports_extension(ext::mesh_shader::NAME), + ); if let Some(ref mesh_shader) = self.mesh_shader { features.set( F::EXPERIMENTAL_MESH_SHADER_MULTIVIEW, @@ -2215,6 +2219,12 @@ impl super::Adapter { // But this requires cloning the `spv::Options` struct, which has heap allocations. true, // could check `super::Workarounds::SEPARATE_ENTRY_POINTS` ); + flags.set( + spv::WriterFlags::PRINT_ON_RAY_QUERY_INITIALIZATION_FAIL, + self.instance.flags.contains(wgt::InstanceFlags::DEBUG) + && (self.instance.instance_api_version >= vk::API_VERSION_1_3 + || enabled_extensions.contains(&khr::shader_non_semantic_info::NAME)), + ); if features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY) { capabilities.push(spv::Capability::RayQueryKHR); } @@ -2273,6 +2283,7 @@ impl super::Adapter { spv::ZeroInitializeWorkgroupMemoryMode::Polyfill }, force_loop_bounding: true, + ray_query_initialization_tracking: true, use_storage_input_output_16: features.contains(wgt::Features::SHADER_F16) && self.phd_features.supports_storage_input_output_16(), fake_missing_bindings: false, diff --git a/third_party/rust/wgpu-hal/src/vulkan/device.rs b/third_party/rust/wgpu-hal/src/vulkan/device.rs @@ -488,11 +488,14 @@ impl super::Device { /// - If `drop_callback` is [`None`], wgpu-hal will take ownership of `vk_image`. If /// `drop_callback` is [`Some`], `vk_image` must be valid until the callback is called. /// - If the `ImageCreateFlags` does not contain `MUTABLE_FORMAT`, the `view_formats` of `desc` must be empty. + /// - If `external_memory` is [`Some`], wgpu-hal will take ownership of the memory (which is presumed to back + /// `vk_image`). If `external_memory` is [`None`], the memory must be valid until `drop_callback` is called. pub unsafe fn texture_from_raw( &self, vk_image: vk::Image, desc: &crate::TextureDescriptor, drop_callback: Option<crate::DropCallback>, + external_memory: Option<vk::DeviceMemory>, ) -> super::Texture { let mut raw_flags = vk::ImageCreateFlags::empty(); let mut view_formats = vec![]; @@ -518,7 +521,7 @@ impl super::Device { super::Texture { raw: vk_image, drop_guard, - external_memory: None, + external_memory, block: None, format: desc.format, copy_size: desc.copy_extent(), @@ -759,6 +762,7 @@ impl super::Device { }; let needs_temp_options = !runtime_checks.bounds_checks || !runtime_checks.force_loop_bounding + || !runtime_checks.ray_query_initialization_tracking || !binding_map.is_empty() || naga_shader.debug_source.is_some() || !stage.zero_initialize_workgroup_memory; @@ -776,6 +780,9 @@ impl super::Device { if !runtime_checks.force_loop_bounding { temp_options.force_loop_bounding = false; } + if !runtime_checks.ray_query_initialization_tracking { + temp_options.ray_query_initialization_tracking = false; + } if !binding_map.is_empty() { temp_options.binding_map = binding_map.clone(); } diff --git a/third_party/rust/wgpu-types/.cargo-checksum.json b/third_party/rust/wgpu-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"7294fed45f6bf1bfbb8a32daf982744671a76cd966a67a610c95c06ac135547e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"1cae2f153a7e4e4e8f3d4cc8ead3635a9a7486d676729f0d7cbba3a6e91ce448","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"5e2dd2e2214265f69226b302bcf9192592a79ca9682653153e01e8efadca301d","src/instance.rs":"deeb5ca694163baf46c386316a498cee011cf960d48b749d4cd01125e9fca57f","src/lib.rs":"af43db13921d181e441d4b414ca90fd20c29ca9c2e44c44f090c09fe5149e2b5","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/tokens.rs":"cdf192e0c9b4ea4f3cd4148d07be2e895f937f8154acbf52caf67f7fb4df11dc","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"7294fed45f6bf1bfbb8a32daf982744671a76cd966a67a610c95c06ac135547e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"1cae2f153a7e4e4e8f3d4cc8ead3635a9a7486d676729f0d7cbba3a6e91ce448","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"44591ecd078fd63fea93f1946472a5ab5d50ca0a54b6804afa50afbc0da5634a","src/instance.rs":"deeb5ca694163baf46c386316a498cee011cf960d48b749d4cd01125e9fca57f","src/lib.rs":"c518ebb506b820b8fb771f619b06fbc99bf3672b2c34a2355b726ffc97d03712","src/math.rs":"916d78724b50ed6e9f84240e0aa19b0afc886e21a1b18428ca6ace5a1e6cc80c","src/tokens.rs":"cdf192e0c9b4ea4f3cd4148d07be2e895f937f8154acbf52caf67f7fb4df11dc","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/wgpu-types/src/features.rs b/third_party/rust/wgpu-types/src/features.rs @@ -920,10 +920,9 @@ bitflags_array! { /// Supported platforms: /// - Vulkan /// - Metal + /// - DX12 /// - OpenGL (web only) /// - /// DX12 support is a WIP. - /// /// This is a native only feature. const MULTIVIEW = 1 << 26; /// Enables using 64-bit types for vertex attributes. @@ -1169,12 +1168,11 @@ bitflags_array! { /// This is a native only feature. const UNIFORM_BUFFER_BINDING_ARRAYS = 1 << 47; - /// Enables mesh shaders and task shaders in mesh shader pipelines. + /// Enables mesh shaders and task shaders in mesh shader pipelines. This extension does NOT imply support for + /// compiling mesh shaders at runtime. Rather, the user must use custom passthrough shaders. /// /// Supported platforms: /// - Vulkan (with [VK_EXT_mesh_shader](https://registry.khronos.org/vulkan/specs/latest/man/html/VK_EXT_mesh_shader.html)) - /// - /// Potential Platforms: /// - DX12 /// - Metal /// @@ -1250,11 +1248,21 @@ bitflags_array! { /// /// Supported platforms /// - Vulkan + /// - DX12 /// - /// DX12 will support this when it supports multiview in general. /// /// While metal supports this in theory, the behavior of `view_index` differs from vulkan and dx12 so the feature isn't exposed. const SELECTIVE_MULTIVIEW = 1 << 54; + + /// Enables the use of point-primitive outputs from mesh shaders. Making use of this feature also requires enabling + /// `Features::EXPERIMENTAL_MESH_SHADER`. + /// + /// Supported platforms + /// - Vulkan + /// - Metal + /// + /// This is a native only feature. + const EXPERIMENTAL_MESH_SHADER_POINTS = 1 << 55; } /// Features that are not guaranteed to be supported. @@ -1532,6 +1540,7 @@ impl Features { Self::from_bits_truncate(FeatureBits([ FeaturesWGPU::EXPERIMENTAL_MESH_SHADER.bits() | FeaturesWGPU::EXPERIMENTAL_MESH_SHADER_MULTIVIEW.bits() + | FeaturesWGPU::EXPERIMENTAL_MESH_SHADER_POINTS.bits() | FeaturesWGPU::EXPERIMENTAL_RAY_QUERY.bits() | FeaturesWGPU::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN.bits() | FeaturesWGPU::EXPERIMENTAL_PASSTHROUGH_SHADERS.bits(), diff --git a/third_party/rust/wgpu-types/src/lib.rs b/third_party/rust/wgpu-types/src/lib.rs @@ -685,6 +685,11 @@ pub struct Limits { pub max_push_constant_size: u32, /// Maximum number of live non-sampler bindings. /// + /// <div class="warning"> + /// The default value is **1_000_000**, On systems with integrated GPUs (iGPUs)—particularly on Windows using the D3D12 + /// backend—this can lead to significant system RAM consumption since iGPUs share system memory directly with the CPU. + /// </div> + /// /// This limit only affects the d3d12 backend. Using a large number will allow the device /// to create many bind groups at the cost of a large up-front allocation at device creation. pub max_non_sampler_bindings: u32, @@ -1057,14 +1062,12 @@ impl Limits { #[must_use] pub const fn using_recommended_minimum_mesh_shader_values(self) -> Self { Self { - // Literally just made this up as 256^2 or 2^16. - // My GPU supports 2^22, and compute shaders don't have this kind of limit. - // This very likely is never a real limiter - max_task_workgroup_total_count: 65536, - max_task_workgroups_per_dimension: 256, + // This is a common limit for apple devices. It's not immediately clear why. + max_task_workgroup_total_count: 1024, + max_task_workgroups_per_dimension: 1024, // llvmpipe reports 0 multiview count, which just means no multiview is allowed max_mesh_multiview_view_count: 0, - // llvmpipe once again requires this to be 8. An RTX 3060 supports well over 1024. + // llvmpipe once again requires this to be <=8. An RTX 3060 supports well over 1024. max_mesh_output_layers: 8, ..self } @@ -7972,6 +7975,20 @@ pub struct ShaderRuntimeChecks { /// conclusions about other safety-critical code paths. This option SHOULD NOT be disabled /// when running untrusted code. pub force_loop_bounding: bool, + /// If false, the caller **MUST** ensure that in all passed shaders every function operating + /// on a ray query must obey these rules (functions using wgsl naming) + /// - `rayQueryInitialize` must have called before `rayQueryProceed` + /// - `rayQueryProceed` must have been called, returned true and have hit an AABB before + /// `rayQueryGenerateIntersection` is called + /// - `rayQueryProceed` must have been called, returned true and have hit a triangle before + /// `rayQueryConfirmIntersection` is called + /// - `rayQueryProceed` must have been called and have returned true before `rayQueryTerminate`, + /// `getCandidateHitVertexPositions` or `rayQueryGetCandidateIntersection` is called + /// - `rayQueryProceed` must have been called and have returned false before `rayQueryGetCommittedIntersection` + /// or `getCommittedHitVertexPositions` are called + /// + /// It is the aim that these cases will not cause UB if this is set to true, but currently this will still happen on DX12 and Metal. + pub ray_query_initialization_tracking: bool, } impl ShaderRuntimeChecks { @@ -8004,6 +8021,7 @@ impl ShaderRuntimeChecks { Self { bounds_checks: all_checks, force_loop_bounding: all_checks, + ray_query_initialization_tracking: all_checks, } } } diff --git a/third_party/rust/wgpu-types/src/math.rs b/third_party/rust/wgpu-types/src/math.rs @@ -1,4 +1,4 @@ -//! Utilitary math functions. +//! Utility math functions. use core::ops::{Add, Rem, Sub};