tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a863ad4896939a1fbf3432d6b215a43083346313
parent 9e6415c587b3801c02ab2b1c2a4da04d0e179d1c
Author: Andy Leiserson <aleiserson@mozilla.com>
Date:   Sun, 16 Nov 2025 01:31:28 +0000

Bug 1998052: Update wgpu to upstream 3e8a11c6 (2025-11-06) r=webgpu-reviewers,supply-chain-reviewers,ErichDonGubler

Differential Revision: https://phabricator.services.mozilla.com/D271449

Diffstat:
M.cargo/config.toml.in | 4++--
MCargo.lock | 29+++++++++++++++++++++++------
Mgfx/wgpu_bindings/Cargo.toml | 12++++++------
Mgfx/wgpu_bindings/moz.yaml | 4++--
Mgfx/wgpu_bindings/src/client.rs | 6+++---
Mgfx/wgpu_bindings/src/client/render_pass.rs | 4+++-
Mgfx/wgpu_bindings/src/command.rs | 7++++---
Mgfx/wgpu_bindings/src/lib.rs | 2+-
Mgfx/wgpu_bindings/src/server.rs | 43+++++++++++++------------------------------
Msupply-chain/audits.toml | 22++++++++++++++++------
Mtesting/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_pass_encoder/cts.https.html.ini | 8--------
Mtesting/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_common/cts.https.html.ini | 172++++++++++++++++++++++---------------------------------------------------------
Mtesting/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_misc/cts.https.html.ini | 12------------
Athird_party/rust/macro_rules_attribute-proc_macro/.cargo-checksum.json | 2++
Athird_party/rust/macro_rules_attribute-proc_macro/Cargo.toml | 28++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute-proc_macro/LICENSE-APACHE | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute-proc_macro/LICENSE-MIT | 21+++++++++++++++++++++
Athird_party/rust/macro_rules_attribute-proc_macro/LICENSE-ZLIB | 19+++++++++++++++++++
Athird_party/rust/macro_rules_attribute-proc_macro/mod.rs | 304+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/.cargo-checksum.json | 2++
Athird_party/rust/macro_rules_attribute/Cargo.toml | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/LICENSE-APACHE | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/LICENSE-MIT | 21+++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/LICENSE-ZLIB | 19+++++++++++++++++++
Athird_party/rust/macro_rules_attribute/README.md | 434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/fix-docsrs-li-details-summary.html | 5+++++
Athird_party/rust/macro_rules_attribute/rust-toolchain.toml | 3+++
Athird_party/rust/macro_rules_attribute/src/lib.rs | 568+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/tests/custom_derive.rs | 20++++++++++++++++++++
Athird_party/rust/macro_rules_attribute/tests/inert_derive_helpers.rs | 14++++++++++++++
Mthird_party/rust/naga/.cargo-checksum.json | 4++--
Mthird_party/rust/naga/src/back/dot/mod.rs | 19+++++++++++++++++++
Mthird_party/rust/naga/src/back/glsl/features.rs | 14++++++++++++++
Mthird_party/rust/naga/src/back/glsl/mod.rs | 35+++++++++++++++++++++++++++++++----
Mthird_party/rust/naga/src/back/hlsl/conv.rs | 7++++++-
Mthird_party/rust/naga/src/back/hlsl/mod.rs | 2++
Mthird_party/rust/naga/src/back/hlsl/writer.rs | 29++++++++++++++++++++++++++---
Mthird_party/rust/naga/src/back/mod.rs | 6+++---
Mthird_party/rust/naga/src/back/msl/mod.rs | 24+++++++++++++++++++++---
Mthird_party/rust/naga/src/back/msl/writer.rs | 20+++++++++++++++++---
Mthird_party/rust/naga/src/back/pipeline_constants.rs | 45+++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/naga/src/back/spv/block.rs | 2++
Mthird_party/rust/naga/src/back/spv/helpers.rs | 10+++++-----
Mthird_party/rust/naga/src/back/spv/writer.rs | 19++++++++++++++++++-
Mthird_party/rust/naga/src/back/wgsl/writer.rs | 5++++-
Mthird_party/rust/naga/src/common/wgsl/to_wgsl.rs | 9++++++++-
Mthird_party/rust/naga/src/compact/mod.rs | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/naga/src/compact/statements.rs | 34++++++++++++++++++++++++++++++++++
Mthird_party/rust/naga/src/front/glsl/functions.rs | 4++++
Mthird_party/rust/naga/src/front/glsl/mod.rs | 2+-
Mthird_party/rust/naga/src/front/glsl/variables.rs | 2++
Mthird_party/rust/naga/src/front/interpolator.rs | 1+
Mthird_party/rust/naga/src/front/spv/convert.rs | 1+
Mthird_party/rust/naga/src/front/spv/function.rs | 2++
Mthird_party/rust/naga/src/front/spv/mod.rs | 9+++++++++
Mthird_party/rust/naga/src/front/wgsl/lower/mod.rs | 3+++
Mthird_party/rust/naga/src/front/wgsl/parse/conv.rs | 1+
Mthird_party/rust/naga/src/ir/mod.rs | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mthird_party/rust/naga/src/proc/mod.rs | 12++++++++++++
Mthird_party/rust/naga/src/proc/terminator.rs | 1+
Mthird_party/rust/naga/src/valid/analyzer.rs | 142++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mthird_party/rust/naga/src/valid/function.rs | 43+++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/naga/src/valid/handles.rs | 30++++++++++++++++++++++++++++++
Mthird_party/rust/naga/src/valid/interface.rs | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mthird_party/rust/naga/src/valid/mod.rs | 6++++++
Mthird_party/rust/naga/src/valid/type.rs | 9++++++---
Mthird_party/rust/wgpu-core/.cargo-checksum.json | 4++--
Mthird_party/rust/wgpu-core/Cargo.toml | 6++++++
Mthird_party/rust/wgpu-core/src/binding_model.rs | 3++-
Mthird_party/rust/wgpu-core/src/command/bundle.rs | 136+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mthird_party/rust/wgpu-core/src/command/clear.rs | 17+----------------
Mthird_party/rust/wgpu-core/src/command/compute.rs | 67-------------------------------------------------------------------
Mthird_party/rust/wgpu-core/src/command/compute_command.rs | 218++++++-------------------------------------------------------------------------
Mthird_party/rust/wgpu-core/src/command/draw.rs | 7+++++++
Mthird_party/rust/wgpu-core/src/command/encoder_command.rs | 221+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mthird_party/rust/wgpu-core/src/command/ffi.rs | 4+++-
Mthird_party/rust/wgpu-core/src/command/mod.rs | 131+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mthird_party/rust/wgpu-core/src/command/query.rs | 21---------------------
Mthird_party/rust/wgpu-core/src/command/ray_tracing.rs | 105+++++++++++++++----------------------------------------------------------------
Mthird_party/rust/wgpu-core/src/command/render.rs | 231+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mthird_party/rust/wgpu-core/src/command/render_command.rs | 449+++++--------------------------------------------------------------------------
Mthird_party/rust/wgpu-core/src/command/transfer.rs | 42+-----------------------------------------
Mthird_party/rust/wgpu-core/src/conv.rs | 7++++++-
Mthird_party/rust/wgpu-core/src/device/global.rs | 856++++++++++++++++++++++---------------------------------------------------------
Mthird_party/rust/wgpu-core/src/device/mod.rs | 12++++++++----
Mthird_party/rust/wgpu-core/src/device/queue.rs | 29++++++++++++++---------------
Mthird_party/rust/wgpu-core/src/device/ray_tracing.rs | 41++++++++++++++++++++++-------------------
Mthird_party/rust/wgpu-core/src/device/resource.rs | 495++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mthird_party/rust/wgpu-core/src/device/trace.rs | 234++++++++++++++++++++++++++++++++++---------------------------------------------
Athird_party/rust/wgpu-core/src/device/trace/record.rs | 760+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/wgpu-core/src/id.rs | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mthird_party/rust/wgpu-core/src/pipeline.rs | 33+++++++++++++++++++++++++--------
Mthird_party/rust/wgpu-core/src/present.rs | 16+++++++++-------
Mthird_party/rust/wgpu-core/src/ray_tracing.rs | 98++++++++++++++++++++++++++++++++-----------------------------------------------
Mthird_party/rust/wgpu-core/src/registry.rs | 5-----
Mthird_party/rust/wgpu-core/src/resource.rs | 97++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mthird_party/rust/wgpu-core/src/storage.rs | 4+++-
Mthird_party/rust/wgpu-core/src/validation.rs | 4+++-
Mthird_party/rust/wgpu-hal/.cargo-checksum.json | 4++--
Mthird_party/rust/wgpu-hal/Cargo.toml | 1+
Mthird_party/rust/wgpu-hal/examples/halmark/main.rs | 4++--
Mthird_party/rust/wgpu-hal/examples/raw-gles.rs | 2+-
Mthird_party/rust/wgpu-hal/src/dx12/adapter.rs | 50++++++++++++++++++++++++++++++++++++++++++++++----
Mthird_party/rust/wgpu-hal/src/dx12/command.rs | 8++++++++
Mthird_party/rust/wgpu-hal/src/dynamic/command.rs | 2+-
Mthird_party/rust/wgpu-hal/src/dynamic/device.rs | 2+-
Mthird_party/rust/wgpu-hal/src/gles/adapter.rs | 4+++-
Mthird_party/rust/wgpu-hal/src/gles/device.rs | 19+++++++++++--------
Mthird_party/rust/wgpu-hal/src/lib.rs | 4++--
Mthird_party/rust/wgpu-hal/src/metal/adapter.rs | 29+++++++++++++++++++++++++++--
Mthird_party/rust/wgpu-hal/src/metal/command.rs | 27++++++++++++++++++++++++++-
Mthird_party/rust/wgpu-hal/src/metal/device.rs | 4++++
Mthird_party/rust/wgpu-hal/src/metal/mod.rs | 2++
Mthird_party/rust/wgpu-hal/src/noop/mod.rs | 10++++++----
Mthird_party/rust/wgpu-hal/src/vulkan/adapter.rs | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mthird_party/rust/wgpu-hal/src/vulkan/command.rs | 30++++++++++++++----------------
Mthird_party/rust/wgpu-hal/src/vulkan/device.rs | 26++++++++++++--------------
Mthird_party/rust/wgpu-hal/src/vulkan/mod.rs | 18++++++++++++++++--
Mthird_party/rust/wgpu-types/.cargo-checksum.json | 4++--
Mthird_party/rust/wgpu-types/src/features.rs | 26+++++++++++++++++++++++++-
Mthird_party/rust/wgpu-types/src/lib.rs | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
121 files changed, 5829 insertions(+), 2458 deletions(-)

diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in @@ -40,9 +40,9 @@ git = "https://github.com/franziskuskiefer/cose-rust" rev = "43c22248d136c8b38fe42ea709d08da6355cf04b" replace-with = "vendored-sources" -[source."git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13"] +[source."git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6"] git = "https://github.com/gfx-rs/wgpu" -rev = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" replace-with = "vendored-sources" [source."git+https://github.com/glandium/allocator-api2?rev=ad5f3d56a5a4519eff52af4ff85293431466ef5c"] diff --git a/Cargo.lock b/Cargo.lock @@ -3993,6 +3993,22 @@ dependencies = [ ] [[package]] +name = "macro_rules_attribute" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" + +[[package]] name = "malloc_buf" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4758,7 +4774,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" [[package]] name = "naga" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" dependencies = [ "arrayvec", "bit-set", @@ -7940,7 +7956,7 @@ dependencies = [ [[package]] name = "wgpu-core" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" dependencies = [ "arrayvec", "bit-set", @@ -7952,6 +7968,7 @@ dependencies = [ "hashbrown 0.16.0", "indexmap", "log", + "macro_rules_attribute", "naga", "once_cell", "parking_lot", @@ -7970,7 +7987,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" dependencies = [ "wgpu-hal", ] @@ -7978,7 +7995,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-windows-linux-android" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" dependencies = [ "wgpu-hal", ] @@ -7986,7 +8003,7 @@ dependencies = [ [[package]] name = "wgpu-hal" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" dependencies = [ "android_system_properties", "arrayvec", @@ -8024,7 +8041,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=a441382328c5163466fae06802737ef1df8d1f13#a441382328c5163466fae06802737ef1df8d1f13" +source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" 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 = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" 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 = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" 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 = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" 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 = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "a441382328c5163466fae06802737ef1df8d1f13" +rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" 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: a441382328c5163466fae06802737ef1df8d1f13 (2025-11-13T20:50:18Z). - revision: a441382328c5163466fae06802737ef1df8d1f13 + release: 3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6 (2025-11-15T22:26:27Z). + revision: 3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6 license: ['MIT', 'Apache-2.0'] updatebot: diff --git a/gfx/wgpu_bindings/src/client.rs b/gfx/wgpu_bindings/src/client.rs @@ -1200,7 +1200,7 @@ pub extern "C" fn wgpu_device_create_render_bundle_encoder( sample_count: desc.sample_count, multiview: None, }; - match wgc::command::RenderBundleEncoder::new(&descriptor, device_id, None) { + match wgc::command::RenderBundleEncoder::new(&descriptor, device_id) { Ok(encoder) => Box::into_raw(Box::new(encoder)), Err(e) => { let message = format!("Error in `Device::create_render_bundle_encoder`: {}", e); @@ -1668,7 +1668,7 @@ pub unsafe extern "C" fn wgpu_client_create_render_pipeline( primitive: desc.primitive.to_wgpu(), depth_stencil: desc.depth_stencil.cloned(), multisample: desc.multisample.clone(), - multiview: None, + multiview_mask: None, cache: None, }; @@ -1833,7 +1833,7 @@ pub unsafe extern "C" fn wgpu_command_encoder_resolve_query_set( destination_offset: wgt::BufferAddress, ) { let action = CommandEncoderAction::ResolveQuerySet { - query_set_id, + query_set: query_set_id, start_query, query_count, destination, diff --git a/gfx/wgpu_bindings/src/client/render_pass.rs b/gfx/wgpu_bindings/src/client/render_pass.rs @@ -73,7 +73,9 @@ pub struct RenderPassDepthStencilAttachment { } impl RenderPassDepthStencilAttachment { - pub(crate) fn to_wgpu(self) -> wgc::command::RenderPassDepthStencilAttachment { + pub(crate) fn to_wgpu( + self, + ) -> wgc::command::RenderPassDepthStencilAttachment<id::TextureViewId> { let Self { view, depth, diff --git a/gfx/wgpu_bindings/src/command.rs b/gfx/wgpu_bindings/src/command.rs @@ -9,7 +9,7 @@ use wgc::{ ComputePassDescriptor, PassTimestampWrites, RenderPassColorAttachment, RenderPassDepthStencilAttachment, }, - id::CommandEncoderId, + id::{CommandEncoderId, TextureViewId}, }; use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat}; @@ -51,7 +51,7 @@ pub struct Pass<C> { pub struct RecordedRenderPass { base: Pass<RenderCommand>, color_attachments: Vec<Option<RenderPassColorAttachment>>, - depth_stencil_attachment: Option<RenderPassDepthStencilAttachment>, + depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<TextureViewId>>, timestamp_writes: Option<PassTimestampWrites>, occlusion_query_set_id: Option<id::QuerySetId>, } @@ -60,7 +60,7 @@ impl RecordedRenderPass { pub fn new( label: Option<String>, color_attachments: Vec<Option<RenderPassColorAttachment>>, - depth_stencil_attachment: Option<RenderPassDepthStencilAttachment>, + depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<TextureViewId>>, timestamp_writes: Option<PassTimestampWrites>, occlusion_query_set_id: Option<id::QuerySetId>, ) -> Self { @@ -717,6 +717,7 @@ pub fn replay_render_pass( depth_stencil_attachment: src_pass.depth_stencil_attachment.as_ref(), timestamp_writes: src_pass.timestamp_writes.as_ref(), occlusion_query_set: src_pass.occlusion_query_set_id, + multiview_mask: None, }, ); if let Some(err) = err { diff --git a/gfx/wgpu_bindings/src/lib.rs b/gfx/wgpu_bindings/src/lib.rs @@ -10,7 +10,7 @@ pub mod command; pub mod error; pub mod server; -pub use wgc::command::Command as CommandEncoderAction; +pub use wgc::command::ffi::Command as CommandEncoderAction; use std::marker::PhantomData; use std::{borrow::Cow, mem, slice}; diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs @@ -2424,26 +2424,19 @@ impl Global { error_buf.init(err, device_id); } } - CommandEncoderAction::RunComputePass { - base, - timestamp_writes, - } => self.compute_pass_end_with_unresolved_commands( - self_id, - base, - timestamp_writes.as_ref(), - ), + CommandEncoderAction::RunComputePass { .. } => unimplemented!(), CommandEncoderAction::WriteTimestamp { - query_set_id, + query_set, query_index, } => { if let Err(err) = - self.command_encoder_write_timestamp(self_id, query_set_id, query_index) + self.command_encoder_write_timestamp(self_id, query_set, query_index) { error_buf.init(err, device_id); } } CommandEncoderAction::ResolveQuerySet { - query_set_id, + query_set, start_query, query_count, destination, @@ -2451,7 +2444,7 @@ impl Global { } => { if let Err(err) = self.command_encoder_resolve_query_set( self_id, - query_set_id, + query_set, start_query, query_count, destination, @@ -2460,20 +2453,7 @@ impl Global { error_buf.init(err, device_id); } } - CommandEncoderAction::RunRenderPass { - base, - target_colors, - target_depth_stencil, - timestamp_writes, - occlusion_query_set_id, - } => self.render_pass_end_with_unresolved_commands( - self_id, - base, - &target_colors, - target_depth_stencil.as_ref(), - timestamp_writes.as_ref(), - occlusion_query_set_id, - ), + CommandEncoderAction::RunRenderPass { .. } => unimplemented!(), CommandEncoderAction::ClearBuffer { dst, offset, size } => { if let Err(err) = self.command_encoder_clear_buffer(self_id, dst, offset, size) { error_buf.init(err, device_id); @@ -2507,6 +2487,9 @@ impl Global { CommandEncoderAction::BuildAccelerationStructures { .. } => { unreachable!("internal error: attempted to build acceleration structures") } + CommandEncoderAction::TransitionResources { .. } => { + unreachable!("internal error: attempted to transition resources") + } } } } @@ -2739,9 +2722,9 @@ unsafe fn process_message( global.command_encoder_action(device_id, id, action, error_buf) } Message::CommandEncoderFinish(device_id, command_encoder_id, command_buffer_id, desc) => { - let (_, error) = + let (_, label_and_error) = global.command_encoder_finish(command_encoder_id, &desc, Some(command_buffer_id)); - if let Some(err) = error { + if let Some((_label, err)) = label_and_error { error_buf.init(err, device_id); } } @@ -2991,9 +2974,9 @@ pub extern "C" fn wgpu_server_encoder_finish( ) { let label = wgpu_string(desc.label); let desc = desc.map_label(|_| label); - let (_, error) = + let (_, label_and_error) = global.command_encoder_finish(command_encoder_id, &desc, Some(command_buffer_id)); - if let Some(err) = error { + if let Some((_label, err)) = label_and_error { error_buf.init(err, device_id); } } diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml @@ -3801,6 +3801,16 @@ who = "Gabriele Svelto <gsvelto@mozilla.com>" criteria = "safe-to-deploy" version = "0.4.1" +[[audits.macro_rules_attribute]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +version = "0.2.2" + +[[audits.macro_rules_attribute-proc_macro]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +version = "0.2.2" + [[audits.malloc_buf]] who = "Bobby Holley <bobbyholley@gmail.com>" criteria = "safe-to-deploy" @@ -4355,7 +4365,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.net2]] @@ -6922,7 +6932,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.wgpu-core-deps-apple]] @@ -6953,7 +6963,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.wgpu-core-deps-windows-linux-android]] @@ -6984,7 +6994,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.wgpu-hal]] @@ -7093,7 +7103,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.wgpu-types]] @@ -7197,7 +7207,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:a441382328c5163466fae06802737ef1df8d1f13" +delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" importable = false [[audits.whatsys]] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_pass_encoder/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_pass_encoder/cts.https.html.ini @@ -1,5 +1,4 @@ [cts.https.html?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:bindings_in_bundle:*] - implementation-status: backlog [:type0="multisampled-texture";type1="multisampled-texture"] [:type0="multisampled-texture";type1="render-target"] @@ -11,7 +10,6 @@ [:type0="readonly-storage-texture";type1="render-target"] [:type0="readonly-storage-texture";type1="sampled-texture"] - expected: FAIL [:type0="readonly-storage-texture";type1="writeonly-storage-texture"] @@ -36,7 +34,6 @@ [:type0="render-target";type1="writeonly-storage-texture"] [:type0="sampled-texture";type1="readonly-storage-texture"] - expected: FAIL [:type0="sampled-texture";type1="readwrite-storage-texture"] @@ -58,9 +55,7 @@ [cts.https.html?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:replaced_binding:*] - implementation-status: backlog [:compute=false;callDrawOrDispatch=false;entry={"storageTexture":{"access":"read-only","format":"r32float"}}] - expected: FAIL [:compute=false;callDrawOrDispatch=false;entry={"storageTexture":{"access":"read-write","format":"r32float"}}] @@ -69,7 +64,6 @@ [:compute=false;callDrawOrDispatch=false;entry={"texture":{"sampleType":"unfilterable-float"}}] [:compute=false;callDrawOrDispatch=true;entry={"storageTexture":{"access":"read-only","format":"r32float"}}] - expected: FAIL [:compute=false;callDrawOrDispatch=true;entry={"storageTexture":{"access":"read-write","format":"r32float"}}] @@ -227,7 +221,6 @@ [:compute=false;type0="render-target";type1="render-target"] [:compute=false;type0="sampled-texture";type1="readonly-storage-texture"] - expected: FAIL [:compute=false;type0="sampled-texture";type1="readwrite-storage-texture"] @@ -253,7 +246,6 @@ expected: FAIL [:compute=true;type0="sampled-texture";type1="readonly-storage-texture"] - expected: FAIL [:compute=true;type0="sampled-texture";type1="readwrite-storage-texture"] diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_common/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_common/cts.https.html.ini @@ -3049,7 +3049,8 @@ [cts.https.html?q=webgpu:api,validation,resource_usages,texture,in_render_common:subresources,multiple_bind_groups:*] tags: [webgpu, webgpu-long] - implementation-status: backlog + implementation-status: + if os == "mac": backlog expected: if os == "mac" and debug: [OK, TIMEOUT] if os == "mac" and not debug: TIMEOUT @@ -3058,7 +3059,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3071,7 +3071,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3092,7 +3091,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3105,7 +3103,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3350,7 +3347,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3363,7 +3359,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3384,7 +3379,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3397,7 +3391,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3418,7 +3411,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3431,7 +3423,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3452,7 +3443,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3465,7 +3455,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3678,7 +3667,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3691,7 +3679,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3712,7 +3699,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3725,7 +3711,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3746,7 +3731,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3759,7 +3743,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -3972,7 +3955,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -3985,7 +3967,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4006,7 +3987,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -4019,7 +3999,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4040,7 +4019,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -4053,7 +4031,6 @@ [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":0,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":0,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4362,7 +4339,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -4375,7 +4351,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4396,7 +4371,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -4409,7 +4383,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4490,7 +4463,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="writeonly-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -4499,7 +4471,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -4656,7 +4627,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -4669,7 +4639,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -4694,11 +4663,6 @@ if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: FAIL - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] expected: @@ -4721,7 +4685,8 @@ if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL + expected: + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -4752,13 +4717,20 @@ if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readonly-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="readonly-storage-texture"] expected: @@ -4777,21 +4749,36 @@ if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="sampled-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="writeonly-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="readonly-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="readwrite-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="writeonly-storage-texture"] + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readonly-storage-texture"] expected: @@ -4802,7 +4789,8 @@ if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] expected: @@ -4825,7 +4813,8 @@ if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL + expected: + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -4857,10 +4846,7 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: FAIL - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] expected: @@ -4876,10 +4862,7 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: FAIL - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] expected: @@ -4895,10 +4878,7 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: FAIL - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] expected: @@ -4914,10 +4894,7 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: FAIL - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] expected: @@ -5096,7 +5073,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5109,7 +5085,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5130,7 +5105,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5143,7 +5117,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5164,7 +5137,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5177,7 +5149,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5202,7 +5173,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5211,7 +5181,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5220,7 +5189,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5393,7 +5361,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5406,7 +5373,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5427,7 +5393,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5440,7 +5405,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5461,7 +5425,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="readwrite-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="writeonly-storage-texture"] @@ -5474,7 +5437,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="writeonly-storage-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] @@ -5499,7 +5461,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5508,7 +5469,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":0,"count":3};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5517,7 +5477,6 @@ [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":1};bgUsage0="writeonly-storage-texture";bgUsage1="sampled-texture"] [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readonly-storage-texture";bgUsage1="sampled-texture"] - expected: FAIL [:bg0Levels={"base":1,"count":1};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":2};bg1Layers={"base":1,"count":2};bgUsage0="readwrite-storage-texture";bgUsage1="sampled-texture"] @@ -5592,9 +5551,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac": [FAIL, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5610,10 +5567,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [FAIL, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5757,10 +5711,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5779,10 +5730,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5801,10 +5749,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5823,10 +5768,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":0,"count":3};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5945,10 +5887,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, FAIL, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5964,10 +5903,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, FAIL, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -5983,10 +5919,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [PASS, FAIL, TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":1};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -6114,10 +6047,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":0,"count":3};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -6136,10 +6066,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":1};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: @@ -6158,10 +6085,7 @@ [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readonly-storage-texture"] expected: - if os == "win": FAIL - if os == "linux": FAIL - if os == "mac" and debug: [PASS, TIMEOUT, NOTRUN] - if os == "mac" and not debug: [TIMEOUT, NOTRUN] + if os == "mac": [PASS, TIMEOUT, NOTRUN] [:bg0Levels={"base":1,"count":2};bg0Layers={"base":1,"count":2};bg1Levels={"base":1,"count":1};bg1Layers={"base":1,"count":2};bgUsage0="sampled-texture";bgUsage1="readwrite-storage-texture"] expected: diff --git a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_misc/cts.https.html.ini b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/resource_usages/texture/in_render_misc/cts.https.html.ini @@ -1,11 +1,9 @@ [cts.https.html?q=webgpu:api,validation,resource_usages,texture,in_render_misc:subresources,set_bind_group_on_same_index_color_texture:*] - implementation-status: backlog [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="readonly-storage-texture"] [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="readwrite-storage-texture"] [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="sampled-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="writeonly-storage-texture"] @@ -18,7 +16,6 @@ [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="readwrite-storage-texture";view2Binding="writeonly-storage-texture"] [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="sampled-texture";view2Binding="readonly-storage-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=false;baseLayer2=0;view1Binding="sampled-texture";view2Binding="readwrite-storage-texture"] @@ -39,7 +36,6 @@ [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="readwrite-storage-texture"] [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="sampled-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="writeonly-storage-texture"] @@ -52,7 +48,6 @@ [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="readwrite-storage-texture";view2Binding="writeonly-storage-texture"] [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="sampled-texture";view2Binding="readonly-storage-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=false;baseLayer2=1;view1Binding="sampled-texture";view2Binding="readwrite-storage-texture"] @@ -73,7 +68,6 @@ [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="readwrite-storage-texture"] [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="sampled-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="readonly-storage-texture";view2Binding="writeonly-storage-texture"] @@ -86,7 +80,6 @@ [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="readwrite-storage-texture";view2Binding="writeonly-storage-texture"] [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="sampled-texture";view2Binding="readonly-storage-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=true;baseLayer2=0;view1Binding="sampled-texture";view2Binding="readwrite-storage-texture"] @@ -107,7 +100,6 @@ [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="readwrite-storage-texture"] [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="sampled-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="readonly-storage-texture";view2Binding="writeonly-storage-texture"] @@ -120,7 +112,6 @@ [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="readwrite-storage-texture";view2Binding="writeonly-storage-texture"] [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="sampled-texture";view2Binding="readonly-storage-texture"] - expected: FAIL [:useDifferentTextureAsTexture2=true;baseLayer2=1;view1Binding="sampled-texture";view2Binding="readwrite-storage-texture"] @@ -148,7 +139,6 @@ [cts.https.html?q=webgpu:api,validation,resource_usages,texture,in_render_misc:subresources,set_unused_bind_group:*] - implementation-status: backlog [:inRenderPass=false;textureUsage0="readonly-storage-texture";textureUsage1="readonly-storage-texture"] [:inRenderPass=false;textureUsage0="readonly-storage-texture";textureUsage1="readwrite-storage-texture"] @@ -186,7 +176,6 @@ [:inRenderPass=true;textureUsage0="readonly-storage-texture";textureUsage1="readwrite-storage-texture"] [:inRenderPass=true;textureUsage0="readonly-storage-texture";textureUsage1="sampled-texture"] - expected: FAIL [:inRenderPass=true;textureUsage0="readonly-storage-texture";textureUsage1="writeonly-storage-texture"] @@ -199,7 +188,6 @@ [:inRenderPass=true;textureUsage0="readwrite-storage-texture";textureUsage1="writeonly-storage-texture"] [:inRenderPass=true;textureUsage0="sampled-texture";textureUsage1="readonly-storage-texture"] - expected: FAIL [:inRenderPass=true;textureUsage0="sampled-texture";textureUsage1="readwrite-storage-texture"] diff --git a/third_party/rust/macro_rules_attribute-proc_macro/.cargo-checksum.json b/third_party/rust/macro_rules_attribute-proc_macro/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"aced87e40c5404daf404267a71859b1c2c7fa684992e018382f82060eb8b51c2","LICENSE-APACHE":"388e98b08de12ba8a9d4575883c8b0386c747cea188ed459380fc58d60da15c9","LICENSE-MIT":"603fb27ef3266ea516872eefd9ae587746b8c34614a35c0fb24e4e9e0c17e137","LICENSE-ZLIB":"1c41c0e19caa2c20b0adfeb8219b606b21b7c63914aa3ae74ae3e091d7ce09ca","mod.rs":"97333f27c4f9b72535436a1c6f15e80834cc0224b5a5986930bed99c523f0afd"},"package":"670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"} +\ No newline at end of file diff --git a/third_party/rust/macro_rules_attribute-proc_macro/Cargo.toml b/third_party/rust/macro_rules_attribute-proc_macro/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" +authors = ["Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"] +description = "Use declarative macros as proc_macro attributes or derives" +license = "Apache-2.0 OR MIT OR Zlib" +repository = "https://github.com/danielhenrymantilla/macro_rules_attribute-rs" + +[lib] +path = "mod.rs" +proc-macro = true + +[dependencies] + +[features] +verbose-expansions = [] diff --git a/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-APACHE b/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-MIT b/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-ZLIB b/third_party/rust/macro_rules_attribute-proc_macro/LICENSE-ZLIB @@ -0,0 +1,19 @@ +zlib License + +(C) 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/third_party/rust/macro_rules_attribute-proc_macro/mod.rs b/third_party/rust/macro_rules_attribute-proc_macro/mod.rs @@ -0,0 +1,304 @@ +//! Do not use this crate directly. Instead, use [`::macro_rules_attribute`]( +//! https://docs.rs/macro_rules_attribute) + +use { + ::core::{ + ops::Not as _, + iter::FromIterator as _, + }, + ::proc_macro::{*, + TokenTree as TT, + }, +}; + +// See the re-export at the frontend (`src/lib.rs`) for the documentation. +#[proc_macro_attribute] pub +fn macro_rules_attribute ( + attrs: TokenStream, + input: TokenStream, +) -> TokenStream +{ + let ret = macro_rules_attribute_impl(&attrs.vec(), input); + #[cfg(feature = "verbose-expansions")] + eprintln!("{}", ret); + ret +} + +fn macro_rules_attribute_impl ( + attrs: &'_ [TokenTree], + input: TokenStream +) -> TokenStream +{ + let mut ret: TokenStream; + // check that `attrs` is indeed of the form `$macro_name:path !` + match is_path_bang_terminated(&attrs) { + | Ok(PathIsBangTerminated(trailing_bang)) => { + ret = attrs.iter().cloned().collect(); + if trailing_bang { + /* OK */ + } else { + // tolerate it + ret.extend([TT::Punct(Punct::new('!', Spacing::Alone))]); + } + }, + | Err(()) => return parse_path_error(attrs), + } + ret.extend([TT::Group(Group::new( + Delimiter::Brace, + // FIXME: directly using `input` makes the token stream be seen + // as a single token tree by the declarative macro !?? + input.into_iter().collect(), + ))]); + ret +} + +// See the re-export at the frontend (`src/lib.rs`) for the documentation. +#[proc_macro_attribute] pub +fn macro_rules_derive ( + attrs: TokenStream, + input: TokenStream, +) -> TokenStream +{ + let mut ret = TokenStream::new(); + ret.extend( + attrs + .vec() + // we use `split_inclusive()` + strip approach to support trailing + // comma and yet detect empty input: `derive(Something,,ShouldFail)` + .split_inclusive(is_punct(',')) + .map(|attr| match attr { + | [hd @ .., p] if is_punct(',')(p) => hd, + | _ => attr, + }) + .flat_map(|attr| macro_rules_attribute_impl(attr, input.clone())) + ); + ret.extend(real_derive(ts!(::macro_rules_attribute::Custom))); + ret.extend(input); + #[cfg(feature = "verbose-expansions")] + eprintln!("{}", ret); + ret +} + +// See the re-export at the frontend (`src/lib.rs`) for the documentation. +#[proc_macro_attribute] pub +fn derive ( + attrs: TokenStream, + input: TokenStream, +) -> TokenStream +{ + let attrs = attrs.vec(); + + // any `path::to::Macro!` in the derive list? + if attrs.iter().any(is_punct('!')).not() { + // This is a good old derive. + let mut ret = real_derive(attrs.into_iter().collect()); + ret.extend(input); + #[cfg(feature = "verbose-expansions")] + eprintln!("{}", ret); + return ret; + } + + // Note: emitting the input as-is would break derives that use helper + // attributes. + // + // ```rust + // let mut ret = input; + // ret.extend(nested_derive! { #[derive(#real_derives)]})… + // ``` + // + // So we have to do it otherwise: we do not emit `input` directly, + // but rather, with the real derives directly attached to it + // (no `nested_derive!` invocation at all, here). + // So it will be the job of each real derive's to strip its inert derive + // helpers, which is something only a built-in derive can do, hence dodging + // the issue :) + let each_attr = || { + attrs + // we use `split_inclusive()` + strip approach to support trailing + // comma and yet detect empty input: `derive(Something,,ShouldFail)` + .split_inclusive(is_punct(',')) + .map(|attr| match attr { + | [hd @ .., p] if is_punct(',')(p) => hd, + | _ => attr, + }) + }; + let ref each_is_path_bang_terminated = + each_attr() + .map(is_path_bang_terminated) + .vec() + ; + for (attr, parse_bang) in each_attr().zip(each_is_path_bang_terminated) { + if let Err(()) = parse_bang { + return parse_path_error(attr); + } + } + let attrs_banged = |banged| { + each_attr() + .zip(each_is_path_bang_terminated) + .filter(move |(_, parse_bang)| parse_bang.unwrap().0 == banged) + .map(|(attr, _)| attr) + }; + let mut ret = TokenStream::new(); + attrs_banged(true).for_each(|attr| { + ret.extend(macro_rules_attribute_impl(attr, input.clone())) + }); + ret.extend(real_derive( + attrs_banged(false) + .flat_map(|attr| attr.iter().cloned().chain(ts!(,))) + .chain(ts!(::macro_rules_attribute::Custom,)) + .collect() + , + )); + ret.extend(input); + + #[cfg(feature = "verbose-expansions")] + eprintln!("{}", ret); + ret +} + +#[proc_macro_derive(Custom, attributes(custom, derive_args))] pub +fn custom(_:TokenStream) -> TokenStream { + TokenStream::new() +} + +fn real_derive ( + derives: TokenStream, +) -> TokenStream +{ + // `#[::core::prelude::v1::derive( #derives )]` + TokenStream::from_iter([ + TT::Punct(Punct::new('#', Spacing::Alone)), + TT::Group(Group::new( + Delimiter::Bracket, + { + let mut ts: TokenStream = ts!( + ::core::prelude::v1::derive + ); + ts.extend([TT::Group(Group::new( + Delimiter::Parenthesis, + derives, + ))]); + ts + }, + )) + ]) +} + + +#[::core::prelude::v1::derive(Clone, Copy)] +struct PathIsBangTerminated(bool); + +fn parse_path_error ( + incorrect_input: &[TokenTree], +) -> TokenStream +{ + let mut spans = incorrect_input.iter().map(|tt| tt.span()); + let mut ts = ts!( + ::core::compile_error! { + "\ + expected a parameter of the form `path::to::macro_name !` \ + or `path::to::macro_name`.\ + " + } + ).vec(); + let fst_span = spans.next().unwrap_or_else(Span::call_site); + let lst_span = spans.fold(fst_span, |_, cur| cur); + ts.iter_mut().for_each(|tt| tt.set_span(fst_span)); + ts.last_mut().unwrap().set_span(lst_span); + ts.into_iter().collect() +} + +/// `Ok(… true)` => `some::path!` +/// `Ok(… false)` => `some::path` +/// `Err` => not a (simple) path. +fn is_path_bang_terminated ( + tts: &'_ [TokenTree], +) -> Result<PathIsBangTerminated, ()> +{ + let mut tts = tts.iter().peekable(); + + macro_rules! parse_optional_semicolons {() => ( + match tts.peek() { + | Some(TT::Punct(p)) => { + let _ = tts.next(); + if p.as_char() == ':' && p.spacing() == Spacing::Joint { + match tts.next() { + | Some(TT::Punct(p)) + if p.as_char() == ':' + && p.spacing() == Spacing::Alone + => { + Some(()) + }, + | _ => return Err(()), + } + } else { + return Err(()); + } + }, + | _ => None, + } + )} + + macro_rules! parse_trailing_comma {() => ( + if tts.peek().copied().map_or(false, is_punct(',')) { + let _ = tts.next(); + if tts.next().is_some() { + return Err(()); + } + } + )} + + parse_optional_semicolons!(); + // Loop invariant: we start at the identifier part of a path segment. + loop { + match tts.next() { + | Some(TT::Ident(_)) => {}, + | _ => return Err(()), + } + // After an identifier, either nothing remains + // (but for an optional trailing comma) + parse_trailing_comma!(); + if tts.peek().is_none() { + return Ok(PathIsBangTerminated(false)); + } + // or remains a punctuation: either a trailing `!`… + if tts.peek().copied().map_or(false, is_punct('!')) { + let _ = tts.next(); + // Now nothing remains (but for an optional trailing comma). + parse_trailing_comma!(); + return if tts.next().is_none() { + Ok(PathIsBangTerminated(true)) + } else { + Err(()) + }; + } + // …or the `::` separator for yet another segment. + if parse_optional_semicolons!().is_none() { + return Err(()); + } + } +} + +fn is_punct (c: char) + -> impl 'static + Fn(&'_ TokenTree) -> bool +{ + move |tt| matches!(tt, TT::Punct(p) if p.as_char() == c) +} + +macro_rules! ts {( $($tt:tt)* ) => ( + ::core::stringify! { + $($tt)* + } + .parse::<::proc_macro::TokenStream>() + .unwrap() +)} use ts; + +trait CollectVec : IntoIterator + Sized { + fn vec (self: Self) + -> Vec<Self::Item> + { + impl<T : IntoIterator> CollectVec for T {} + + self.into_iter().collect() + } +} diff --git a/third_party/rust/macro_rules_attribute/.cargo-checksum.json b/third_party/rust/macro_rules_attribute/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"a084bb0495b00c318aaa05b771cb01281fc432dad4ecf226840e02f41558c2c8","LICENSE-APACHE":"388e98b08de12ba8a9d4575883c8b0386c747cea188ed459380fc58d60da15c9","LICENSE-MIT":"603fb27ef3266ea516872eefd9ae587746b8c34614a35c0fb24e4e9e0c17e137","LICENSE-ZLIB":"1c41c0e19caa2c20b0adfeb8219b606b21b7c63914aa3ae74ae3e091d7ce09ca","README.md":"bf472832f2b187743754c3f4533d355f3bd5c2f83f87ff3a97954ea59c716c04","fix-docsrs-li-details-summary.html":"8ee2f691516dea98a02944c553dda8255cb90d412a29f96572c5194e6a454086","rust-toolchain.toml":"ce21c6119593c883c901f87be4a36d7848f57df8d9cebadf0939061fc61bac87","src/lib.rs":"2b74e5b5da38f158b4967f0a07548b9258b9666200c1777b20a281991a1f30c0","tests/custom_derive.rs":"e4fa2644aaf53ec3076dc3a577856a48074576fb88723fa22b5bee999648929e","tests/inert_derive_helpers.rs":"dcbbf216c600138f3ae74303966aec77109b550cb9fae8d3a5391ee8593e5a09"},"package":"65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"} +\ No newline at end of file diff --git a/third_party/rust/macro_rules_attribute/Cargo.toml b/third_party/rust/macro_rules_attribute/Cargo.toml @@ -0,0 +1,59 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "macro_rules_attribute" +version = "0.2.2" +authors = ["Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>"] +exclude = ["*.sh"] +description = "Use declarative macros in attribute or derive position" +homepage = "https://crates.io/crates/macro_rules_attribute" +documentation = "https://docs.rs/macro_rules_attribute" +readme = "README.md" +keywords = [ + "macro", + "attribute", + "decorator", + "derive", + "macro_rules", +] +categories = ["rust-patterns"] +license = "Apache-2.0 OR MIT OR Zlib" +repository = "https://github.com/danielhenrymantilla/macro_rules_attribute-rs" + +[package.metadata.docs.rs] +features = ["better-docs"] +rustdoc-args = [ + "--html-before-content", + "fix-docsrs-li-details-summary.html", +] + +[dependencies.macro_rules_attribute-proc_macro] +version = "=0.2.2" + +[dependencies.paste] +version = "1.0.7" + +[dev-dependencies.once_cell] +version = "1.10.0" + +[dev-dependencies.pin-project-lite] +version = "0.2.8" + +[dev-dependencies.serde] +version = "1.0.136" +features = ["derive"] + +[features] +better-docs = [] +default = [] +verbose-expansions = ["macro_rules_attribute-proc_macro/verbose-expansions"] diff --git a/third_party/rust/macro_rules_attribute/LICENSE-APACHE b/third_party/rust/macro_rules_attribute/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/rust/macro_rules_attribute/LICENSE-MIT b/third_party/rust/macro_rules_attribute/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/macro_rules_attribute/LICENSE-ZLIB b/third_party/rust/macro_rules_attribute/LICENSE-ZLIB @@ -0,0 +1,19 @@ +zlib License + +(C) 2019 Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com> + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/third_party/rust/macro_rules_attribute/README.md b/third_party/rust/macro_rules_attribute/README.md @@ -0,0 +1,434 @@ +# `::macro_rules_attribute` + +Use declarative macros in attribute or derive position. + +```rust ,ignore +macro_rules! my_fancy_decorator { /* … */ } + +#[apply(my_fancy_decorator!)] +struct Foo { /* … */ } +``` + +```rust ,ignore +macro_rules! MyFancyDerive { /* … */ } + +#[derive(MyFancyDerive!)] /* using this crate's `#[derive]` attribute */ +struct Foo { /* … */ } +``` + + +[![Repository](https://img.shields.io/badge/repository-GitHub-brightgreen.svg)]( +https://github.com/danielhenrymantilla/macro_rules_attribute-rs) +[![Latest version](https://img.shields.io/crates/v/macro_rules_attribute.svg)]( +https://crates.io/crates/macro_rules_attribute) +[![Documentation](https://docs.rs/macro_rules_attribute/badge.svg)]( +https://docs.rs/macro_rules_attribute) +[![MSRV](https://img.shields.io/badge/MSRV-1.78.0-white)]( +https://gist.github.com/danielhenrymantilla/9b59de4db8e5f2467ed008b3c450527b) +[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)]( +https://github.com/rust-secure-code/safety-dance/) +[![License](https://img.shields.io/crates/l/macro_rules_attribute.svg)]( +https://github.com/danielhenrymantilla/macro_rules_attribute-rs/blob/master/LICENSE-ZLIB) +[![CI](https://github.com/danielhenrymantilla/macro_rules_attribute-rs/workflows/CI/badge.svg)]( +https://github.com/danielhenrymantilla/macro_rules_attribute-rs/actions) + +<!-- Templated by `cargo-generate` using https://github.com/danielhenrymantilla/proc-macro-template --> + +## Motivation + +<details><summary>Click to see</summary> + +`macro_rules!` macros can be extremely powerful, but their call-site ergonomics +are sometimes not great, especially when decorating item definitions. + +Indeed, compare: + +```rust ,ignore +foo! { + struct Struct { + some_field: SomeType, + } +} +``` + +to: + +```rust ,ignore +#[foo] +struct Struct { + some_field: SomeType, +} +``` + + 1. The former does not scale well, since it leads to **rightward drift and +"excessive" braces**. + + 1. But on the other hand, the latter requires setting up a dedicated crate for + the compiler, a `proc-macro` crate. And 99% of the time this will pull the + [`::syn`] and [`::quote`] dependencies, which have **a + non-negligible compile-time overhead** (the first time they are compiled). + + - note: these crates are a wonderful piece of technology, and can lead to + extremely powerful macros. When the logic of the macro is so complicated + that it requires a recursive `tt` muncher when implemented as a + `macro_rules!` macro, it is definitely time to be using a `proc`edural + macro. + + Anything involving `ident` generation / derivation, for instance, will very + often require `proc`edural macros, unless it is simple enough for + [`::paste`] to handle it. + +___ + +## Solution + +</details> + +With this crate's <code>#\[[apply]\]</code> and <code>#\[[derive]\]</code> +attributes, it is now possible to use `proc_macro_attribute` syntax to apply a +`macro_rules!` macro: + + +```rust +#[macro_use] +extern crate macro_rules_attribute; + +macro_rules! foo { + // … + # ( $($tt:tt)* ) => () +} + +macro_rules! Bar { + // … + # ( $($tt:tt)* ) => () +} + +#[apply(foo)] +#[derive(Debug, Bar!)] +struct Struct { + some_field: SomeType, +} +# +# fn main() {} +``` + +without even depending on [`::quote`], [`::syn`] or [`::proc-macro2`], for +**fast compile times**. + +[`::paste`]: https://docs.rs/paste +[`::proc-macro2`]: https://docs.rs/proc_macro2 +[`::syn`]: https://docs.rs/syn +[`::quote`]: https://docs.rs/quote +[`::pin-project`]: https://docs.rs/pin-project +[`::pin-project-lite`]: https://docs.rs/pin-project-lite + +# Examples + +<details><summary>Click to see</summary> + +### Nicer derives + +```rust +#[macro_use] +extern crate macro_rules_attribute; + +// Easily define shorthand aliases for "derive groups" +derive_alias! { + #[derive(Eq!)] = #[derive(Eq, PartialEq)]; + #[derive(Ord!)] = #[derive(Ord, PartialOrd, Eq!)]; + #[derive(Copy!)] = #[derive(Copy, Clone)]; + #[derive(StdDerives!)] = #[derive(Debug, Copy!, Default, Ord!, Hash)]; +} + +/// Strongly-typed newtype wrapper around a `usize`, to be used for `PlayerId`s. +#[derive(StdDerives!, Into!, From!)] +pub +struct PlayerId /* = */ ( + pub usize, +); + +// You can also fully define your own derives using `macro_rules!` syntax +// (handling generic type definitions may be the only finicky thing, though…) +macro_rules! Into {( + $( #[$attr:meta] )* + $pub:vis + struct $NewType:ident ( + $(#[$field_attr:meta])* + $field_pub:vis + $Inner:ty $(, + + $($rest:tt)* )? + ); +) => ( + impl ::core::convert::Into<$Inner> for $NewType { + #[inline] + fn into (self: $NewType) + -> $Inner + { + self.0 + } + } +)} use Into; + +macro_rules! From {( + $( #[$attr:meta] )* + $pub:vis + struct $NewType:ident ( + $(#[$field_attr:meta])* + $field_pub:vis + $Inner:ty $(, + + $(#[$other_field_attr:meta])* + $other_field_pub:vis + $Rest:ty )* $(,)? + ); +) => ( + impl ::core::convert::From<$Inner> for $NewType { + #[inline] + fn from (inner: $Inner) + -> Self + { + Self(inner, $($Rest::default),*) + } + } +)} use From; +# +# fn main() {} +``` + +### Have a `-lite` version of a proc-macro dependency that thus requires unergonomic `macro_rules!`? + +Say you are writing a (pervasive and yet) tiny dependency within the `async` +ecosystem. + + - By virtue of working with `async`, you'll most probably need to deal with + pin-projections, and thence, with [`::pin-project`]. + + - But by virtue of being (pervasive and yet) tiny, you don't want to depend + on the `quote / proc-macro2 / syn` heavyweight[^only_full_syn_is_heavy] + troika/trinity/triumvirate of more advanced proc-macro crates. + +[^only_full_syn_is_heavy]: (note that only `syn` with the `"full"` features would be the truly heavyweight party) + +Hence why you may reach for something such as [`::pin-project-lite`], and its +`pin_project!` `macro_rules!`-based polyfill of the former's `#[pin_project]` +attribute. + +But this suddenly hinders the ergonomics of your type definitions, and, worse, +would not be composable whenever the pattern were to be repeated for some other +functionality (_e.g._, say a `cell_project!` similar macro). + +Say no more! Time to <code>#\[[apply]\]</code> our neat trick: + +```rust +#[macro_use] +extern crate macro_rules_attribute; + +use { + ::core::pin::{ + Pin, + }, + ::pin_project_lite::{ + pin_project, + }, +}; + +#[apply(pin_project!)] +struct Struct<T, U> { + #[pin] + pinned: T, + unpinned: U, +} + +impl<T, U> Struct<T, U> { + fn method(self: Pin<&mut Self>) { + let this = self.project(); + let _: Pin<&mut T> = this.pinned; // Pinned reference to the field + let _: &mut U = this.unpinned; // Normal reference to the field + } +} +# +# fn main() {} +``` + +### More ergonomic `lazy_static!`s + +Say you had something like: + +```rust +# use Sync as Logic; +# +static MY_GLOBAL: &dyn Logic = &Vec::<i32>::new(); +``` + +and now you want to change the value of that `MY_GLOBAL` to something that isn't +`const`-constructible, and yet would like to minimize the churn in doing so. + +```rust ,compile_fail +// (For those unaware of it, leaking memory to initialize a lazy static is +// a completely fine pattern, since it only occurs once, and thus, a bounded +// amount of times). +static MY_GLOBAL: &dyn Logic = Box::leak(Box::new(vec![42, 27])); // Error: not `const`! +``` + +You could _directly_ use a `lazy_static!` or a `OnceCell`, but then the +definition of your `static` will now appear noisier than it needs be. It's time +for attribute-position polish! + +First, define the helper around, say, `OnceCell`'s `Lazy` type: + +```rust +macro_rules! lazy_init {( + $( #[$attrs:meta] )* + $pub:vis + static $NAME:ident: $Ty:ty = $init_value:expr ; +) => ( + $( #[$attrs] )* + $pub + static $NAME : ::once_cell::sync::Lazy<$Ty> = + ::once_cell::sync::Lazy::new(|| $init_value) + ; +)} pub(in crate) use lazy_init; +``` + +and now it is time to use it!: + +```rust +# use Sync as Logic; +# +#[macro_use] +extern crate macro_rules_attribute; + +#[apply(lazy_init)] +static MY_GLOBAL: &dyn Logic = Box::leak(Box::new(vec![42, 27])); +# +# macro_rules! lazy_init {( +# $( #[$attrs:meta] )* +# $pub:vis +# static $NAME:ident : $Ty:ty = $init_value:expr ; +# ) => ( +# $( #[$attrs] )* +# $pub +# static $NAME : ::once_cell::sync::Lazy<$Ty> = +# ::once_cell::sync::Lazy::new(|| $init_value) +# ; +# )} use lazy_init; +# +# fn main() {} +``` + +</details> + +# Debugging + +An optional compilation feature, `"verbose-expansions"` can be used to print at +compile-time the exact output of each macro invocation from this crate: + +```toml +[dependencies] +macro_rules_attribute.version = "..." +macro_rules_attribute.features = ["verbose-expansions"] +``` + +# Features + +### `derive` aliases + +```rust +# fn main() {} +#[macro_use] +extern crate macro_rules_attribute; + +derive_alias! { + #[derive(Ord!)] = #[derive(PartialEq, Eq, PartialOrd, Ord)]; +} + +#[derive(Debug, Clone, Copy, Ord!)] +struct Foo { + // … +} +``` + + - See [`derive_alias!`] and <code>#\[[derive]\]</code> for more info. + +### `cfg` aliases + +<details><summary>Click to see</summary> + +```rust +# fn main() {} +#[macro_use] +extern crate macro_rules_attribute; + +attribute_alias! { + #[apply(complex_cfg!)] = #[cfg( + any( + any( + foo, + feature = "bar", + ), + all( + target_os = "fenestrations", + not(target_arch = "Pear"), + ), + ), + )]; +} + +#[apply(complex_cfg!)] +mod some_item { /* … */ } +``` + +</details> + +### Not using `#[macro_use] extern crate macro_rules_attribute` + +<details><summary>Click to see</summary> + +If you are allergic to `#[macro_use]` unscoped / globally-preluded semantics, +you may not be fond of having to use: + +```rust +#[macro_use] +extern crate macro_rules_attribute; +# fn main() {} +``` + +like this documentation pervasively does. + +In that case, know that you may very well stick to using `use` imports: + +```rust +use ::macro_rules_attribute::{derive, derive_alias, /* … */}; +// or even +use ::macro_rules_attribute::*; + +derive_alias! { + #[derive(Copy!)] = #[derive(Clone, Copy)]; +} + +#[derive(Copy!)] +struct Foo; +``` + +or even inlining the fully qualified paths (but note that the `…_alias!` macros +still take unqualified paths inside the definitions): + +```rust +::macro_rules_attribute::derive_alias! { + #[derive(Copy!)] = #[derive(Clone, Copy)]; +} + +#[::macro_rules_attribute::derive(Copy!)] +struct Foo; +``` + +I personally find these approaches too noisy to be worth it, despite the so +gained "namespace purity", hence my not using that pattern across the rest of +the examples. + +</details> + +[apply]: https://docs.rs/macro_rules_attribute/0.1.*/macro_rules_attribute/attr.apply.html +[derive]: https://docs.rs/macro_rules_attribute/0.1.*/macro_rules_attribute/attr.derive.html +[`derive_alias!`]: https://docs.rs/macro_rules_attribute/0.1.*/macro_rules_attribute/macro.derive_alias.html diff --git a/third_party/rust/macro_rules_attribute/fix-docsrs-li-details-summary.html b/third_party/rust/macro_rules_attribute/fix-docsrs-li-details-summary.html @@ -0,0 +1,5 @@ +<style> +summary { + display: list-item; +} +</style> diff --git a/third_party/rust/macro_rules_attribute/rust-toolchain.toml b/third_party/rust/macro_rules_attribute/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = '1.78.0' +# Templated by `cargo-generate` using https://github.com/danielhenrymantilla/proc-macro-template diff --git a/third_party/rust/macro_rules_attribute/src/lib.rs b/third_party/rust/macro_rules_attribute/src/lib.rs @@ -0,0 +1,568 @@ +/*! +[apply]: apply +[derive]: derive +[`derive_alias!`]: derive_alias +[`macro_rules_attribute`]: macro_rules_attribute +[`macro_rules_derive`]: macro_rules_derive +*/ +#![cfg_attr(feature = "better-docs", + cfg_attr(all(), doc = include_str!("../README.md")) +)] +#![cfg_attr(feature = "better-docs", + feature(doc_auto_cfg), +)] +#![no_std] +#![forbid(unsafe_code)] + +/// Legacy name for what is currently named <code>#\[[apply]]</code> +/// +/// Despite being a slightly clearer name (than `#[apply]` is) w.r.t. what it +/// does, `#[macro_rules_attribute]` had the big drawback of being a mouthful. +/// +/// Hence the `#[apply]` alias being born, and now even superseding +/// `#[macro_rules_attribute]` altogether as the author-deemed "idiomatic" +/// name to favor. +pub use ::macro_rules_attribute_proc_macro::macro_rules_attribute; + +/// Applies the given `macro_rules!` macro to the decorated item. +/// +/// This, as with any `proc_macro_attribute`, **consumes** the item it +/// decorates: it is the `macro_rules!` macro job to generate it (_it is thus +/// able to modify it_!). +/// +/// For a version with "read-only" access to the item it decorates, see +/// [`macro_rules_derive`][`macro@macro_rules_derive`]. +/// +/// ## Examples +/// +/// ### Deriving getters for a (non-generic) `struct` +/// +/// Imagine having define the following handy `make_getters!` (`macro_rules!`) +/// macro: +/// +/** ```rust +macro_rules! make_getters {( + $(#[$struct_meta:meta])* + $struct_vis:vis + struct $StructName:ident { + $( + $(#[$field_meta:meta])* + $field_vis:vis // this visibility will be applied to the getters instead + $field_name:ident : $field_ty:ty + ),* $(,)? + } +) => ( + // First, generate the struct definition we have been given, but with + // private fields instead. + $(#[$struct_meta])* + $struct_vis + struct $StructName { + $( + $(#[$field_meta])* + // notice the lack of visibility => private fields + $field_name: $field_ty, + )* + } + + // Then, implement the getters: + impl $StructName { + $( + #[inline] + $field_vis + fn $field_name (self: &'_ Self) + -> &'_ $field_ty + { + &self.$field_name + } + )* + } +)} +``` */ +/// +/// Basically allowing you to write: +/// +/** ```rust ,compile_fail +use example::Person; +mod example { + make_getters! { + /// The macro handles meta attributes such as docstrings + pub + struct Person { + pub + name: String, + + pub + age: u8, + } + } +} + +fn is_new_born (person: &'_ mut Person) + -> bool +{ + // Reading the value through the getter is fine… + return *person.age() == 0; + // But trying to mutate it by skipping the getter is not 💪 + person.age = 0; + // ^ error[E0616]: field `age` of struct `example::Person` is private +} +``` */ +/// +/// This is fine, _etc._, but that rightward drift on `make_getters! {` syntax +/// problematic: +/// +/// - Incurs in extra rightward drift and thus, noise. +/// +/// - Worse, **it leads to a non-escalable / composable pattern**: if we had a +/// second macro, say `make_setters!`, our syntax is unable to handle both +/// macros being called on the same type definition. +/// +/// Hence `::macro_rules_attribute`'s <code>#\[[apply]\]</code> (formerly called +/// `#[macro_rules_attribute]` itself) helper: +/// +/** ```rust +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +use example::Person; +mod example { + #[apply(make_getters!)] // or `#[apply(make_getters)]`: the final `!` is not mandatory + /// The macro handles meta attributes such as docstrings + pub + struct Person { + pub + name: String, + + pub + age: u8, + } + # // where; + # macro_rules! make_getters {( + # $(#[$struct_meta:meta])* + # $struct_vis:vis + # struct $StructName:ident { + # $( + # $(#[$field_meta:meta])* + # $field_vis:vis // this visibility will be applied to the getters instead + # $field_name:ident : $field_ty:ty + # ),* $(,)? + # } + # ) => ( + # // First, generate the struct definition we have been given, but with + # // private fields instead. + # $(#[$struct_meta])* + # $struct_vis + # struct $StructName { + # $( + # $(#[$field_meta])* + # // notice the lack of visibility => private fields + # $field_name: $field_ty, + # )* + # } + + # // Then, implement the getters: + # impl $StructName { + # $( + # #[inline] + # $field_vis + # fn $field_name (self: &'_ Self) + # -> &'_ $field_ty + # { + # &self.$field_name + # } + # )* + # } + # )} use make_getters; +} + +fn is_new_born (person: &'_ Person) + -> bool +{ + // Reading the value through the getter is fine… + *person.age() == 0 + // But trying to mutate it by skipping the getter is not 💪 + // person.age == 0 + // ^ error[E0616]: field `age` of struct `example::Person` is private +} +``` */ +pub use ::macro_rules_attribute_proc_macro::macro_rules_attribute as apply; + +/// Applies the given `macro_rules!` macro to the decorated item. +/// +/// This, as with any `#[derive(...)]`, **does not consume** the item it +/// decorates: instead, it only generates code on top of it. +/// +/// Also derives [`Custom`] to allow using `#[custom(...)]` and `#[derive_args(...)]` +/// as derive helpers. +/// +/// ## Examples +/// +/// ### Implementing `Into<Int>` for a given `#[repr(Int)]` `enum`: +/// +/** ```rust +#[macro_use] +extern crate macro_rules_attribute; + +macro_rules! ToInteger {( + #[repr($Int:ident)] + $(#[$enum_meta:meta])* + $pub:vis + enum $Enum:ident { + $( + $Variant:ident $(= $value:expr)? + ),* $(,)? + } +) => ( + impl ::core::convert::From<$Enum> for $Int { + #[inline] + fn from (x: $Enum) + -> Self + { + x as _ + } + } +)} + +#[macro_rules_derive(ToInteger)] // or `#[macro_rules_derive(ToInteger!)]` +#[repr(u32)] +enum Bool { + False, + True, +} + +fn main () +{ + assert_eq!(u32::from(Bool::False), 0); + assert_eq!(u32::from(Bool::True), 1); + // assert_eq!(u8::from(Bool::False), 0); + // ^ error[E0277]: the trait bound `u8: std::convert::From<main::Bool>` is not satisfied +} +``` */ +/// +/// ## Difference with <code>#\[[derive]\]</code> +/// +/// <code>#\[[macro_rules_derive]\]</code> is specifically intended to be used +/// with `macro_rules!`-based derives: +/// +/// - it won't accept classic derives; +/// +/// - thanks to that, the trailing `!` on the macro name is not mandatory. +/// +/// For <code>#\[[derive]\]</code>, it's exactly the opposite. +pub use ::macro_rules_attribute_proc_macro::macro_rules_derive; + +/// Convenience macro to define new derive aliases. +/// +/// The so-defined macros are intended to be used by +/// <code>#\[[macro_rules_derive]]</code> or this crate's +/// <code>#\[[derive]]</code>. +/// +/// ## Examples +/// +/** ```rust +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +derive_alias! { + #[derive(Copy!)] = #[derive(Clone, Copy)]; + #[derive(Eq!)] = #[derive(PartialEq, Eq)]; + #[derive(Ord!)] = #[derive(Eq!, PartialOrd, Ord)]; +} + +#[derive(Debug, Copy!, Ord!)] +struct Foo { + // … +} + +// Note: this defines `Copy!`, `Eq!` and `Ord!` as properly scoped +// `crate`-local macros. +mod example { + use super::Copy; + + #[derive(Copy!, super::Eq!)] + struct Bar; +} +``` */ +/// +/** ```rust +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +use ::core::{fmt::Debug, hash::Hash}; + +/// Trait alias pattern: `T : TheUsualSuspects ⇔ T : Debug + Copy + Ord + Hash`. +trait TheUsualSuspects +where // `⇒` direction + Self : Debug + Copy + Ord + Hash, +{} +impl<T : ?Sized> TheUsualSuspects for T +where // `⇐` direction + Self : Debug + Copy + Ord + Hash, +{} + +derive_alias! { + #[derive(TheUsualSuspects!)] = #[derive( + Debug, + Copy, Clone, + Ord, PartialOrd, Eq, PartialEq, + Hash, + )]; +} + +#[derive(TheUsualSuspects!)] +struct KeyserSöze; + +const _: () = { + fn compile_time_assert_impls<T : ?Sized> () + where + T : TheUsualSuspects, + {} + + let _ = compile_time_assert_impls::<KeyserSöze>; +}; +``` */ +/// +/// ### Caveat regarding derive helpers (inert-made attributes) +/// +/// <details><summary>Click to see</summary> +/// +/// Some derive attributes (such as `{De,}Serialize`), can involve helper +/// attributes (such as `#[serde]`). +/// This yields +/// <a href="https://doc.rust-lang.org/1.60.0/reference/attributes.html#active-and-inert-attributes" target="_blank">inert</a> +/// derive-<a href="https://doc.rust-lang.org/1.60.0/reference/procedural-macros.html#derive-macro-helper-attributes" target="_blank">helper-attributes</a>, +/// which represent a _semantic_ aspect of the derive that +/// **non-compiler-blessed macros such as this one cannot possibly know about**. +/// +/// This makes aliasing such derives problematic, **since the `derive` aliases +/// won't be able to handle the helper attributes**. +/// +/** ```rust ,compile_fail +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +derive_alias! { + #[derive(Serde!)] = #[derive(::serde::Deserialize, ::serde::Serialize)]; +} + +#[derive(Serde!)] +#[serde(rename_all = "snake_case")] // Error, unknown `#[serde]` attribute +struct Mejrs { + swaginess: u8, +} +``` */ +/// +/// The above, for instance, yields something along the lines of: +/// +/** ```rust +# #[cfg(any())] macro_rules! ignore { + error: cannot find attribute "serde" in this scope + --> src/lib.rs:11:3 + | + 11 | #[serde(rename_all = "snake_case")] + | ^^^^^ + | + = note: "serde" is in scope, but it is a crate, not an attribute +# } +``` */ +/// +/// The only solution is to forgo the niceties of a `derive_alias!`, and define +/// your own <code>#\[[apply]\]</code>-able `macro_rules_attribute` that aliases +/// the `#[derive(…)]` attribute as a whole. [`attribute_alias!`] can come in +/// handy in such situations: +/// +/** ```rust +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +attribute_alias! { + #[apply(derive_Serde)] = #[derive(::serde::Deserialize, ::serde::Serialize)]; +} + +#[apply(derive_Serde)] +#[serde(rename_all = "snake_case")] // OK +struct Mejrs { + swaginess: u8, +} +``` */ +/// +/// ___ +/// +/// </details> +#[macro_export] +macro_rules! derive_alias {( + $( + #[derive($MacroName:ident !)] = #[derive($($derives:tt)*)]; + )* +) => ( + $crate::ඞ_with_dollar! {( $_:tt ) => ( + $crate::ඞ::paste! { + $( + // To avoid ambiguities with what the re-export + // refers to, let's use a hopefully unused name. + // + // Indeed, eponymous derive macros in scope such as those + // from the prelude would otherwise cause trouble with the + // re-export line. + #[allow(nonstandard_style)] + macro_rules! [< $MacroName __derive_macro >] {( + $_($item:tt)* + ) => ( + $crate::ඞ_nested_derive! { + #[derive($($derives)*)] + $_($item)* + } + )} + #[allow(unused_imports)] + pub(in crate) use [< $MacroName __derive_macro >] as $MacroName; + )* + } + )} +)} + + +/// Convenience macro to define new attribute aliases. +/// +/// The so-defined macros are intended to be used by <code>#\[[apply]]</code>. +/// +/// ## Examples +/// +/** ```rust +# fn main () {} +#[macro_use] +extern crate macro_rules_attribute; + +attribute_alias! { + #[apply(complex_cfg)] = #[cfg( + any( + test, + doc, + all( + feature = "some very complex cfg", + target_arch = "…", + ), + ) + )]; + + #[apply(NOT_PART_OF_THE_PUBLIC_API!)] = + /// Not part of the public API + #[doc(hidden)] + ; +} + +#[apply(complex_cfg)] +struct Foo { + // … +} + +#[apply(NOT_PART_OF_THE_PUBLIC_API!)] +pub mod __macro_internals { + // … +} +``` */ +/// +#[macro_export] +macro_rules! attribute_alias {( + $( + #[apply($name:ident $(!)?)] = $( #[$($attrs:tt)*] )+; + )* +) => ( + $( + $crate::ඞ_with_dollar! {( $_:tt ) => ( + // Let's not do the paste + module + re-export dance here since it + // is less likely for an attribute name to collide with a prelude item. + #[allow(nonstandard_style)] + macro_rules! $name {( $_($item:tt)* ) => ( + $( #[$($attrs)*] )+ + $_($item)* + )} + #[allow(unused_imports)] + pub(in crate) use $name; + )} + )* +)} + +#[doc(hidden)] /** Not part of the public API*/ #[macro_export] +macro_rules! ඞ_with_dollar {( $($rules:tt)* ) => ( + macro_rules! __emit__ { $($rules)* } + __emit__! { $ } +)} + +/// Like <code>#\[[macro_rules_derive]\]</code>, but for allowing to be +/// used to shadow [the "built-in" `#[derive]` attribute][1] (on Rust ≥ 1.57.0). +/// +/// [1]: https://doc.rust-lang.org/stable/core/prelude/v1/macro.derive.html +/// +/// That is, it is made a bit more lenient to allow for things such as: +/** ```rust +#[macro_use] +extern crate macro_rules_attribute; + +derive_alias! { + #[derive(Eq!)] = #[derive(PartialEq, Eq)]; +} + +#[derive(Debug, Eq!)] +struct Foo; + +fn main () +{ + assert_eq!(Foo, Foo); +} +``` */ +/// +/// This is achieved thanks to **checking for the presence of a terminating `!` +/// (or lack thereof)** to determine whether the given derive macro is a classic +/// procedural macro one or a `macro_rules!` one. +/// +/// Also derives [`Custom`] to allow using `#[custom(...)]` and `#[derive_args(...)]` +/// as derive helpers. +pub use ::macro_rules_attribute_proc_macro::derive; + +/// No-op macro that is automatically derived with [`derive`] or [`macro_rules_derive`] +/// to allow using the `#[custom(...)]` and `#[derive_args(...)]` attribute. +/// +/// See <https://github.com/danielhenrymantilla/macro_rules_attribute-rs/issues/9> for more info. +pub use ::macro_rules_attribute_proc_macro::Custom; + +attribute_alias! { + #[apply(this_macro_is_private!)] = + #[doc(hidden)] + /// Not part of the public API + #[macro_export] + ; +} + +mod nested_derive { + //! Inlined mini-version of `::nested_derive`. + #[crate::apply(this_macro_is_private!)] + macro_rules! ඞ_nested_derive { + ( + #[derive( $($Derives:tt)* )] + $($rest:tt)* + ) => ( + #[$crate::derive( $($Derives)* )] + #[$crate::apply($crate::ඞ_dalek_EXTERMINATE!)] + $($rest)* + ); + } + + // Ideally this would have been `dalek_☃_EXTERMINATE`, since the snowman + // ressembles a Dalek more, which is a paramount aspect of this hidden macro + // but for some reason Rust despises snowmen even though there are + // ඞ-infected identifiers among (s)us… + #[crate::apply(this_macro_is_private!)] + macro_rules! ඞ_dalek_EXTERMINATE {( $it:item ) => ()} +} + +#[doc(hidden)] /** Not part of the public API */ pub +mod ඞ { + pub use { + ::paste::paste, + }; +} diff --git a/third_party/rust/macro_rules_attribute/tests/custom_derive.rs b/third_party/rust/macro_rules_attribute/tests/custom_derive.rs @@ -0,0 +1,20 @@ +#[macro_use] +extern crate macro_rules_attribute; + +derive_alias! { + #[derive(Nothing!)] = #[derive()]; +} + +#[derive(Nothing!)] +#[custom(hello)] +struct Foo { + #[derive_args("test")] + x: i32, +} + +#[macro_rules_derive(Nothing)] +#[custom(hello)] +struct Bar { + #[derive_args("test")] + x: i32, +} diff --git a/third_party/rust/macro_rules_attribute/tests/inert_derive_helpers.rs b/third_party/rust/macro_rules_attribute/tests/inert_derive_helpers.rs @@ -0,0 +1,14 @@ +#[macro_use] +extern crate macro_rules_attribute; + +use ::serde::Serialize; + +derive_alias! { + #[derive(Nothing!)] = #[derive()]; +} + +#[derive(Nothing!, Serialize)] +#[serde(rename_all = "snake_case")] +struct Foo { + x: i32, +} 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":"3f63a91f4afde7bedb3163489a347ccfa4b833e1fc7a0f33ccd8817efc7d303a","src/back/glsl/features.rs":"da2c8fd44b25a03ded4a0ff2e16c5039ca77398efa7918b0af5cf055b87365e3","src/back/glsl/keywords.rs":"fee8ed132e44bace54869a7c169a1ab7ed55db1bf590b4b1bce9efa4552e1dd7","src/back/glsl/mod.rs":"86337bb3041b34d4051862665b6858afaf9c1d5bac69ce8e24b81a47e878f0d0","src/back/hlsl/conv.rs":"3e1a78203e8c4efb75986db962cec150c7b2d99f7e48b400e702233de70e8aab","src/back/hlsl/help.rs":"12ddb9d08fe64eb34b66ae2166edffce5106a04ccef0b8cc0391a6fafd676270","src/back/hlsl/keywords.rs":"f7fc06c44d2f0d620bcf1a02b699c98c32059741b771a0d1ba5645d71b2f433f","src/back/hlsl/mod.rs":"e83d54a5741f6f5c89d5e8ac56015021ceb9077262c3b9c47f0bf1a7e35dbab5","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"5083d03b1f25fe767e45e0c507bd30424352fccd48484c081620712d3682aae8","src/back/hlsl/writer.rs":"4415d3ce654bae43ffa85d587cbb2b628cbcda387a8bf3237f1450248d423414","src/back/mod.rs":"c9a21fefbf383dca12a44cdf5201beba35384ab175eaa61da05f3a2af5310484","src/back/msl/keywords.rs":"b3e5d86d2586d553ff0fc6d91a25f0f4726c829d280a65dd2deeeb146cbbaf6d","src/back/msl/mod.rs":"f9d05aadd4d6cb6fea165c7e0b31c910b63d8102de60edfe283f8f56b8d4197f","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"0d9bacb72fdee1768ff9a6b02e799607331788b557d44ad8d4c4f00e67c822a2","src/back/pipeline_constants.rs":"c2244d7e47a52c01ead61b4b6c7b3d0f29263ca308aca70f213137a0938c9aa4","src/back/spv/block.rs":"7fbe28ab6679070d8960201c97890f2f69d80dc1105eae1a992a5b82f4490d35","src/back/spv/f16_polyfill.rs":"44ce07ef497dff13a9152eb9bc5936c486ef53de6d476da6b0a39396b0e6abdb","src/back/spv/helpers.rs":"6ec40b59d9f0a77e1569a2610cad1f1ca1e02bc78871ce9322e70ecdda0b3eb9","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":"18f103c0d5c728036b5cb133677a301f51fe9702abb0b975ae618365b304158f","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":"d6ed811147b79ed74c2600bfc5485c2821dabb08b70982a4191a6a6c3d2c1a38","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":"215212963faf83c5c931c760b858c6c8b11cc582dda08f8627aefa83b6425135","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":"7627b587f9ada7771728d0248113213ef0750e1ab9290e2a1a312a693c574568","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":"fb76ba4922898700d6b156d4f214566e60931954219d22ff2ff47689b3666613","src/front/glsl/lex.rs":"24706628b600b5ce435cef464c84196ac5d58013122a97e7b59d509cc25f85a2","src/front/glsl/mod.rs":"f4f1cce6911935b305c415afe3c15f84c7824a3bb828a5d15e6f9ae4b0316df0","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":"75d3e203a07befd011f5693ab8f2789e4f06821badb4974043cc4ee10bd5c6c9","src/front/interpolator.rs":"4d6c6639c01fba78ffb8d0af298094cc2d6bb33f8054dad4379fd9fe3af5a4c8","src/front/mod.rs":"fddd2be54ff44b52743ac8eb4a19e153a8a169af8e65d9061a9b9fc9857f64db","src/front/spv/convert.rs":"16b8281fc1ae75dc62a02893db2c5b6d8994166e78b3b6b8cac7a01e0da4eae2","src/front/spv/error.rs":"d08e1d65716ccc0f2a94a1285a1d034fa4840dc79ca60a5ec7481697bdec74d1","src/front/spv/function.rs":"26323687512d18c74c16e82b3aca3f5a65f1eae8a0e7e218b195f0051fe3012e","src/front/spv/image.rs":"c39ffdb19a19861cec009de39431a879be99bdd4d9d08c0ecdef397c2f3f6fa5","src/front/spv/mod.rs":"ed64895ebb2050f9b401f9f98a69f1ddf80a361d8ac98e1bda780b6e1c02086b","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":"5473b4607ac7f89ab10cdd2bfeb59a47b52dd591ba19d85c8795d45ab4ca72de","src/front/wgsl/mod.rs":"95d38b0a49833638a06ac35c6df30c8fd3dcfa5494871e6d166f7e70f54b8fa3","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"d76de215e3fea00776b5a0e8f979c074ac35a2f16892522c1a6bfe5a051c438a","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":"2933daabb5e22d023682ad5368d9c65a136000ad85f48a29104a562326a91a40","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":"3674ef30174a6110bad461a4208f16ed208b7347f1a8c58654b87e14558cf99c","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":"9e0479bee5d2ac15704f69d8852400cd1bcd35bc01c056cb9a510db6dec63a39","src/valid/compose.rs":"46eeed8c4d5b66fc043ddb701074bd864a9fdd24e38b88e282046230acefb747","src/valid/expression.rs":"f8d9e3e20d21ddb9ade2e793d590631bcf4e7c135804a0130302d57212521f6f","src/valid/function.rs":"e97ddecd0369f192fd25c59aeeef3bdd04f86858f5ed625dc384c2d00030ebbc","src/valid/handles.rs":"59f96f672f57e253006f330a3b9a540564dfb462a543e5cad6d20231de29538f","src/valid/interface.rs":"d6bddc8c722ed6e36371bc7796922a524f443f870a06b8f874f2aa49bde682d3","src/valid/mod.rs":"83a51f1e5d30dc1b3118218e21d1ac87d4c16ebb962fd71d50534d258fef8d7d","src/valid/type.rs":"65d2c02000e8038d9adab6ea94741fea61844d0626d7fa4389c54dcaa594704b"},"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":"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 diff --git a/third_party/rust/naga/src/back/dot/mod.rs b/third_party/rust/naga/src/back/dot/mod.rs @@ -307,6 +307,25 @@ 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/features.rs b/third_party/rust/naga/src/back/glsl/features.rs @@ -55,6 +55,8 @@ bitflags::bitflags! { const SUBGROUP_OPERATIONS = 1 << 24; /// Image atomics const TEXTURE_ATOMICS = 1 << 25; + /// Image atomics + const SHADER_BARYCENTRICS = 1 << 26; } } @@ -288,6 +290,14 @@ impl FeaturesManager { writeln!(out, "#extension GL_OES_shader_image_atomic : require")?; } + if self.0.contains(Features::SHADER_BARYCENTRICS) { + // https://github.com/KhronosGroup/GLSL/blob/main/extensions/ext/GLSL_EXT_fragment_shader_barycentric.txt + writeln!( + out, + "#extension GL_EXT_fragment_shader_barycentric : require" + )?; + } + Ok(()) } } @@ -603,6 +613,9 @@ impl<W> Writer<'_, W> { crate::BuiltIn::InstanceIndex | crate::BuiltIn::DrawID => { self.features.request(Features::INSTANCE_INDEX) } + crate::BuiltIn::Barycentric => { + self.features.request(Features::SHADER_BARYCENTRICS) + } _ => {} }, Binding::Location { @@ -610,6 +623,7 @@ impl<W> Writer<'_, W> { interpolation, sampling, blend_src, + per_primitive: _, } => { if interpolation == Some(Interpolation::Linear) { self.features.request(Features::NOPERSPECTIVE_QUALIFIER); diff --git a/third_party/rust/naga/src/back/glsl/mod.rs b/third_party/rust/naga/src/back/glsl/mod.rs @@ -139,7 +139,8 @@ impl crate::AddressSpace { | crate::AddressSpace::Uniform | crate::AddressSpace::Storage { .. } | crate::AddressSpace::Handle - | crate::AddressSpace::PushConstant => false, + | crate::AddressSpace::PushConstant + | crate::AddressSpace::TaskPayload => false, } } } @@ -1300,6 +1301,9 @@ impl<'a, W: Write> Writer<'a, W> { crate::AddressSpace::Storage { .. } => { self.write_interface_block(handle, global)?; } + crate::AddressSpace::TaskPayload => { + self.write_interface_block(handle, global)?; + } // A global variable in the `Function` address space is a // contradiction in terms. crate::AddressSpace::Function => unreachable!(), @@ -1614,6 +1618,7 @@ impl<'a, W: Write> Writer<'a, W> { interpolation, sampling, blend_src, + per_primitive: _, } => (location, interpolation, sampling, blend_src), crate::Binding::BuiltIn(built_in) => { match built_in { @@ -1732,6 +1737,7 @@ impl<'a, W: Write> Writer<'a, W> { interpolation: None, sampling: None, blend_src, + per_primitive: false, }, stage: self.entry_point.stage, options: VaryingOptions::from_writer_options(self.options, output), @@ -1873,7 +1879,7 @@ impl<'a, W: Write> Writer<'a, W> { writeln!(self.out, ") {{")?; if self.options.zero_initialize_workgroup_memory - && ctx.ty.is_compute_entry_point(self.module) + && ctx.ty.is_compute_like_entry_point(self.module) { self.write_workgroup_variables_initialization(&ctx)?; } @@ -2669,6 +2675,11 @@ 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(); @@ -5204,8 +5215,13 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s "gl_FragCoord" } } - Bi::ViewIndex if options.targeting_webgl => "int(gl_ViewID_OVR)", - Bi::ViewIndex => "gl_ViewIndex", + Bi::ViewIndex => { + if options.targeting_webgl { + "gl_ViewID_OVR" + } else { + "uint(gl_ViewIndex)" + } + } // vertex Bi::BaseInstance => "uint(gl_BaseInstance)", Bi::BaseVertex => "uint(gl_BaseVertex)", @@ -5227,6 +5243,7 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s Bi::PointCoord => "gl_PointCoord", Bi::FrontFacing => "gl_FrontFacing", Bi::PrimitiveIndex => "uint(gl_PrimitiveID)", + Bi::Barycentric => "gl_BaryCoordEXT", Bi::SampleIndex => "gl_SampleID", Bi::SampleMask => { if options.output { @@ -5247,6 +5264,15 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s Bi::SubgroupId => "gl_SubgroupID", Bi::SubgroupSize => "gl_SubgroupSize", Bi::SubgroupInvocationId => "gl_SubgroupInvocationID", + // mesh + // TODO: figure out how to map these to glsl things as glsl treats them as arrays + Bi::CullPrimitive + | Bi::PointIndex + | Bi::LineIndices + | Bi::TriangleIndices + | Bi::MeshTaskSize => { + unimplemented!() + } } } @@ -5262,6 +5288,7 @@ const fn glsl_storage_qualifier(space: crate::AddressSpace) -> Option<&'static s As::Handle => Some("uniform"), As::WorkGroup => Some("shared"), As::PushConstant => Some("uniform"), + As::TaskPayload => unreachable!(), } } diff --git a/third_party/rust/naga/src/back/hlsl/conv.rs b/third_party/rust/naga/src/back/hlsl/conv.rs @@ -161,6 +161,7 @@ impl crate::BuiltIn { Self::FragDepth => "SV_Depth", Self::FrontFacing => "SV_IsFrontFace", Self::PrimitiveIndex => "SV_PrimitiveID", + Self::Barycentric => "SV_Barycentrics", Self::SampleIndex => "SV_SampleIndex", Self::SampleMask => "SV_Coverage", // compute @@ -172,6 +173,7 @@ impl crate::BuiltIn { // to this field will get replaced with references to `SPECIAL_CBUF_VAR` // in `Writer::write_expr`. Self::NumWorkGroups => "SV_GroupID", + Self::ViewIndex => "SV_ViewID", // These builtins map to functions Self::SubgroupSize | Self::SubgroupInvocationId @@ -180,9 +182,12 @@ impl crate::BuiltIn { Self::BaseInstance | Self::BaseVertex | Self::WorkGroupSize => { return Err(Error::Unimplemented(format!("builtin {self:?}"))) } - Self::PointSize | Self::ViewIndex | Self::PointCoord | Self::DrawID => { + Self::PointSize | Self::PointCoord | Self::DrawID => { return Err(Error::Custom(format!("Unsupported builtin {self:?}"))) } + Self::CullPrimitive => "SV_CullPrimitive", + Self::PointIndex | Self::LineIndices | Self::TriangleIndices => unimplemented!(), + Self::MeshTaskSize => unreachable!(), }) } } diff --git a/third_party/rust/naga/src/back/hlsl/mod.rs b/third_party/rust/naga/src/back/hlsl/mod.rs @@ -650,6 +650,8 @@ pub enum Error { ResolveArraySizeError(#[from] proc::ResolveArraySizeError), #[error("entry point with stage {0:?} and name '{1}' not found")] EntryPointNotFound(ir::ShaderStage, String), + #[error("requires shader model {1:?} for reason: {0}")] + ShaderModelTooLow(String, ShaderModel), } #[derive(PartialEq, Eq, Hash)] diff --git a/third_party/rust/naga/src/back/hlsl/writer.rs b/third_party/rust/naga/src/back/hlsl/writer.rs @@ -507,7 +507,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_wrapped_functions(module, &ctx)?; - if ep.stage == ShaderStage::Compute { + if ep.stage.compute_like() { // HLSL is calling workgroup size "num threads" let num_threads = ep.workgroup_size; writeln!( @@ -569,6 +569,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { ) -> BackendResult { match *binding { Some(crate::Binding::BuiltIn(builtin)) if !is_subgroup_builtin_binding(binding) => { + if builtin == crate::BuiltIn::ViewIndex + && self.options.shader_model < ShaderModel::V6_1 + { + return Err(Error::ShaderModelTooLow( + "used @builtin(view_index) or SV_ViewID".to_string(), + ShaderModel::V6_1, + )); + } let builtin_str = builtin.to_hlsl_str()?; write!(self.out, " : {builtin_str}")?; } @@ -967,6 +975,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.write_type(module, global.ty)?; "" } + crate::AddressSpace::TaskPayload => unimplemented!(), crate::AddressSpace::Uniform => { // constant buffer declarations are expected to be inlined, e.g. // `cbuffer foo: register(b0) { field1: type1; }` @@ -1764,7 +1773,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { module: &Module, ) -> bool { self.options.zero_initialize_workgroup_memory - && func_ctx.ty.is_compute_entry_point(module) + && func_ctx.ty.is_compute_like_entry_point(module) && module.global_variables.iter().any(|(handle, var)| { !func_ctx.info[handle].is_empty() && var.space == crate::AddressSpace::WorkGroup }) @@ -2599,6 +2608,19 @@ 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(); @@ -3076,7 +3098,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { crate::AddressSpace::Function | crate::AddressSpace::Private | crate::AddressSpace::WorkGroup - | crate::AddressSpace::PushConstant, + | crate::AddressSpace::PushConstant + | crate::AddressSpace::TaskPayload, ) | None => true, Some(crate::AddressSpace::Uniform) => { diff --git a/third_party/rust/naga/src/back/mod.rs b/third_party/rust/naga/src/back/mod.rs @@ -139,11 +139,11 @@ pub enum FunctionType { } impl FunctionType { - /// Returns true if the function is an entry point for a compute shader. - pub fn is_compute_entry_point(&self, module: &crate::Module) -> bool { + /// Returns true if the function is an entry point for a compute-like shader. + pub fn is_compute_like_entry_point(&self, module: &crate::Module) -> bool { match *self { FunctionType::EntryPoint(index) => { - module.entry_points[index as usize].stage == crate::ShaderStage::Compute + module.entry_points[index as usize].stage.compute_like() } FunctionType::Function(_) => false, } diff --git a/third_party/rust/naga/src/back/msl/mod.rs b/third_party/rust/naga/src/back/msl/mod.rs @@ -526,10 +526,21 @@ impl Options { return Err(Error::UnsupportedAttribute("instance_id".to_string())); } // macOS: Since Metal 2.2 - // iOS: Since Metal 2.3 (check depends on https://github.com/gfx-rs/naga/issues/2164) - crate::BuiltIn::PrimitiveIndex if self.lang_version < (2, 2) => { + // iOS: Since Metal 2.3 (check depends on https://github.com/gfx-rs/wgpu/issues/4414) + crate::BuiltIn::PrimitiveIndex if self.lang_version < (2, 3) => { return Err(Error::UnsupportedAttribute("primitive_id".to_string())); } + // macOS: since Metal 2.3 + // iOS: Since Metal 2.2 + // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf#page=114 + crate::BuiltIn::ViewIndex if self.lang_version < (2, 2) => { + return Err(Error::UnsupportedAttribute("amplification_id".to_string())); + } + // macOS: Since Metal 2.2 + // iOS: Since Metal 2.3 (check depends on https://github.com/gfx-rs/wgpu/issues/4414) + crate::BuiltIn::Barycentric if self.lang_version < (2, 3) => { + return Err(Error::UnsupportedAttribute("barycentric_coord".to_string())); + } _ => {} } @@ -540,6 +551,7 @@ impl Options { interpolation, sampling, blend_src, + per_primitive: _, } => match mode { LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)), LocationMode::FragmentOutput => { @@ -668,6 +680,7 @@ impl ResolvedBinding { let name = match built_in { Bi::Position { invariant: false } => "position", Bi::Position { invariant: true } => "position, invariant", + Bi::ViewIndex => "amplification_id", // vertex Bi::BaseInstance => "base_instance", Bi::BaseVertex => "base_vertex", @@ -680,6 +693,7 @@ impl ResolvedBinding { Bi::PointCoord => "point_coord", Bi::FrontFacing => "front_facing", Bi::PrimitiveIndex => "primitive_id", + Bi::Barycentric => "barycentric_coord", Bi::SampleIndex => "sample_id", Bi::SampleMask => "sample_mask", // compute @@ -694,9 +708,13 @@ impl ResolvedBinding { Bi::SubgroupId => "simdgroup_index_in_threadgroup", Bi::SubgroupSize => "threads_per_simdgroup", Bi::SubgroupInvocationId => "thread_index_in_simdgroup", - Bi::CullDistance | Bi::ViewIndex | Bi::DrawID => { + Bi::CullDistance | Bi::DrawID => { return Err(Error::UnsupportedBuiltIn(built_in)) } + 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!(), }; 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 @@ -594,7 +594,8 @@ impl crate::AddressSpace { | Self::Private | Self::WorkGroup | Self::PushConstant - | Self::Handle => true, + | Self::Handle + | Self::TaskPayload => true, Self::Function => false, } } @@ -607,6 +608,7 @@ impl crate::AddressSpace { // may end up with "const" even if the binding is read-write, // and that should be OK. Self::Storage { .. } => true, + Self::TaskPayload => unimplemented!(), // These should always be read-write. Self::Private | Self::WorkGroup => false, // These translate to `constant` address space, no need for qualifiers. @@ -623,6 +625,7 @@ impl crate::AddressSpace { Self::Storage { .. } => Some("device"), Self::Private | Self::Function => Some("thread"), Self::WorkGroup => Some("threadgroup"), + Self::TaskPayload => Some("object_data"), } } } @@ -4060,6 +4063,14 @@ 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(""); @@ -6619,7 +6630,7 @@ template <typename A> LocationMode::Uniform, false, ), - crate::ShaderStage::Task | crate::ShaderStage::Mesh => unreachable!(), + crate::ShaderStage::Task | crate::ShaderStage::Mesh => unimplemented!(), }; // Should this entry point be modified to do vertex pulling? @@ -6686,6 +6697,9 @@ template <typename A> break; } } + crate::AddressSpace::TaskPayload => { + unimplemented!() + } crate::AddressSpace::Function | crate::AddressSpace::Private | crate::AddressSpace::WorkGroup => {} @@ -7683,7 +7697,7 @@ mod workgroup_mem_init { fun_info: &valid::FunctionInfo, ) -> bool { options.zero_initialize_workgroup_memory - && ep.stage == crate::ShaderStage::Compute + && ep.stage.compute_like() && module.global_variables.iter().any(|(handle, var)| { !fun_info[handle].is_empty() && var.space == crate::AddressSpace::WorkGroup }) diff --git a/third_party/rust/naga/src/back/pipeline_constants.rs b/third_party/rust/naga/src/back/pipeline_constants.rs @@ -39,6 +39,8 @@ pub enum PipelineConstantError { ValidationError(#[from] WithSpan<ValidationError>), #[error("workgroup_size override isn't strictly positive")] NegativeWorkgroupSize, + #[error("max vertices or max primitives is negative")] + NegativeMeshOutputMax, } /// Compact `module` and replace all overrides with constants. @@ -243,6 +245,7 @@ pub fn process_overrides<'a>( for ep in entry_points.iter_mut() { process_function(&mut module, &override_map, &mut layouter, &mut ep.function)?; process_workgroup_size_override(&mut module, &adjusted_global_expressions, ep)?; + process_mesh_shader_overrides(&mut module, &adjusted_global_expressions, ep)?; } module.entry_points = entry_points; module.overrides = overrides; @@ -296,6 +299,28 @@ fn process_workgroup_size_override( Ok(()) } +fn process_mesh_shader_overrides( + module: &mut Module, + adjusted_global_expressions: &HandleVec<Expression, Handle<Expression>>, + ep: &mut crate::EntryPoint, +) -> Result<(), PipelineConstantError> { + if let Some(ref mut mesh_info) = ep.mesh_info { + if let Some(r#override) = mesh_info.max_vertices_override { + mesh_info.max_vertices = module + .to_ctx() + .eval_expr_to_u32(adjusted_global_expressions[r#override]) + .map_err(|_| PipelineConstantError::NegativeMeshOutputMax)?; + } + if let Some(r#override) = mesh_info.max_primitives_override { + mesh_info.max_primitives = module + .to_ctx() + .eval_expr_to_u32(adjusted_global_expressions[r#override]) + .map_err(|_| PipelineConstantError::NegativeMeshOutputMax)?; + } + } + Ok(()) +} + /// Add a [`Constant`] to `module` for the override `old_h`. /// /// Add the new `Constant` to `override_map` and `adjusted_constant_initializers`. @@ -835,6 +860,26 @@ 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 @@ -3543,6 +3543,7 @@ impl BlockContext<'_> { } _ => unimplemented!(), }; + let mut cas_instr = Instruction::new(spirv::Op::AtomicCompareExchange); cas_instr.set_type(scalar_type_id); cas_instr.set_result(cas_result_id); @@ -3654,6 +3655,7 @@ impl BlockContext<'_> { } => { self.write_subgroup_gather(mode, argument, result, &mut block)?; } + Statement::MeshFunction(_) => unreachable!(), } } diff --git a/third_party/rust/naga/src/back/spv/helpers.rs b/third_party/rust/naga/src/back/spv/helpers.rs @@ -54,6 +54,7 @@ pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::Stor crate::AddressSpace::Uniform => spirv::StorageClass::Uniform, crate::AddressSpace::WorkGroup => spirv::StorageClass::Workgroup, crate::AddressSpace::PushConstant => spirv::StorageClass::PushConstant, + crate::AddressSpace::TaskPayload => unreachable!(), } } @@ -79,11 +80,10 @@ impl crate::AddressSpace { self, ) -> (spirv::MemorySemantics, spirv::Scope) { match self { - Self::Storage { .. } => (spirv::MemorySemantics::UNIFORM_MEMORY, spirv::Scope::Device), - Self::WorkGroup => ( - spirv::MemorySemantics::WORKGROUP_MEMORY, - spirv::Scope::Workgroup, - ), + Self::Storage { .. } => (spirv::MemorySemantics::empty(), spirv::Scope::Device), + Self::WorkGroup => (spirv::MemorySemantics::empty(), spirv::Scope::Workgroup), + Self::Uniform => (spirv::MemorySemantics::empty(), spirv::Scope::Device), + Self::Handle => (spirv::MemorySemantics::empty(), spirv::Scope::Device), _ => (spirv::MemorySemantics::empty(), spirv::Scope::Invocation), } } diff --git a/third_party/rust/naga/src/back/spv/writer.rs b/third_party/rust/naga/src/back/spv/writer.rs @@ -1094,7 +1094,10 @@ impl Writer { super::ZeroInitializeWorkgroupMemoryMode::Polyfill, Some( ref mut interface @ FunctionInterface { - stage: crate::ShaderStage::Compute, + stage: + crate::ShaderStage::Compute + | crate::ShaderStage::Mesh + | crate::ShaderStage::Task, .. }, ), @@ -1991,6 +1994,7 @@ impl Writer { interpolation, sampling, blend_src, + per_primitive: _, } => { self.decorate(id, Decoration::Location, &[location]); @@ -2089,6 +2093,14 @@ impl Writer { )?; BuiltIn::PrimitiveId } + Bi::Barycentric => { + self.require_any( + "`barycentric` built-in", + &[spirv::Capability::FragmentBarycentricKHR], + )?; + self.use_extension("SPV_KHR_fragment_shader_barycentric"); + BuiltIn::BaryCoordKHR + } Bi::SampleIndex => { self.require_any( "`sample_index` built-in", @@ -2140,6 +2152,11 @@ impl Writer { )?; BuiltIn::SubgroupLocalInvocationId } + Bi::MeshTaskSize + | Bi::CullPrimitive + | Bi::PointIndex + | Bi::LineIndices + | Bi::TriangleIndices => unreachable!(), }; self.decorate(id, Decoration::BuiltIn, &[built_in as u32]); diff --git a/third_party/rust/naga/src/back/wgsl/writer.rs b/third_party/rust/naga/src/back/wgsl/writer.rs @@ -207,7 +207,7 @@ impl<W: Write> Writer<W> { Attribute::Stage(ShaderStage::Compute), Attribute::WorkGroupSize(ep.workgroup_size), ], - ShaderStage::Task | ShaderStage::Mesh => unreachable!(), + ShaderStage::Mesh | ShaderStage::Task => unreachable!(), }; self.write_attributes(&attributes)?; @@ -856,6 +856,7 @@ 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(); @@ -1822,6 +1823,7 @@ fn map_binding_to_attribute(binding: &crate::Binding) -> Vec<Attribute> { interpolation, sampling, blend_src: None, + per_primitive: _, } => vec![ Attribute::Location(location), Attribute::Interpolate(interpolation, sampling), @@ -1831,6 +1833,7 @@ fn map_binding_to_attribute(binding: &crate::Binding) -> Vec<Attribute> { interpolation, sampling, blend_src: Some(blend_src), + per_primitive: _, } => vec![ Attribute::Location(location), Attribute::BlendSrc(blend_src), diff --git a/third_party/rust/naga/src/common/wgsl/to_wgsl.rs b/third_party/rust/naga/src/common/wgsl/to_wgsl.rs @@ -169,6 +169,7 @@ impl TryToWgsl for crate::BuiltIn { Bi::FragDepth => "frag_depth", Bi::FrontFacing => "front_facing", Bi::PrimitiveIndex => "primitive_index", + Bi::Barycentric => "barycentric", Bi::SampleIndex => "sample_index", Bi::SampleMask => "sample_mask", Bi::GlobalInvocationId => "global_invocation_id", @@ -188,7 +189,12 @@ impl TryToWgsl for crate::BuiltIn { | Bi::PointSize | Bi::DrawID | Bi::PointCoord - | Bi::WorkGroupSize => return None, + | Bi::WorkGroupSize + | Bi::CullPrimitive + | Bi::TriangleIndices + | Bi::LineIndices + | Bi::MeshTaskSize + | Bi::PointIndex => return None, }) } } @@ -352,6 +358,7 @@ pub const fn address_space_str( As::WorkGroup => "workgroup", As::Handle => return (None, None), As::Function => "function", + As::TaskPayload => return (None, None), }), None, ) diff --git a/third_party/rust/naga/src/compact/mod.rs b/third_party/rust/naga/src/compact/mod.rs @@ -221,6 +221,45 @@ 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, @@ -342,6 +381,23 @@ pub fn compact(module: &mut crate::Module, keep_unused: KeepUnused) { &module_map, &mut reused_named_expressions, ); + if let Some(ref mut task_payload) = entry.task_payload { + module_map.globals.adjust(task_payload); + } + if let Some(ref mut mesh_info) = entry.mesh_info { + module_map.types.adjust(&mut mesh_info.vertex_output_type); + module_map + .types + .adjust(&mut mesh_info.primitive_output_type); + if let Some(ref mut max_vertices_override) = mesh_info.max_vertices_override { + module_map.global_expressions.adjust(max_vertices_override); + } + if let Some(ref mut max_primitives_override) = mesh_info.max_primitives_override { + module_map + .global_expressions + .adjust(max_primitives_override); + } + } } } diff --git a/third_party/rust/naga/src/compact/statements.rs b/third_party/rust/naga/src/compact/statements.rs @@ -117,6 +117,20 @@ 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); @@ -335,6 +349,26 @@ 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/glsl/functions.rs b/third_party/rust/naga/src/front/glsl/functions.rs @@ -1377,6 +1377,8 @@ impl Frontend { result: ty.map(|ty| FunctionResult { ty, binding: None }), ..Default::default() }, + mesh_info: None, + task_payload: None, }); Ok(()) @@ -1446,6 +1448,7 @@ impl Context<'_> { interpolation, sampling: None, blend_src: None, + per_primitive: false, }; location += 1; @@ -1482,6 +1485,7 @@ impl Context<'_> { interpolation, sampling: None, blend_src: None, + per_primitive: false, }; location += 1; binding diff --git a/third_party/rust/naga/src/front/glsl/mod.rs b/third_party/rust/naga/src/front/glsl/mod.rs @@ -107,7 +107,7 @@ impl ShaderMetadata { self.version = 0; self.profile = Profile::Core; self.stage = stage; - self.workgroup_size = [u32::from(stage == ShaderStage::Compute); 3]; + self.workgroup_size = [u32::from(stage.compute_like()); 3]; self.early_fragment_tests = false; self.extensions.clear(); } diff --git a/third_party/rust/naga/src/front/glsl/variables.rs b/third_party/rust/naga/src/front/glsl/variables.rs @@ -200,6 +200,7 @@ impl Frontend { "gl_BaseVertex" => BuiltIn::BaseVertex, "gl_BaseInstance" => BuiltIn::BaseInstance, "gl_PrimitiveID" => BuiltIn::PrimitiveIndex, + "gl_BaryCoordEXT" => BuiltIn::Barycentric, "gl_InstanceIndex" => BuiltIn::InstanceIndex, "gl_VertexIndex" => BuiltIn::VertexIndex, "gl_SampleID" => BuiltIn::SampleIndex, @@ -465,6 +466,7 @@ impl Frontend { interpolation, sampling, blend_src, + per_primitive: false, }, handle, storage, diff --git a/third_party/rust/naga/src/front/interpolator.rs b/third_party/rust/naga/src/front/interpolator.rs @@ -44,6 +44,7 @@ impl crate::Binding { interpolation: ref mut interpolation @ None, ref mut sampling, blend_src: _, + per_primitive: _, } = *self { match ty.scalar_kind() { diff --git a/third_party/rust/naga/src/front/spv/convert.rs b/third_party/rust/naga/src/front/spv/convert.rs @@ -147,6 +147,7 @@ pub(super) fn map_builtin(word: spirv::Word, invariant: bool) -> Result<crate::B Some(Bi::PointCoord) => crate::BuiltIn::PointCoord, Some(Bi::FrontFacing) => crate::BuiltIn::FrontFacing, Some(Bi::PrimitiveId) => crate::BuiltIn::PrimitiveIndex, + Some(Bi::BaryCoordKHR) => crate::BuiltIn::Barycentric, Some(Bi::SampleId) => crate::BuiltIn::SampleIndex, Some(Bi::SampleMask) => crate::BuiltIn::SampleMask, // compute diff --git a/third_party/rust/naga/src/front/spv/function.rs b/third_party/rust/naga/src/front/spv/function.rs @@ -596,6 +596,8 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> { workgroup_size: ep.workgroup_size, workgroup_size_overrides: None, function, + mesh_info: None, + task_payload: None, }); Ok(()) diff --git a/third_party/rust/naga/src/front/spv/mod.rs b/third_party/rust/naga/src/front/spv/mod.rs @@ -83,6 +83,7 @@ pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[ spirv::Capability::GroupNonUniformShuffleRelative, spirv::Capability::RuntimeDescriptorArray, spirv::Capability::StorageImageMultisample, + spirv::Capability::FragmentBarycentricKHR, // tricky ones spirv::Capability::UniformBufferArrayDynamicIndexing, spirv::Capability::StorageBufferArrayDynamicIndexing, @@ -265,6 +266,7 @@ impl Decoration { interpolation, sampling, blend_src: None, + per_primitive: false, }), _ => Err(Error::MissingDecoration(spirv::Decoration::Location)), } @@ -4659,6 +4661,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> { | S::Atomic { .. } | S::ImageAtomic { .. } | S::RayQuery { .. } + | S::MeshFunction(..) | S::SubgroupBallot { .. } | S::SubgroupCollectiveOperation { .. } | S::SubgroupGather { .. } => {} @@ -4940,6 +4943,8 @@ impl<I: Iterator<Item = u32>> Frontend<I> { spirv::ExecutionModel::Vertex => crate::ShaderStage::Vertex, spirv::ExecutionModel::Fragment => crate::ShaderStage::Fragment, spirv::ExecutionModel::GLCompute => crate::ShaderStage::Compute, + spirv::ExecutionModel::TaskEXT => crate::ShaderStage::Task, + spirv::ExecutionModel::MeshEXT => crate::ShaderStage::Mesh, _ => return Err(Error::UnsupportedExecutionModel(exec_model as u32)), }, name, @@ -6038,6 +6043,10 @@ impl<I: Iterator<Item = u32>> Frontend<I> { size: crate::VectorSize::Tri, scalar: crate::Scalar::U32, }), + crate::BuiltIn::Barycentric => Some(crate::TypeInner::Vector { + size: crate::VectorSize::Tri, + scalar: crate::Scalar::F32, + }), _ => None, }; if let (Some(inner), Some(crate::ScalarKind::Sint)) = diff --git a/third_party/rust/naga/src/front/wgsl/lower/mod.rs b/third_party/rust/naga/src/front/wgsl/lower/mod.rs @@ -1527,6 +1527,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { workgroup_size, workgroup_size_overrides, function, + mesh_info: None, + task_payload: None, }); Ok(LoweredGlobalDecl::EntryPoint( ctx.module.entry_points.len() - 1, @@ -4069,6 +4071,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { interpolation, sampling, blend_src, + per_primitive: false, }; binding.apply_default_interpolation(&ctx.module.types[ty].inner); Some(binding) diff --git a/third_party/rust/naga/src/front/wgsl/parse/conv.rs b/third_party/rust/naga/src/front/wgsl/parse/conv.rs @@ -36,6 +36,7 @@ pub fn map_built_in( "front_facing" => crate::BuiltIn::FrontFacing, "frag_depth" => crate::BuiltIn::FragDepth, "primitive_index" => crate::BuiltIn::PrimitiveIndex, + "barycentric" => crate::BuiltIn::Barycentric, "sample_index" => crate::BuiltIn::SampleIndex, "sample_mask" => crate::BuiltIn::SampleMask, // compute diff --git a/third_party/rust/naga/src/ir/mod.rs b/third_party/rust/naga/src/ir/mod.rs @@ -320,13 +320,21 @@ pub enum ConservativeDepth { #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] -#[allow(missing_docs)] // The names are self evident pub enum ShaderStage { + /// A vertex shader, in a render pipeline. Vertex, - Fragment, - Compute, + + /// A task shader, in a mesh render pipeline. Task, + + /// A mesh shader, in a mesh render pipeline. Mesh, + + /// A fragment shader, in a render pipeline. + Fragment, + + /// Compute pipeline shader. + Compute, } /// Addressing space of variables. @@ -363,6 +371,8 @@ pub enum AddressSpace { /// /// [`SHADER_FLOAT16`]: crate::valid::Capabilities::SHADER_FLOAT16 PushConstant, + /// Task shader to mesh shader payload + TaskPayload, } /// Built-in inputs and outputs. @@ -371,36 +381,75 @@ pub enum AddressSpace { #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum BuiltIn { + /// Written in vertex/mesh shaders, read in fragment shaders Position { invariant: bool }, + /// Read in task, mesh, vertex, and fragment shaders ViewIndex, - // vertex + + /// Read in vertex shaders BaseInstance, + /// Read in vertex shaders BaseVertex, + /// Written in vertex & mesh shaders ClipDistance, + /// Written in vertex & mesh shaders CullDistance, + /// Read in vertex shaders InstanceIndex, + /// Written in vertex & mesh shaders PointSize, + /// Read in vertex shaders VertexIndex, + /// Read in vertex & task shaders, or mesh shaders in pipelines without task shaders DrawID, - // fragment + + /// Written in fragment shaders FragDepth, + /// Read in fragment shaders PointCoord, + /// Read in fragment shaders FrontFacing, + /// Read in fragment shaders, in the future may written in mesh shaders PrimitiveIndex, + /// Read in fragment shaders + Barycentric, + /// Read in fragment shaders SampleIndex, + /// Read or written in fragment shaders SampleMask, - // compute + + /// Read in compute, task, and mesh shaders GlobalInvocationId, + /// Read in compute, task, and mesh shaders LocalInvocationId, + /// Read in compute, task, and mesh shaders LocalInvocationIndex, + /// Read in compute, task, and mesh shaders WorkGroupId, + /// Read in compute, task, and mesh shaders WorkGroupSize, + /// Read in compute, task, and mesh shaders NumWorkGroups, - // subgroup + + /// Read in compute, task, and mesh shaders NumSubgroups, + /// Read in compute, task, and mesh shaders SubgroupId, + /// Read in compute, fragment, task, and mesh shaders SubgroupSize, + /// Read in compute, fragment, task, and mesh shaders SubgroupInvocationId, + + /// Written in task shaders + MeshTaskSize, + /// Written in mesh shaders + CullPrimitive, + /// Written in mesh shaders + PointIndex, + /// Written in mesh shaders + LineIndices, + /// Written in mesh shaders + TriangleIndices, } /// Number of bytes per scalar. @@ -945,6 +994,9 @@ pub enum Binding { /// Indexed location. /// + /// This is a value passed to a [`Fragment`] shader from a [`Vertex`] or + /// [`Mesh`] shader. + /// /// Values passed from the [`Vertex`] stage to the [`Fragment`] stage must /// have their `interpolation` defaulted (i.e. not `None`) by the front end /// as appropriate for that language. @@ -958,14 +1010,30 @@ pub enum Binding { /// interpolation must be `Flat`. /// /// [`Vertex`]: crate::ShaderStage::Vertex + /// [`Mesh`]: crate::ShaderStage::Mesh /// [`Fragment`]: crate::ShaderStage::Fragment Location { location: u32, interpolation: Option<Interpolation>, sampling: Option<Sampling>, + /// Optional `blend_src` index used for dual source blending. /// See <https://www.w3.org/TR/WGSL/#attribute-blend_src> blend_src: Option<u32>, + + /// Whether the binding is a per-primitive binding for use with mesh shaders. + /// + /// This must be `true` if this binding is a mesh shader primitive output, or such + /// an output's corresponding fragment shader input. It must be `false` otherwise. + /// + /// A stage's outputs must all have unique `location` numbers, regardless of + /// whether they are per-primitive; a mesh shader's per-vertex and per-primitive + /// outputs share the same location numbering space. + /// + /// Per-primitive values are not interpolated at all and are not dependent on the + /// vertices or pixel location. For example, it may be used to store a + /// non-interpolated normal vector. + per_primitive: bool, }, } @@ -1724,10 +1792,12 @@ pub enum Expression { query: Handle<Expression>, committed: bool, }, + /// Result of a [`SubgroupBallot`] statement. /// /// [`SubgroupBallot`]: Statement::SubgroupBallot SubgroupBallotResult, + /// Result of a [`SubgroupCollectiveOperation`] or [`SubgroupGather`] statement. /// /// [`SubgroupCollectiveOperation`]: Statement::SubgroupCollectiveOperation @@ -2141,6 +2211,8 @@ 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. @@ -2314,6 +2386,12 @@ pub struct EntryPoint { pub workgroup_size_overrides: Option<[Option<Handle<Expression>>; 3]>, /// The entrance function. pub function: Function, + /// Information for [`Mesh`] shaders. + /// + /// [`Mesh`]: ShaderStage::Mesh + pub mesh_info: Option<MeshStageInfo>, + /// The unique global variable used as a task payload from task shader to mesh shader + pub task_payload: Option<Handle<GlobalVariable>>, } /// Return types predeclared for the frexp, modf, and atomicCompareExchangeWeak built-in functions. @@ -2490,6 +2568,66 @@ pub struct DocComments { pub module: Vec<String>, } +/// The output topology for a mesh shader. Note that mesh shaders don't allow things like triangle-strips. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub enum MeshOutputTopology { + /// Outputs individual vertices to be rendered as points. + Points, + /// Outputs groups of 2 vertices to be renderedas lines . + Lines, + /// Outputs groups of 3 vertices to be rendered as triangles. + Triangles, +} + +/// Information specific to mesh shader entry points. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +#[allow(dead_code)] +pub struct MeshStageInfo { + /// The type of primitive outputted. + pub topology: MeshOutputTopology, + /// The maximum number of vertices a mesh shader may output. + pub max_vertices: u32, + /// If pipeline constants are used, the expressions that override `max_vertices` + pub max_vertices_override: Option<Handle<Expression>>, + /// The maximum number of primitives a mesh shader may output. + pub max_primitives: u32, + /// If pipeline constants are used, the expressions that override `max_primitives` + pub max_primitives_override: Option<Handle<Expression>>, + /// The type used by vertex outputs, i.e. what is passed to `setVertex`. + 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>, + }, +} + /// Shader module. /// /// A module is a set of constants, global variables and functions, as well as diff --git a/third_party/rust/naga/src/proc/mod.rs b/third_party/rust/naga/src/proc/mod.rs @@ -179,6 +179,9 @@ impl super::AddressSpace { crate::AddressSpace::Storage { access } => access, crate::AddressSpace::Handle => Sa::LOAD, crate::AddressSpace::PushConstant => Sa::LOAD, + // TaskPayload isn't always writable, but this is checked for elsewhere, + // when not using multiple payloads and matching the entry payload is checked. + crate::AddressSpace::TaskPayload => Sa::LOAD | Sa::STORE, } } } @@ -628,6 +631,15 @@ pub fn flatten_compose<'arenas>( .take(size) } +impl super::ShaderStage { + pub const fn compute_like(self) -> bool { + match self { + Self::Vertex | Self::Fragment => false, + Self::Compute | Self::Task | Self::Mesh => true, + } + } +} + #[test] fn test_matrix_size() { let module = crate::Module::default(); diff --git a/third_party/rust/naga/src/proc/terminator.rs b/third_party/rust/naga/src/proc/terminator.rs @@ -36,6 +36,7 @@ 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,6 +85,25 @@ 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 { @@ -302,6 +321,9 @@ 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 { @@ -372,6 +394,22 @@ impl FunctionInfo { info.uniformity.non_uniform_result } + /// Note an entry point's use of `global` not recorded by [`ModuleInfo::process_function`]. + /// + /// Most global variable usage should be recorded via [`add_ref_impl`] in the process + /// of expression behavior analysis by [`ModuleInfo::process_function`]. But that code + /// has no access to entrypoint-specific information, so interface analysis uses this + /// function to record global uses there (like task shader payloads). + /// + /// [`add_ref_impl`]: Self::add_ref_impl + pub(super) fn insert_global_use( + &mut self, + global_use: GlobalUse, + global: Handle<crate::GlobalVariable>, + ) { + self.global_uses[global.index()] |= global_use; + } + /// Record a use of `expr` for its value. /// /// This is used for almost all expression references. Anything @@ -482,6 +520,9 @@ 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 { @@ -635,7 +676,8 @@ impl FunctionInfo { // local data is non-uniform As::Function | As::Private => false, // workgroup memory is exclusively accessed by the group - As::WorkGroup => true, + // task payload memory is very similar to workgroup memory + As::WorkGroup | As::TaskPayload => true, // uniform data As::Uniform | As::PushConstant => true, // storage data is only uniform when read-only @@ -1113,6 +1155,36 @@ 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, @@ -1158,6 +1230,72 @@ 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 { @@ -1193,6 +1331,7 @@ 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); @@ -1326,6 +1465,7 @@ 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 @@ -217,6 +217,14 @@ pub enum FunctionError { EmitResult(Handle<crate::Expression>), #[error("Expression not visited by the appropriate statement")] UnvisitedExpression(Handle<crate::Expression>), + #[error("Expression {0:?} in mesh shader intrinsic call should be `u32` (is the expression a signed integer?)")] + InvalidMeshFunctionCall(Handle<crate::Expression>), + #[error("Mesh output types differ from {0:?} to {1:?}")] + ConflictingMeshOutputTypes(Handle<crate::Expression>, Handle<crate::Expression>), + #[error("Task payload variables differ from {0:?} to {1:?}")] + ConflictingTaskPayloadVariables(Handle<crate::Expression>, Handle<crate::Expression>), + #[error("Mesh shader output at {0:?} is not a user-defined struct")] + InvalidMeshShaderOutputType(Handle<crate::Expression>), } bitflags::bitflags! { @@ -1539,6 +1547,41 @@ 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 @@ -233,6 +233,20 @@ impl super::Validator { validate_const_expr(size)?; } } + if let Some(task_payload) = entry_point.task_payload { + Self::validate_global_variable_handle(task_payload, global_variables)?; + } + if let Some(ref mesh_info) = entry_point.mesh_info { + validate_type(mesh_info.vertex_output_type)?; + validate_type(mesh_info.primitive_output_type)?; + for ov in mesh_info + .max_vertices_override + .iter() + .chain(mesh_info.max_primitives_override.iter()) + { + validate_const_expr(*ov)?; + } + } } for (function_handle, function) in functions.iter() { @@ -801,6 +815,22 @@ 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 @@ -43,6 +43,8 @@ pub enum GlobalVariableError { StorageAddressSpaceWriteOnlyNotSupported, #[error("Type is not valid for use as a push constant")] InvalidPushConstantType(#[source] PushConstantError), + #[error("Task payload must not be zero-sized")] + ZeroSizedTaskPayload, } #[derive(Clone, Debug, thiserror::Error)] @@ -92,6 +94,12 @@ pub enum VaryingError { }, #[error("Workgroup size is multi dimensional, `@builtin(subgroup_id)` and `@builtin(subgroup_invocation_id)` are not supported.")] InvalidMultiDimensionalSubgroupBuiltIn, + #[error("The `@per_primitive` attribute can only be used in fragment shader inputs or mesh shader primitive outputs")] + 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)] @@ -123,6 +131,34 @@ pub enum EntryPointError { InvalidIntegerInterpolation { location: u32 }, #[error(transparent)] Function(#[from] FunctionError), + #[error("mesh shader entry point missing mesh shader attributes")] + ExpectedMeshShaderAttributes, + #[error("Non mesh shader entry point cannot have mesh shader attributes")] + UnexpectedMeshShaderAttributes, + #[error("Non mesh/task shader entry point cannot have task payload attribute")] + UnexpectedTaskPayload, + #[error("Task payload must be declared with `var<task_payload>`")] + 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." + )] + MeshShaderCapabilityDisabled, } fn storage_usage(access: crate::StorageAccess) -> GlobalUse { @@ -139,6 +175,13 @@ fn storage_usage(access: crate::StorageAccess) -> GlobalUse { storage_usage } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum MeshOutputType { + None, + VertexOutput, + PrimitiveOutput, +} + struct VaryingContext<'a> { stage: crate::ShaderStage, output: bool, @@ -149,6 +192,8 @@ struct VaryingContext<'a> { built_ins: &'a mut crate::FastHashSet<crate::BuiltIn>, capabilities: Capabilities, flags: super::ValidationFlags, + mesh_output_type: MeshOutputType, + has_task_payload: bool, } impl VaryingContext<'_> { @@ -180,6 +225,7 @@ impl VaryingContext<'_> { Bi::ClipDistance => Capabilities::CLIP_DISTANCE, Bi::CullDistance => Capabilities::CULL_DISTANCE, Bi::PrimitiveIndex => Capabilities::PRIMITIVE_INDEX, + Bi::Barycentric => Capabilities::SHADER_BARYCENTRICS, Bi::ViewIndex => Capabilities::MULTIVIEW, Bi::SampleIndex => Capabilities::MULTISAMPLED_SHADING, Bi::NumSubgroups @@ -201,16 +247,20 @@ impl VaryingContext<'_> { } let (visible, type_good) = match built_in { - Bi::BaseInstance - | Bi::BaseVertex - | Bi::InstanceIndex - | Bi::VertexIndex - | Bi::DrawID => ( + Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => ( self.stage == St::Vertex && !self.output, *ty_inner == Ti::Scalar(crate::Scalar::U32), ), + Bi::DrawID => ( + // Always allowed in task/vertex stage. Allowed in mesh stage if there is no task stage in the pipeline. + (self.stage == St::Vertex + || self.stage == St::Task + || (self.stage == St::Mesh && !self.has_task_payload)) + && !self.output, + *ty_inner == Ti::Scalar(crate::Scalar::U32), + ), Bi::ClipDistance | Bi::CullDistance => ( - self.stage == St::Vertex && self.output, + (self.stage == St::Vertex || self.stage == St::Mesh) && self.output, match *ty_inner { Ti::Array { base, size, .. } => { self.types[base].inner == Ti::Scalar(crate::Scalar::F32) @@ -223,7 +273,7 @@ impl VaryingContext<'_> { }, ), Bi::PointSize => ( - self.stage == St::Vertex && self.output, + (self.stage == St::Vertex || self.stage == St::Mesh) && self.output, *ty_inner == Ti::Scalar(crate::Scalar::F32), ), Bi::PointCoord => ( @@ -236,10 +286,9 @@ impl VaryingContext<'_> { ), Bi::Position { .. } => ( match self.stage { - St::Vertex => self.output, + St::Vertex | St::Mesh => self.output, St::Fragment => !self.output, - St::Compute => false, - St::Task | St::Mesh => unreachable!(), + St::Compute | St::Task => false, }, *ty_inner == Ti::Vector { @@ -249,11 +298,10 @@ impl VaryingContext<'_> { ), Bi::ViewIndex => ( match self.stage { - St::Vertex | St::Fragment => !self.output, + St::Vertex | St::Fragment | St::Task | St::Mesh => !self.output, St::Compute => false, - St::Task | St::Mesh => unreachable!(), }, - *ty_inner == Ti::Scalar(crate::Scalar::I32), + *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::FragDepth => ( self.stage == St::Fragment && self.output, @@ -267,6 +315,14 @@ impl VaryingContext<'_> { self.stage == St::Fragment && !self.output, *ty_inner == Ti::Scalar(crate::Scalar::U32), ), + Bi::Barycentric => ( + self.stage == St::Fragment && !self.output, + *ty_inner + == Ti::Vector { + size: Vs::Tri, + scalar: crate::Scalar::F32, + }, + ), Bi::SampleIndex => ( self.stage == St::Fragment && !self.output, *ty_inner == Ti::Scalar(crate::Scalar::U32), @@ -276,7 +332,7 @@ impl VaryingContext<'_> { *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::LocalInvocationIndex => ( - self.stage == St::Compute && !self.output, + self.stage.compute_like() && !self.output, *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::GlobalInvocationId @@ -284,7 +340,7 @@ impl VaryingContext<'_> { | Bi::WorkGroupId | Bi::WorkGroupSize | Bi::NumWorkGroups => ( - self.stage == St::Compute && !self.output, + self.stage.compute_like() && !self.output, *ty_inner == Ti::Vector { size: Vs::Tri, @@ -292,17 +348,48 @@ impl VaryingContext<'_> { }, ), Bi::NumSubgroups | Bi::SubgroupId => ( - self.stage == St::Compute && !self.output, + self.stage.compute_like() && !self.output, *ty_inner == Ti::Scalar(crate::Scalar::U32), ), Bi::SubgroupSize | Bi::SubgroupInvocationId => ( match self.stage { - St::Compute | St::Fragment => !self.output, + St::Compute | St::Fragment | St::Task | St::Mesh => !self.output, St::Vertex => false, - St::Task | St::Mesh => unreachable!(), }, *ty_inner == Ti::Scalar(crate::Scalar::U32), ), + Bi::CullPrimitive => ( + self.mesh_output_type == MeshOutputType::PrimitiveOutput, + *ty_inner == Ti::Scalar(crate::Scalar::BOOL), + ), + Bi::PointIndex => ( + self.mesh_output_type == MeshOutputType::PrimitiveOutput, + *ty_inner == Ti::Scalar(crate::Scalar::U32), + ), + Bi::LineIndices => ( + self.mesh_output_type == MeshOutputType::PrimitiveOutput, + *ty_inner + == Ti::Vector { + size: Vs::Bi, + scalar: crate::Scalar::U32, + }, + ), + Bi::TriangleIndices => ( + self.mesh_output_type == MeshOutputType::PrimitiveOutput, + *ty_inner + == Ti::Vector { + size: Vs::Tri, + scalar: crate::Scalar::U32, + }, + ), + Bi::MeshTaskSize => ( + self.stage == St::Task && self.output, + *ty_inner + == Ti::Vector { + size: Vs::Tri, + scalar: crate::Scalar::U32, + }, + ), }; if !visible { @@ -318,7 +405,11 @@ impl VaryingContext<'_> { interpolation, sampling, blend_src, + per_primitive, } => { + if per_primitive && !self.capabilities.contains(Capabilities::MESH_SHADER) { + return Err(VaryingError::PerPrimitiveNotAllowed); + } // Only IO-shareable types may be stored in locations. if !self.type_info[ty.index()] .flags @@ -327,6 +418,22 @@ impl VaryingContext<'_> { return Err(VaryingError::NotIOShareableType(ty)); } + // Check whether `per_primitive` is appropriate for this stage and direction. + if self.mesh_output_type == MeshOutputType::PrimitiveOutput { + // All mesh shader `Location` outputs must be `per_primitive`. + if !per_primitive { + return Err(VaryingError::MissingPerPrimitive); + } + } else if self.stage == crate::ShaderStage::Fragment && !self.output { + // Fragment stage inputs may be `per_primitive`. We'll only + // know if these are correct when the whole mesh pipeline is + // created and we're paired with a specific mesh or vertex + // shader. + } else if per_primitive { + // All other `Location` bindings must not be `per_primitive`. + return Err(VaryingError::InvalidPerPrimitive); + } + if let Some(blend_src) = blend_src { // `blend_src` is only valid if dual source blending was explicitly enabled, // see https://www.w3.org/TR/WGSL/#extension-dual_source_blending @@ -392,9 +499,9 @@ impl VaryingContext<'_> { let needs_interpolation = match self.stage { crate::ShaderStage::Vertex => self.output, - crate::ShaderStage::Fragment => !self.output, - crate::ShaderStage::Compute => false, - crate::ShaderStage::Task | crate::ShaderStage::Mesh => unreachable!(), + crate::ShaderStage::Fragment => !self.output && !per_primitive, + crate::ShaderStage::Compute | crate::ShaderStage::Task => false, + crate::ShaderStage::Mesh => self.output, }; // It doesn't make sense to specify a sampling when `interpolation` is `Flat`, but @@ -596,6 +703,14 @@ impl super::Validator { false, ), crate::AddressSpace::WorkGroup => (TypeFlags::DATA | TypeFlags::SIZED, false), + crate::AddressSpace::TaskPayload => { + if !self.capabilities.contains(Capabilities::MESH_SHADER) { + return Err(GlobalVariableError::UnsupportedCapability( + Capabilities::MESH_SHADER, + )); + } + (TypeFlags::DATA | TypeFlags::SIZED, false) + } crate::AddressSpace::PushConstant => { if !self.capabilities.contains(Capabilities::PUSH_CONSTANT) { return Err(GlobalVariableError::UnsupportedCapability( @@ -628,6 +743,14 @@ impl super::Validator { } } + if var.space == crate::AddressSpace::TaskPayload { + let ty = &gctx.types[var.ty].inner; + // HLSL doesn't allow zero sized payloads. + if ty.try_size(gctx) == Some(0) { + return Err(GlobalVariableError::ZeroSizedTaskPayload); + } + } + if let Some(init) = var.init { match var.space { crate::AddressSpace::Private | crate::AddressSpace::Function => {} @@ -651,12 +774,72 @@ impl super::Validator { Ok(()) } + /// Validate the mesh shader output type `ty`, used as `mesh_output_type`. + fn validate_mesh_output_type( + &mut self, + ep: &crate::EntryPoint, + module: &crate::Module, + ty: Handle<crate::Type>, + mesh_output_type: MeshOutputType, + ) -> Result<(), WithSpan<EntryPointError>> { + if !matches!(module.types[ty].inner, crate::TypeInner::Struct { .. }) { + return Err(EntryPointError::InvalidMeshOutputType.with_span_handle(ty, &module.types)); + } + let mut result_built_ins = crate::FastHashSet::default(); + let mut ctx = VaryingContext { + stage: ep.stage, + output: true, + types: &module.types, + type_info: &self.types, + location_mask: &mut self.location_mask, + blend_src_mask: &mut self.blend_src_mask, + built_ins: &mut result_built_ins, + capabilities: self.capabilities, + flags: self.flags, + mesh_output_type, + has_task_payload: ep.task_payload.is_some(), + }; + ctx.validate(ep, ty, None) + .map_err_inner(|e| EntryPointError::Result(e).with_span())?; + if mesh_output_type == MeshOutputType::PrimitiveOutput { + let mut num_indices_builtins = 0; + if result_built_ins.contains(&crate::BuiltIn::PointIndex) { + num_indices_builtins += 1; + } + if result_built_ins.contains(&crate::BuiltIn::LineIndices) { + num_indices_builtins += 1; + } + if result_built_ins.contains(&crate::BuiltIn::TriangleIndices) { + num_indices_builtins += 1; + } + if num_indices_builtins != 1 { + return Err(EntryPointError::InvalidMeshPrimitiveOutputType + .with_span_handle(ty, &module.types)); + } + } else if mesh_output_type == MeshOutputType::VertexOutput + && !result_built_ins.contains(&crate::BuiltIn::Position { invariant: false }) + { + return Err( + EntryPointError::MissingVertexOutputPosition.with_span_handle(ty, &module.types) + ); + } + + Ok(()) + } + pub(super) fn validate_entry_point( &mut self, ep: &crate::EntryPoint, module: &crate::Module, mod_info: &ModuleInfo, ) -> Result<FunctionInfo, WithSpan<EntryPointError>> { + if matches!( + ep.stage, + crate::ShaderStage::Task | crate::ShaderStage::Mesh + ) && !self.capabilities.contains(Capabilities::MESH_SHADER) + { + return Err(EntryPointError::MeshShaderCapabilityDisabled.with_span()); + } if ep.early_depth_test.is_some() { let required = Capabilities::EARLY_DEPTH_TEST; if !self.capabilities.contains(required) { @@ -671,7 +854,7 @@ impl super::Validator { } } - if ep.stage == crate::ShaderStage::Compute { + if ep.stage.compute_like() { if ep .workgroup_size .iter() @@ -683,10 +866,54 @@ impl super::Validator { return Err(EntryPointError::UnexpectedWorkgroupSize.with_span()); } + match (ep.stage, &ep.mesh_info) { + (crate::ShaderStage::Mesh, &None) => { + return Err(EntryPointError::ExpectedMeshShaderAttributes.with_span()); + } + (_, &Some(_)) => { + return Err(EntryPointError::UnexpectedMeshShaderAttributes.with_span()); + } + (_, _) => {} + } + let mut info = self .validate_function(&ep.function, module, mod_info, true) .map_err(WithSpan::into_other)?; + // Validate the task shader payload. + match ep.stage { + // Task shaders must produce a payload. + crate::ShaderStage::Task => { + let Some(handle) = ep.task_payload else { + return Err(EntryPointError::ExpectedTaskPayload.with_span()); + }; + if module.global_variables[handle].space != crate::AddressSpace::TaskPayload { + return Err(EntryPointError::TaskPayloadWrongAddressSpace + .with_span_handle(handle, &module.global_variables)); + } + info.insert_global_use(GlobalUse::READ | GlobalUse::WRITE, handle); + } + + // Mesh shaders may accept a payload. + crate::ShaderStage::Mesh => { + if let Some(handle) = ep.task_payload { + if module.global_variables[handle].space != crate::AddressSpace::TaskPayload { + return Err(EntryPointError::TaskPayloadWrongAddressSpace + .with_span_handle(handle, &module.global_variables)); + } + info.insert_global_use(GlobalUse::READ, handle); + } + } + + // Other stages must not have a payload. + _ => { + if let Some(handle) = ep.task_payload { + return Err(EntryPointError::UnexpectedTaskPayload + .with_span_handle(handle, &module.global_variables)); + } + } + } + { use super::ShaderStages; @@ -694,7 +921,8 @@ impl super::Validator { crate::ShaderStage::Vertex => ShaderStages::VERTEX, crate::ShaderStage::Fragment => ShaderStages::FRAGMENT, crate::ShaderStage::Compute => ShaderStages::COMPUTE, - crate::ShaderStage::Task | crate::ShaderStage::Mesh => unreachable!(), + crate::ShaderStage::Mesh => ShaderStages::MESH, + crate::ShaderStage::Task => ShaderStages::TASK, }; if !info.available_stages.contains(stage_bit) { @@ -716,6 +944,8 @@ impl super::Validator { built_ins: &mut argument_built_ins, capabilities: self.capabilities, flags: self.flags, + mesh_output_type: MeshOutputType::None, + has_task_payload: ep.task_payload.is_some(), }; ctx.validate(ep, fa.ty, fa.binding.as_ref()) .map_err_inner(|e| EntryPointError::Argument(index as u32, e).with_span())?; @@ -734,6 +964,8 @@ impl super::Validator { built_ins: &mut result_built_ins, capabilities: self.capabilities, flags: self.flags, + mesh_output_type: MeshOutputType::None, + has_task_payload: ep.task_payload.is_some(), }; ctx.validate(ep, fr.ty, fr.binding.as_ref()) .map_err_inner(|e| EntryPointError::Result(e).with_span())?; @@ -742,11 +974,25 @@ impl super::Validator { { return Err(EntryPointError::MissingVertexOutputPosition.with_span()); } + if ep.stage == crate::ShaderStage::Mesh { + return Err(EntryPointError::UnexpectedMeshShaderEntryResult.with_span()); + } + // Task shaders must have a single `MeshTaskSize` output, and nothing else. + if ep.stage == crate::ShaderStage::Task { + let ok = result_built_ins.contains(&crate::BuiltIn::MeshTaskSize) + && result_built_ins.len() == 1 + && self.location_mask.is_empty(); + if !ok { + return Err(EntryPointError::WrongTaskShaderEntryResult.with_span()); + } + } if !self.blend_src_mask.is_empty() { info.dual_source_blending = true; } } else if ep.stage == crate::ShaderStage::Vertex { return Err(EntryPointError::MissingVertexOutputPosition.with_span()); + } else if ep.stage == crate::ShaderStage::Task { + return Err(EntryPointError::WrongTaskShaderEntryResult.with_span()); } { @@ -771,6 +1017,13 @@ impl super::Validator { continue; } + if var.space == crate::AddressSpace::TaskPayload { + if ep.task_payload != Some(var_handle) { + return Err(EntryPointError::WrongTaskPayloadUsed + .with_span_handle(var_handle, &module.global_variables)); + } + } + let allowed_usage = match var.space { crate::AddressSpace::Function => unreachable!(), crate::AddressSpace::Uniform => GlobalUse::READ | GlobalUse::QUERY, @@ -792,6 +1045,15 @@ impl super::Validator { crate::AddressSpace::Private | crate::AddressSpace::WorkGroup => { GlobalUse::READ | GlobalUse::WRITE | GlobalUse::QUERY } + crate::AddressSpace::TaskPayload => { + GlobalUse::READ + | GlobalUse::QUERY + | if ep.stage == crate::ShaderStage::Task { + GlobalUse::WRITE + } else { + GlobalUse::empty() + } + } crate::AddressSpace::PushConstant => GlobalUse::READ, }; if !allowed_usage.contains(usage) { @@ -811,6 +1073,46 @@ 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 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)); + } + } + + self.validate_mesh_output_type( + ep, + module, + mesh_info.vertex_output_type, + MeshOutputType::VertexOutput, + )?; + self.validate_mesh_output_type( + ep, + module, + 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 @@ -186,6 +186,10 @@ bitflags::bitflags! { /// Support for `quantizeToF16`, `pack2x16float`, and `unpack2x16float`, which store /// `f16`-precision values in `f32`s. const SHADER_FLOAT16_IN_FLOAT32 = 1 << 28; + /// Support for fragment shader barycentric coordinates. + const SHADER_BARYCENTRICS = 1 << 29; + /// Support for task shaders, mesh shaders, and per-primitive fragment inputs + const MESH_SHADER = 1 << 30; } } @@ -278,6 +282,8 @@ bitflags::bitflags! { const VERTEX = 0x1; const FRAGMENT = 0x2; const COMPUTE = 0x4; + const MESH = 0x8; + const TASK = 0x10; } } diff --git a/third_party/rust/naga/src/valid/type.rs b/third_party/rust/naga/src/valid/type.rs @@ -220,9 +220,12 @@ const fn ptr_space_argument_flag(space: crate::AddressSpace) -> TypeFlags { use crate::AddressSpace as As; match space { As::Function | As::Private => TypeFlags::ARGUMENT, - As::Uniform | As::Storage { .. } | As::Handle | As::PushConstant | As::WorkGroup => { - TypeFlags::empty() - } + As::Uniform + | As::Storage { .. } + | As::Handle + | As::PushConstant + | As::WorkGroup + | As::TaskPayload => TypeFlags::empty(), } } 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":"14fc314e094524575e12773badac343c650bfd0c983d828539a4ac887a64bbf6","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","build.rs":"5e3619e28faeac243cbae1a5f739ad15035dc9e1254957b64fd1deed6f393c8a","src/as_hal.rs":"5d08d8e49b016abb662957d8e42ab748d580a2f3e449caeeb7311f222b8818f6","src/binding_model.rs":"9943f0814b697f446ee374343a980e49ca2f8fae1bb1955ba889eb0bee4b1f3b","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"198c23d5d5a0012a0aac58d4a42e7fd5c69776e7b19309720fbb85e699347d0d","src/command/bundle.rs":"d078bb708cbdea42ebebc5c5a510bff3cad982b67be3682ed5956bfb212114f1","src/command/clear.rs":"932afc6e1858f8c93d3ecf721215a0bc584a8e613444641a98f5cb98e3061b4b","src/command/compute.rs":"bd7f8df05c7172781bed6d181b75360e3b66d0cf0c56f655ad76ab8e73b59b76","src/command/compute_command.rs":"18aa0b8e389a5d345243b876b1abbacfc998a19d23069e092183fa7be10fa0ab","src/command/draw.rs":"e7bf195d33683a19b077e64d181cb27b8acde724732ac9af3c94d83c3f21559e","src/command/encoder.rs":"7655f8c248120f39e37f3ad0f84bd9816df78a75657790ab12d5aba144fef65f","src/command/encoder_command.rs":"4e1d28040d9330a803644e377bd7675ec503cd0396c31394658dc67d71a4b50f","src/command/ffi.rs":"1fb626579a7726a32d571a17a14f2656def0c170f4f6297e7e51772a6fc5a566","src/command/memory_init.rs":"f68a796c4262d261620cf85e5762e267dee013f4ef5d61f67fcb173b59048983","src/command/mod.rs":"0c650f854bbf48b25c00ff4b3423b0e33abc7199a4a423d39ae155cc694deb47","src/command/pass.rs":"e92efb6eef955cc329e5c5d2aa49e5be78e42dc82ed62e6878b005f4450e9e80","src/command/query.rs":"fa7cb51fbbaa50febe0e61c473891d4131125c290180a05d49b60f5138931fb4","src/command/ray_tracing.rs":"bcb785a0845ecccc87411037fac234474429beba9cd67ba33d55476716e25dca","src/command/render.rs":"f0dda975fa2f1c6f74e6150db7b26d1f3c8a9cf9523892e4e2f3a3f81009b839","src/command/render_command.rs":"3f1bc2fec688fa3f33052867eeb2e194020a643f7d16f6111b8b128594c38570","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"28fdca903934d7e2e5d12d28f952ad3e9ef804c8452f9d020831b5e6aca7e19d","src/command/transition_resources.rs":"753cb02adfee4758404c403d19fd76e6c8de77de01435a2cbe2f60bdbe44bde1","src/conv.rs":"4e4115429df502099f7230d47a050d307f6237c7c11c9c90cba9e34dc909ebdd","src/device/bgl.rs":"b081fe1393f1dd917151efc3a10ee0269fecd3920eac3b45411c1197a98c5a06","src/device/global.rs":"e6ca310ed5f0ed4bd369d25b0f6ee6711624484f35c9fd533111f603aae25618","src/device/life.rs":"44bd34cf5ab1c1a21729f2188df6d2ca0238f11c5f723380c8a4a16fbbd90b88","src/device/mod.rs":"dc8271ae7b62e1096f1a9068f671e6ed8cf7a11b5f9987066d5c173c6e4c4ad8","src/device/queue.rs":"efe56b3905bac2540d67a469aa01c6579034b541ee7e898234809d0071f08abf","src/device/ray_tracing.rs":"cb13bc0caf54113ca12ce5db147af339474ec4b2423f2556600b5ea936b408cc","src/device/resource.rs":"039e2b45debf9396038482ae67cdea7bed0bb5fc8ba694941ee61638df11ff1f","src/device/trace.rs":"39e52ee5b220eb6a13d949582f1f87756189648bf2f05ea7148b0a67b73c226f","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"bd76f9552496996f9eba6502e5caf1bcd6ca33bf3d5008795b5335f74e56fd55","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"308c53e05134e5a48294c61511e43077adfdb5c334237de2016ed4537d562382","src/id.rs":"134974aa304d1d0eb7349438b9660519886c513f01d5868cd4331d2bc78f2cb8","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":"b7aae46522bc6843b0f47dac7e73e33197c76e9724cfb4be3b949bfa27a99fb1","src/pipeline_cache.rs":"f6a82de6cf362be50335d26e8eed983b53812a8444dff9c8c988a075f3325f8f","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"bf0c6c47e58496199955013170f41cbf10755c1572583d5af4b88686c28ffb66","src/ray_tracing.rs":"a4261ccd978e8fab1fef48a168d2d33f8a9f2dae89f285ecd9ec8a6d0894fa3b","src/registry.rs":"ecd457e8956e065050bb9c63ca404505e56ffed6d540b3f14f745d7c4010b205","src/resource.rs":"942a362cc4ef05876870d3bcb0f0db8d2a513be5acacf257c202ee2c0c83a908","src/scratch.rs":"ea5c40e4d18a12f09cc1038f2dcdddb69b13e99275ac987d826658229a39b326","src/snatch.rs":"bf422810afd952894e365cd397763d42d6365ce3c5a5b4c1170566432f462939","src/storage.rs":"29427dea035d03abc8b8abdebecc5591378f1366088d1468ab2beb8536e7d675","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":"a4f661cd65a621e1aebf2d5c5aa3d726373647d6cbab36ed8ebdcb42bbecf416","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":"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 diff --git a/third_party/rust/wgpu-core/Cargo.toml b/third_party/rust/wgpu-core/Cargo.toml @@ -79,6 +79,8 @@ serde = [ "wgpu-types/serde", "arrayvec/serde", "hashbrown/serde", + "smallvec/serde", + "macro_rules_attribute", ] spirv = ["naga/spv-in"] static-dxc = ["wgpu-hal/static-dxc"] @@ -143,6 +145,10 @@ default-features = false [dependencies.log] version = "0.4.21" +[dependencies.macro_rules_attribute] +version = "0.2" +optional = true + [dependencies.naga] version = "27.0.0" path = "../naga" diff --git a/third_party/rust/wgpu-core/src/binding_model.rs b/third_party/rust/wgpu-core/src/binding_model.rs @@ -889,7 +889,8 @@ where } /// cbindgen:ignore -pub type ResolvedPipelineLayoutDescriptor<'a> = PipelineLayoutDescriptor<'a, Arc<BindGroupLayout>>; +pub type ResolvedPipelineLayoutDescriptor<'a, BGL = Arc<BindGroupLayout>> = + PipelineLayoutDescriptor<'a, BGL>; #[derive(Debug)] pub struct PipelineLayout { diff --git a/third_party/rust/wgpu-core/src/command/bundle.rs b/third_party/rust/wgpu-core/src/command/bundle.rs @@ -96,11 +96,13 @@ use thiserror::Error; use wgpu_hal::ShouldBeNonZeroExt; use wgt::error::{ErrorType, WebGpuError}; +#[cfg(feature = "trace")] +use crate::command::ArcReferences; use crate::{ binding_model::{BindError, BindGroup, PipelineLayout}, command::{ - BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr, - PassErrorScope, RenderCommandError, StateChange, + BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, IdReferences, MapPassErr, + PassErrorScope, RenderCommand, RenderCommandError, StateChange, }, device::{ AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext, @@ -120,11 +122,7 @@ use crate::{ Label, LabelHelpers, }; -use super::{ - pass, - render_command::{ArcRenderCommand, RenderCommand}, - DrawCommandFamily, DrawKind, -}; +use super::{pass, render_command::ArcRenderCommand, DrawCommandFamily, DrawKind}; /// Describes a [`RenderBundleEncoder`]. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -158,7 +156,7 @@ pub struct RenderBundleEncoderDescriptor<'a> { #[derive(Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct RenderBundleEncoder { - base: BasePass<RenderCommand, Infallible>, + base: BasePass<RenderCommand<IdReferences>, Infallible>, parent_id: id::DeviceId, pub(crate) context: RenderPassContext, pub(crate) is_depth_read_only: bool, @@ -175,7 +173,6 @@ impl RenderBundleEncoder { pub fn new( desc: &RenderBundleEncoderDescriptor, parent_id: id::DeviceId, - base: Option<BasePass<RenderCommand, Infallible>>, ) -> Result<Self, CreateRenderBundleError> { let (is_depth_read_only, is_stencil_read_only) = match desc.depth_stencil { Some(ds) => { @@ -197,7 +194,7 @@ impl RenderBundleEncoder { //TODO: validate that attachment formats are renderable, // have expected aspects, support multisampling. Ok(Self { - base: base.unwrap_or_else(|| BasePass::new(&desc.label)), + base: BasePass::new(&desc.label), parent_id, context: RenderPassContext { attachments: AttachmentData { @@ -221,7 +218,7 @@ impl RenderBundleEncoder { } sc }, - multiview: desc.multiview, + multiview_mask: desc.multiview, }, is_depth_read_only, @@ -242,7 +239,7 @@ impl RenderBundleEncoder { depth_stencil: None, }, sample_count: 0, - multiview: None, + multiview_mask: None, }, is_depth_read_only: false, is_stencil_read_only: false, @@ -252,11 +249,6 @@ impl RenderBundleEncoder { } } - #[cfg(feature = "trace")] - pub(crate) fn to_base_pass(&self) -> BasePass<RenderCommand, Infallible> { - self.base.clone() - } - pub fn parent(&self) -> id::DeviceId { self.parent_id } @@ -305,12 +297,12 @@ impl RenderBundleEncoder { let base = &self.base; - for &command in &base.commands { + for command in &base.commands { match command { - RenderCommand::SetBindGroup { + &RenderCommand::SetBindGroup { index, num_dynamic_offsets, - bind_group_id, + bind_group, } => { let scope = PassErrorScope::SetBindGroup; set_bind_group( @@ -319,11 +311,11 @@ impl RenderBundleEncoder { &base.dynamic_offsets, index, num_dynamic_offsets, - bind_group_id, + bind_group, ) .map_pass_err(scope)?; } - RenderCommand::SetPipeline(pipeline_id) => { + &RenderCommand::SetPipeline(pipeline) => { let scope = PassErrorScope::SetPipelineRender; set_pipeline( &mut state, @@ -331,12 +323,12 @@ impl RenderBundleEncoder { &self.context, self.is_depth_read_only, self.is_stencil_read_only, - pipeline_id, + pipeline, ) .map_pass_err(scope)?; } - RenderCommand::SetIndexBuffer { - buffer_id, + &RenderCommand::SetIndexBuffer { + buffer, index_format, offset, size, @@ -345,24 +337,24 @@ impl RenderBundleEncoder { set_index_buffer( &mut state, &buffer_guard, - buffer_id, + buffer, index_format, offset, size, ) .map_pass_err(scope)?; } - RenderCommand::SetVertexBuffer { + &RenderCommand::SetVertexBuffer { slot, - buffer_id, + buffer, offset, size, } => { let scope = PassErrorScope::SetVertexBuffer; - set_vertex_buffer(&mut state, &buffer_guard, slot, buffer_id, offset, size) + set_vertex_buffer(&mut state, &buffer_guard, slot, buffer, offset, size) .map_pass_err(scope)?; } - RenderCommand::SetPushConstant { + &RenderCommand::SetPushConstant { stages, offset, size_bytes, @@ -372,7 +364,7 @@ impl RenderBundleEncoder { set_push_constant(&mut state, stages, offset, size_bytes, values_offset) .map_pass_err(scope)?; } - RenderCommand::Draw { + &RenderCommand::Draw { vertex_count, instance_count, first_vertex, @@ -392,7 +384,7 @@ impl RenderBundleEncoder { ) .map_pass_err(scope)?; } - RenderCommand::DrawIndexed { + &RenderCommand::DrawIndexed { index_count, instance_count, first_index, @@ -414,7 +406,7 @@ impl RenderBundleEncoder { ) .map_pass_err(scope)?; } - RenderCommand::DrawMeshTasks { + &RenderCommand::DrawMeshTasks { group_count_x, group_count_y, group_count_z, @@ -432,11 +424,13 @@ impl RenderBundleEncoder { ) .map_pass_err(scope)?; } - RenderCommand::DrawIndirect { - buffer_id, + &RenderCommand::DrawIndirect { + buffer, offset, count: 1, family, + vertex_or_index_limit: None, + instance_limit: None, } => { let scope = PassErrorScope::Draw { kind: DrawKind::DrawIndirect, @@ -446,32 +440,39 @@ impl RenderBundleEncoder { &mut state, &base.dynamic_offsets, &buffer_guard, - buffer_id, + buffer, offset, family, ) .map_pass_err(scope)?; } - RenderCommand::DrawIndirect { .. } - | RenderCommand::MultiDrawIndirectCount { .. } - | RenderCommand::PushDebugGroup { color: _, len: _ } - | RenderCommand::InsertDebugMarker { color: _, len: _ } - | RenderCommand::PopDebugGroup => { + &RenderCommand::DrawIndirect { + count, + vertex_or_index_limit, + instance_limit, + .. + } => { + unreachable!("unexpected (multi-)draw indirect with count {count}, vertex_or_index_limits {vertex_or_index_limit:?}, instance_limit {instance_limit:?} found in a render bundle"); + } + &RenderCommand::MultiDrawIndirectCount { .. } + | &RenderCommand::PushDebugGroup { color: _, len: _ } + | &RenderCommand::InsertDebugMarker { color: _, len: _ } + | &RenderCommand::PopDebugGroup => { unimplemented!("not supported by a render bundle") } // Must check the TIMESTAMP_QUERY_INSIDE_PASSES feature - RenderCommand::WriteTimestamp { .. } - | RenderCommand::BeginOcclusionQuery { .. } - | RenderCommand::EndOcclusionQuery - | RenderCommand::BeginPipelineStatisticsQuery { .. } - | RenderCommand::EndPipelineStatisticsQuery => { + &RenderCommand::WriteTimestamp { .. } + | &RenderCommand::BeginOcclusionQuery { .. } + | &RenderCommand::EndOcclusionQuery + | &RenderCommand::BeginPipelineStatisticsQuery { .. } + | &RenderCommand::EndPipelineStatisticsQuery => { unimplemented!("not supported by a render bundle") } - RenderCommand::ExecuteBundle(_) - | RenderCommand::SetBlendConstant(_) - | RenderCommand::SetStencilReference(_) - | RenderCommand::SetViewport { .. } - | RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"), + &RenderCommand::ExecuteBundle(_) + | &RenderCommand::SetBlendConstant(_) + | &RenderCommand::SetStencilReference(_) + | &RenderCommand::SetViewport { .. } + | &RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"), } } @@ -518,13 +519,13 @@ impl RenderBundleEncoder { pub fn set_index_buffer( &mut self, - buffer_id: id::BufferId, + buffer: id::BufferId, index_format: wgt::IndexFormat, offset: wgt::BufferAddress, size: Option<wgt::BufferSize>, ) { self.base.commands.push(RenderCommand::SetIndexBuffer { - buffer_id, + buffer, index_format, offset, size, @@ -899,8 +900,8 @@ fn multi_draw_indirect( count: 1, family, - vertex_or_index_limit, - instance_limit, + vertex_or_index_limit: Some(vertex_or_index_limit), + instance_limit: Some(instance_limit), }); Ok(()) } @@ -941,6 +942,7 @@ pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>; //Note: here, `RenderBundle` is just wrapping a raw stream of render commands. // The plan is to back it by an actual Vulkan secondary buffer, D3D12 Bundle, // or Metal indirect command buffer. +/// cbindgen:ignore #[derive(Debug)] pub struct RenderBundle { // Normalized command stream. It can be executed verbatim, @@ -971,6 +973,11 @@ unsafe impl Send for RenderBundle {} unsafe impl Sync for RenderBundle {} impl RenderBundle { + #[cfg(feature = "trace")] + pub(crate) fn to_base_pass(&self) -> BasePass<RenderCommand<ArcReferences>, Infallible> { + self.base.clone() + } + /// Actually encode the contents into a native command buffer. /// /// This is partially duplicating the logic of `render_pass_end`. @@ -1142,8 +1149,9 @@ impl RenderBundle { buffer, *offset, *family, - *vertex_or_index_limit, - *instance_limit, + vertex_or_index_limit + .expect("finalized render bundle missing vertex_or_index_limit"), + instance_limit.expect("finalized render bundle missing instance_limit"), )?; let dst_buffer = @@ -1590,7 +1598,7 @@ impl State { /// Error encountered when finishing recording a render bundle. #[derive(Clone, Debug, Error)] -pub(super) enum RenderBundleErrorInner { +pub enum RenderBundleErrorInner { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] @@ -1692,7 +1700,7 @@ pub mod bundle_ffi { bundle.base.commands.push(RenderCommand::SetBindGroup { index, num_dynamic_offsets: offset_length, - bind_group_id, + bind_group: bind_group_id, }); } @@ -1719,7 +1727,7 @@ pub mod bundle_ffi { ) { bundle.base.commands.push(RenderCommand::SetVertexBuffer { slot, - buffer_id, + buffer: buffer_id, offset, size, }); @@ -1813,10 +1821,12 @@ pub mod bundle_ffi { offset: BufferAddress, ) { bundle.base.commands.push(RenderCommand::DrawIndirect { - buffer_id, + buffer: buffer_id, offset, count: 1, family: DrawCommandFamily::Draw, + vertex_or_index_limit: None, + instance_limit: None, }); } @@ -1826,10 +1836,12 @@ pub mod bundle_ffi { offset: BufferAddress, ) { bundle.base.commands.push(RenderCommand::DrawIndirect { - buffer_id, + buffer: buffer_id, offset, count: 1, family: DrawCommandFamily::DrawIndexed, + vertex_or_index_limit: None, + instance_limit: None, }); } diff --git a/third_party/rust/wgpu-core/src/command/clear.rs b/third_party/rust/wgpu-core/src/command/clear.rs @@ -1,8 +1,6 @@ use alloc::{sync::Arc, vec::Vec}; use core::ops::Range; -#[cfg(feature = "trace")] -use crate::command::Command as TraceCommand; use crate::{ api_log, command::{encoder::EncodingState, ArcCommand, EncoderStateError}, @@ -119,11 +117,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::ClearBuffer { dst, offset, size }); - } - cmd_buf_data.push_with(|| -> Result<_, ClearError> { Ok(ArcCommand::ClearBuffer { dst: self.resolve_buffer_id(dst)?, @@ -147,14 +140,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::ClearTexture { - dst, - subresource_range: *subresource_range, - }); - } - cmd_buf_data.push_with(|| -> Result<_, ClearError> { Ok(ArcCommand::ClearTexture { dst: self.resolve_texture_id(dst)?, @@ -547,7 +532,7 @@ fn clear_texture_via_render_passes( sample_count: dst_texture.desc.sample_count, color_attachments, depth_stencil_attachment, - multiview: None, + multiview_mask: None, timestamp_writes: None, occlusion_query_set: None, }) diff --git a/third_party/rust/wgpu-core/src/command/compute.rs b/third_party/rust/wgpu-core/src/command/compute.rs @@ -478,73 +478,6 @@ impl Global { } } - /// Note that this differs from [`Self::compute_pass_end`], it will - /// create a new pass, replay the commands and end the pass. - /// - /// # Panics - /// On any error. - #[doc(hidden)] - #[cfg(any(feature = "serde", feature = "replay"))] - pub fn compute_pass_end_with_unresolved_commands( - &self, - encoder_id: id::CommandEncoderId, - base: BasePass<super::ComputeCommand, Infallible>, - timestamp_writes: Option<&PassTimestampWrites>, - ) { - #[cfg(feature = "trace")] - { - let cmd_enc = self.hub.command_encoders.get(encoder_id); - let mut cmd_buf_data = cmd_enc.data.lock(); - let cmd_buf_data = cmd_buf_data.get_inner(); - - if let Some(ref mut list) = cmd_buf_data.trace_commands { - list.push(crate::command::Command::RunComputePass { - base: BasePass { - label: base.label.clone(), - error: None, - commands: base.commands.clone(), - dynamic_offsets: base.dynamic_offsets.clone(), - string_data: base.string_data.clone(), - push_constant_data: base.push_constant_data.clone(), - }, - timestamp_writes: timestamp_writes.cloned(), - }); - } - } - - let BasePass { - label, - error: _, - commands, - dynamic_offsets, - string_data, - push_constant_data, - } = base; - - let (mut compute_pass, encoder_error) = self.command_encoder_begin_compute_pass( - encoder_id, - &ComputePassDescriptor { - label: label.as_deref().map(Cow::Borrowed), - timestamp_writes: timestamp_writes.cloned(), - }, - ); - if let Some(err) = encoder_error { - panic!("{:?}", err); - }; - - compute_pass.base = BasePass { - label, - error: None, - commands: super::ComputeCommand::resolve_compute_command_ids(&self.hub, &commands) - .unwrap(), - dynamic_offsets, - string_data, - push_constant_data, - }; - - self.compute_pass_end(&mut compute_pass).unwrap(); - } - pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), EncoderStateError> { profiling::scope!( "CommandEncoder::run_compute_pass {}", diff --git a/third_party/rust/wgpu-core/src/command/compute_command.rs b/third_party/rust/wgpu-core/src/command/compute_command.rs @@ -1,208 +1,21 @@ -use alloc::sync::Arc; +#[cfg(feature = "serde")] +use crate::command::serde_object_reference_struct; +use crate::command::{ArcReferences, ReferenceType}; -use crate::{ - binding_model::BindGroup, - id, - pipeline::ComputePipeline, - resource::{Buffer, QuerySet}, -}; +#[cfg(feature = "serde")] +use macro_rules_attribute::apply; -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ComputeCommand { - SetBindGroup { - index: u32, - num_dynamic_offsets: usize, - bind_group_id: Option<id::BindGroupId>, - }, - - SetPipeline(id::ComputePipelineId), - - /// Set a range of push constants to values stored in `push_constant_data`. - SetPushConstant { - /// The byte offset within the push constant storage to write to. This - /// must be a multiple of four. - offset: u32, - - /// The number of bytes to write. This must be a multiple of four. - size_bytes: u32, - - /// Index in `push_constant_data` of the start of the data - /// to be written. - /// - /// Note: this is not a byte offset like `offset`. Rather, it is the - /// index of the first `u32` element in `push_constant_data` to read. - values_offset: u32, - }, - - Dispatch([u32; 3]), - - DispatchIndirect { - buffer_id: id::BufferId, - offset: wgt::BufferAddress, - }, - - PushDebugGroup { - color: u32, - len: usize, - }, - - PopDebugGroup, - - InsertDebugMarker { - color: u32, - len: usize, - }, - - WriteTimestamp { - query_set_id: id::QuerySetId, - query_index: u32, - }, - - BeginPipelineStatisticsQuery { - query_set_id: id::QuerySetId, - query_index: u32, - }, - - EndPipelineStatisticsQuery, -} - -impl ComputeCommand { - /// Resolves all ids in a list of commands into the corresponding resource Arc. - #[cfg(any(feature = "serde", feature = "replay"))] - pub fn resolve_compute_command_ids( - hub: &crate::hub::Hub, - commands: &[ComputeCommand], - ) -> Result<alloc::vec::Vec<ArcComputeCommand>, super::ComputePassError> { - use super::{ComputePassError, PassErrorScope}; - use alloc::vec::Vec; - - let buffers_guard = hub.buffers.read(); - let bind_group_guard = hub.bind_groups.read(); - let query_set_guard = hub.query_sets.read(); - let pipelines_guard = hub.compute_pipelines.read(); - - let resolved_commands: Vec<ArcComputeCommand> = commands - .iter() - .map(|c| -> Result<ArcComputeCommand, ComputePassError> { - Ok(match *c { - ComputeCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group_id, - } => { - if bind_group_id.is_none() { - return Ok(ArcComputeCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: None, - }); - } - - let bind_group_id = bind_group_id.unwrap(); - let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| { - ComputePassError { - scope: PassErrorScope::SetBindGroup, - inner: e.into(), - } - })?; - - ArcComputeCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: Some(bg), - } - } - ComputeCommand::SetPipeline(pipeline_id) => ArcComputeCommand::SetPipeline( - pipelines_guard - .get(pipeline_id) - .get() - .map_err(|e| ComputePassError { - scope: PassErrorScope::SetPipelineCompute, - inner: e.into(), - })?, - ), - - ComputeCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - } => ArcComputeCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - }, - - ComputeCommand::Dispatch(dim) => ArcComputeCommand::Dispatch(dim), - - ComputeCommand::DispatchIndirect { buffer_id, offset } => { - ArcComputeCommand::DispatchIndirect { - buffer: buffers_guard.get(buffer_id).get().map_err(|e| { - ComputePassError { - scope: PassErrorScope::Dispatch { indirect: true }, - inner: e.into(), - } - })?, - offset, - } - } - - ComputeCommand::PushDebugGroup { color, len } => { - ArcComputeCommand::PushDebugGroup { color, len } - } - - ComputeCommand::PopDebugGroup => ArcComputeCommand::PopDebugGroup, - - ComputeCommand::InsertDebugMarker { color, len } => { - ArcComputeCommand::InsertDebugMarker { color, len } - } - - ComputeCommand::WriteTimestamp { - query_set_id, - query_index, - } => ArcComputeCommand::WriteTimestamp { - query_set: query_set_guard.get(query_set_id).get().map_err(|e| { - ComputePassError { - scope: PassErrorScope::WriteTimestamp, - inner: e.into(), - } - })?, - query_index, - }, - - ComputeCommand::BeginPipelineStatisticsQuery { - query_set_id, - query_index, - } => ArcComputeCommand::BeginPipelineStatisticsQuery { - query_set: query_set_guard.get(query_set_id).get().map_err(|e| { - ComputePassError { - scope: PassErrorScope::BeginPipelineStatisticsQuery, - inner: e.into(), - } - })?, - query_index, - }, - - ComputeCommand::EndPipelineStatisticsQuery => { - ArcComputeCommand::EndPipelineStatisticsQuery - } - }) - }) - .collect::<Result<Vec<_>, ComputePassError>>()?; - Ok(resolved_commands) - } -} - -/// Equivalent to `ComputeCommand` but the Ids resolved into resource Arcs. +/// cbindgen:ignore #[derive(Clone, Debug)] -pub enum ArcComputeCommand { +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub enum ComputeCommand<R: ReferenceType> { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group: Option<Arc<BindGroup>>, + bind_group: Option<R::BindGroup>, }, - SetPipeline(Arc<ComputePipeline>), + SetPipeline(R::ComputePipeline), /// Set a range of push constants to values stored in `push_constant_data`. SetPushConstant { @@ -224,12 +37,11 @@ pub enum ArcComputeCommand { Dispatch([u32; 3]), DispatchIndirect { - buffer: Arc<Buffer>, + buffer: R::Buffer, offset: wgt::BufferAddress, }, PushDebugGroup { - #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))] color: u32, len: usize, }, @@ -237,20 +49,22 @@ pub enum ArcComputeCommand { PopDebugGroup, InsertDebugMarker { - #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))] color: u32, len: usize, }, WriteTimestamp { - query_set: Arc<QuerySet>, + query_set: R::QuerySet, query_index: u32, }, BeginPipelineStatisticsQuery { - query_set: Arc<QuerySet>, + query_set: R::QuerySet, query_index: u32, }, EndPipelineStatisticsQuery, } + +/// cbindgen:ignore +pub type ArcComputeCommand = ComputeCommand<ArcReferences>; diff --git a/third_party/rust/wgpu-core/src/command/draw.rs b/third_party/rust/wgpu-core/src/command/draw.rs @@ -71,6 +71,13 @@ pub enum DrawError { limit: u32, max_total: u32, }, + #[error( + "Mesh shader calls in multiview render passes require enabling the `EXPERIMENTAL_MESH_SHADER_MULTIVIEW` feature, and the highest bit ({highest_view_index}) in the multiview mask must be <= `Limits::max_multiview_view_count` ({max_multiviews})" + )] + MeshPipelineMultiviewLimitsViolated { + highest_view_index: u32, + max_multiviews: u32, + }, } impl WebGpuError for DrawError { diff --git a/third_party/rust/wgpu-core/src/command/encoder_command.rs b/third_party/rust/wgpu-core/src/command/encoder_command.rs @@ -1,141 +1,186 @@ -use core::convert::Infallible; +use core::{convert::Infallible, num::NonZero}; use alloc::{string::String, sync::Arc, vec::Vec}; +#[cfg(feature = "serde")] +use macro_rules_attribute::{apply, attribute_alias}; use crate::{ + command::ColorAttachments, id, + instance::Surface, resource::{Buffer, QuerySet, Texture}, }; +pub trait ReferenceType { + type Buffer: Clone + core::fmt::Debug; + type Surface: Clone; // Surface does not implement Debug, although it probably could. + type Texture: Clone + core::fmt::Debug; + type TextureView: Clone + core::fmt::Debug; + type ExternalTexture: Clone + core::fmt::Debug; + type QuerySet: Clone + core::fmt::Debug; + type BindGroup: Clone + core::fmt::Debug; + type RenderPipeline: Clone + core::fmt::Debug; + type RenderBundle: Clone + core::fmt::Debug; + type ComputePipeline: Clone + core::fmt::Debug; + type Blas: Clone + core::fmt::Debug; + type Tlas: Clone + core::fmt::Debug; +} + +/// Reference wgpu objects via numeric IDs assigned by [`crate::identity::IdentityManager`]. #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Command { - CopyBufferToBuffer { - src: id::BufferId, - src_offset: wgt::BufferAddress, - dst: id::BufferId, - dst_offset: wgt::BufferAddress, - size: Option<wgt::BufferAddress>, - }, - CopyBufferToTexture { - src: wgt::TexelCopyBufferInfo<id::BufferId>, - dst: wgt::TexelCopyTextureInfo<id::TextureId>, - size: wgt::Extent3d, - }, - CopyTextureToBuffer { - src: wgt::TexelCopyTextureInfo<id::TextureId>, - dst: wgt::TexelCopyBufferInfo<id::BufferId>, - size: wgt::Extent3d, - }, - CopyTextureToTexture { - src: wgt::TexelCopyTextureInfo<id::TextureId>, - dst: wgt::TexelCopyTextureInfo<id::TextureId>, - size: wgt::Extent3d, - }, - ClearBuffer { - dst: id::BufferId, - offset: wgt::BufferAddress, - size: Option<wgt::BufferAddress>, - }, - ClearTexture { - dst: id::TextureId, - subresource_range: wgt::ImageSubresourceRange, - }, - WriteTimestamp { - query_set_id: id::QuerySetId, - query_index: u32, - }, - ResolveQuerySet { - query_set_id: id::QuerySetId, - start_query: u32, - query_count: u32, - destination: id::BufferId, - destination_offset: wgt::BufferAddress, - }, - PushDebugGroup(String), - PopDebugGroup, - InsertDebugMarker(String), - RunComputePass { - base: crate::command::BasePass<crate::command::ComputeCommand, Infallible>, - timestamp_writes: Option<crate::command::PassTimestampWrites>, - }, - RunRenderPass { - base: crate::command::BasePass<crate::command::RenderCommand, Infallible>, - target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>, - target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>, - timestamp_writes: Option<crate::command::PassTimestampWrites>, - occlusion_query_set_id: Option<id::QuerySetId>, - }, - BuildAccelerationStructures { - blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>, - tlas: Vec<crate::ray_tracing::TraceTlasPackage>, - }, +pub struct IdReferences; + +/// Reference wgpu objects via the integer value of pointers. +/// +/// This is used for trace recording and playback. Recording stores the pointer +/// value of `Arc` references in the trace. Playback uses the integer values +/// as keys to a `HashMap`. +#[cfg(feature = "serde")] +#[doc(hidden)] +#[derive(Clone, Debug)] +pub struct PointerReferences; + +/// Reference wgpu objects via `Arc`s. +#[derive(Clone, Debug)] +pub struct ArcReferences; + +impl ReferenceType for IdReferences { + type Buffer = id::BufferId; + type Surface = id::SurfaceId; + type Texture = id::TextureId; + type TextureView = id::TextureViewId; + type ExternalTexture = id::ExternalTextureId; + type QuerySet = id::QuerySetId; + type BindGroup = id::BindGroupId; + type RenderPipeline = id::RenderPipelineId; + type RenderBundle = id::RenderBundleId; + type ComputePipeline = id::ComputePipelineId; + type Blas = id::BlasId; + type Tlas = id::TlasId; +} + +#[cfg(feature = "serde")] +impl ReferenceType for PointerReferences { + type Buffer = id::PointerId<id::markers::Buffer>; + type Surface = id::PointerId<id::markers::Surface>; + type Texture = id::PointerId<id::markers::Texture>; + type TextureView = id::PointerId<id::markers::TextureView>; + type ExternalTexture = id::PointerId<id::markers::ExternalTexture>; + type QuerySet = id::PointerId<id::markers::QuerySet>; + type BindGroup = id::PointerId<id::markers::BindGroup>; + type RenderPipeline = id::PointerId<id::markers::RenderPipeline>; + type RenderBundle = id::PointerId<id::markers::RenderBundle>; + type ComputePipeline = id::PointerId<id::markers::ComputePipeline>; + type Blas = id::PointerId<id::markers::Blas>; + type Tlas = id::PointerId<id::markers::Tlas>; +} + +impl ReferenceType for ArcReferences { + type Buffer = Arc<Buffer>; + type Surface = Arc<Surface>; + type Texture = Arc<Texture>; + type TextureView = Arc<crate::resource::TextureView>; + type ExternalTexture = Arc<crate::resource::ExternalTexture>; + type QuerySet = Arc<QuerySet>; + type BindGroup = Arc<crate::binding_model::BindGroup>; + type RenderPipeline = Arc<crate::pipeline::RenderPipeline>; + type RenderBundle = Arc<crate::command::RenderBundle>; + type ComputePipeline = Arc<crate::pipeline::ComputePipeline>; + type Blas = Arc<crate::resource::Blas>; + type Tlas = Arc<crate::resource::Tlas>; +} + +#[cfg(feature = "serde")] +attribute_alias! { + #[apply(serde_object_reference_struct)] = + #[derive(serde::Serialize, serde::Deserialize)] + #[serde(bound = + "R::Buffer: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::Surface: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::Texture: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::TextureView: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::ExternalTexture: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::QuerySet: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::BindGroup: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::RenderPipeline: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::RenderBundle: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::ComputePipeline: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::Blas: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + R::Tlas: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + wgt::BufferTransition<R::Buffer>: serde::Serialize + for<'d> serde::Deserialize<'d>,\ + wgt::TextureTransition<R::Texture>: serde::Serialize + for<'d> serde::Deserialize<'d>" + )]; } #[derive(Clone, Debug)] -pub enum ArcCommand { +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub enum Command<R: ReferenceType> { CopyBufferToBuffer { - src: Arc<Buffer>, + src: R::Buffer, src_offset: wgt::BufferAddress, - dst: Arc<Buffer>, + dst: R::Buffer, dst_offset: wgt::BufferAddress, size: Option<wgt::BufferAddress>, }, CopyBufferToTexture { - src: wgt::TexelCopyBufferInfo<Arc<Buffer>>, - dst: wgt::TexelCopyTextureInfo<Arc<Texture>>, + src: wgt::TexelCopyBufferInfo<R::Buffer>, + dst: wgt::TexelCopyTextureInfo<R::Texture>, size: wgt::Extent3d, }, CopyTextureToBuffer { - src: wgt::TexelCopyTextureInfo<Arc<Texture>>, - dst: wgt::TexelCopyBufferInfo<Arc<Buffer>>, + src: wgt::TexelCopyTextureInfo<R::Texture>, + dst: wgt::TexelCopyBufferInfo<R::Buffer>, size: wgt::Extent3d, }, CopyTextureToTexture { - src: wgt::TexelCopyTextureInfo<Arc<Texture>>, - dst: wgt::TexelCopyTextureInfo<Arc<Texture>>, + src: wgt::TexelCopyTextureInfo<R::Texture>, + dst: wgt::TexelCopyTextureInfo<R::Texture>, size: wgt::Extent3d, }, ClearBuffer { - dst: Arc<Buffer>, + dst: R::Buffer, offset: wgt::BufferAddress, size: Option<wgt::BufferAddress>, }, ClearTexture { - dst: Arc<Texture>, + dst: R::Texture, subresource_range: wgt::ImageSubresourceRange, }, WriteTimestamp { - query_set: Arc<QuerySet>, + query_set: R::QuerySet, query_index: u32, }, ResolveQuerySet { - query_set: Arc<QuerySet>, + query_set: R::QuerySet, start_query: u32, query_count: u32, - destination: Arc<Buffer>, + destination: R::Buffer, destination_offset: wgt::BufferAddress, }, PushDebugGroup(String), PopDebugGroup, InsertDebugMarker(String), RunComputePass { - pass: super::BasePass<super::ArcComputeCommand, Infallible>, - timestamp_writes: Option<super::ArcPassTimestampWrites>, + pass: crate::command::BasePass<crate::command::ComputeCommand<R>, Infallible>, + timestamp_writes: Option<crate::command::PassTimestampWrites<R::QuerySet>>, }, RunRenderPass { - pass: super::BasePass<super::ArcRenderCommand, Infallible>, - color_attachments: super::ArcRenderPassColorAttachmentArray, - depth_stencil_attachment: Option<super::ArcRenderPassDepthStencilAttachment>, - timestamp_writes: Option<super::ArcPassTimestampWrites>, - occlusion_query_set: Option<Arc<QuerySet>>, + pass: crate::command::BasePass<crate::command::RenderCommand<R>, Infallible>, + color_attachments: ColorAttachments<R::TextureView>, + depth_stencil_attachment: + Option<crate::command::ResolvedRenderPassDepthStencilAttachment<R::TextureView>>, + timestamp_writes: Option<crate::command::PassTimestampWrites<R::QuerySet>>, + occlusion_query_set: Option<R::QuerySet>, + multiview_mask: Option<NonZero<u32>>, }, BuildAccelerationStructures { - blas: Vec<crate::ray_tracing::ArcBlasBuildEntry>, - tlas: Vec<crate::ray_tracing::ArcTlasPackage>, + blas: Vec<crate::ray_tracing::OwnedBlasBuildEntry<R>>, + tlas: Vec<crate::ray_tracing::OwnedTlasPackage<R>>, }, TransitionResources { - buffer_transitions: Vec<wgt::BufferTransition<Arc<Buffer>>>, - texture_transitions: Vec<wgt::TextureTransition<Arc<Texture>>>, + buffer_transitions: Vec<wgt::BufferTransition<R::Buffer>>, + texture_transitions: Vec<wgt::TextureTransition<R::Texture>>, }, } + +pub type ArcCommand = Command<ArcReferences>; diff --git a/third_party/rust/wgpu-core/src/command/ffi.rs b/third_party/rust/wgpu-core/src/command/ffi.rs @@ -1,7 +1,9 @@ //! Types that are useful for FFI bindings to `wgpu`. -use crate::id; +use crate::{command::IdReferences, id}; pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<id::BufferId>; pub type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo<id::TextureId>; pub type CopyExternalImageDestInfo = wgt::CopyExternalImageDestInfo<id::TextureId>; + +pub type Command = super::Command<IdReferences>; diff --git a/third_party/rust/wgpu-core/src/command/mod.rs b/third_party/rust/wgpu-core/src/command/mod.rs @@ -31,23 +31,31 @@ mod transition_resources; use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec::Vec}; use core::convert::Infallible; use core::mem::{self, ManuallyDrop}; -use core::ops; +use core::{ops, panic}; pub(crate) use self::clear::clear_texture; +#[cfg(feature = "serde")] +pub(crate) use self::encoder_command::serde_object_reference_struct; +#[cfg(any(feature = "trace", feature = "replay"))] +#[doc(hidden)] +pub use self::encoder_command::PointerReferences; pub use self::{ bundle::*, clear::ClearError, compute::*, - compute_command::{ArcComputeCommand, ComputeCommand}, + compute_command::ArcComputeCommand, draw::*, - encoder_command::{ArcCommand, Command}, + encoder_command::{ArcCommand, ArcReferences, Command, IdReferences, ReferenceType}, query::*, render::*, - render_command::{ArcRenderCommand, RenderCommand}, + render_command::ArcRenderCommand, transfer::*, }; pub(crate) use allocator::CommandAllocator; +/// cbindgen:ignore +pub use self::{compute_command::ComputeCommand, render_command::RenderCommand}; + pub(crate) use timestamp_writes::ArcPassTimestampWrites; pub use timestamp_writes::PassTimestampWrites; @@ -81,9 +89,6 @@ use wgt::error::{ErrorType, WebGpuError}; use thiserror::Error; -#[cfg(feature = "trace")] -type TraceCommand = Command; - /// cbindgen:ignore pub type TexelCopyBufferInfo = ffi::TexelCopyBufferInfo; /// cbindgen:ignore @@ -148,12 +153,12 @@ pub(crate) enum CommandEncoderStatus { } impl CommandEncoderStatus { - #[cfg(feature = "trace")] - fn trace(&mut self) -> Option<&mut Vec<TraceCommand>> { - match self { - Self::Recording(cmd_buf_data) => cmd_buf_data.trace_commands.as_mut(), - _ => None, - } + #[doc(hidden)] + fn replay(&mut self, commands: Vec<Command<ArcReferences>>) { + let Self::Recording(cmd_buf_data) = self else { + panic!("encoder should be in the recording state"); + }; + cmd_buf_data.commands.extend(commands); } /// Push a command provided by a closure onto the encoder. @@ -277,20 +282,6 @@ impl CommandEncoderStatus { } } - #[cfg(all(feature = "trace", any(feature = "serde", feature = "replay")))] - fn get_inner(&mut self) -> &mut CommandBufferMutable { - match self { - Self::Locked(inner) | Self::Finished(inner) | Self::Recording(inner) => inner, - // This is unreachable because this function is only used when - // playing back a recorded trace. If only to avoid having to - // implement serialization for all the error types, we don't support - // storing the errors in a trace. - Self::Consumed => unreachable!("command encoder is consumed"), - Self::Error(_) => unreachable!("passes in a trace do not store errors"), - Self::Transitioning => unreachable!(), - } - } - /// Locks the encoder by putting it in the [`Self::Locked`] state. /// /// Render or compute passes call this on start. At the end of the pass, @@ -782,10 +773,12 @@ pub struct CommandBufferMutable { indirect_draw_validation_resources: crate::indirect_validation::DrawResources, - pub(crate) commands: Vec<ArcCommand>, + pub(crate) commands: Vec<Command<ArcReferences>>, + /// If tracing, `command_encoder_finish` replaces the `Arc`s in `commands` + /// with integer pointers, and moves them into `trace_commands`. #[cfg(feature = "trace")] - pub(crate) trace_commands: Option<Vec<TraceCommand>>, + pub(crate) trace_commands: Option<Vec<Command<PointerReferences>>>, } impl CommandBufferMutable { @@ -972,7 +965,31 @@ impl CommandEncoder { } let mut commands = mem::take(&mut cmd_buf_data.commands); - for command in commands.drain(..) { + #[cfg(not(feature = "trace"))] + let command_iter = commands.drain(..); + #[cfg(feature = "trace")] + let mut trace_commands = None; + + #[cfg(feature = "trace")] + let command_iter = { + if self.device.trace.lock().is_some() { + trace_commands = Some( + cmd_buf_data + .trace_commands + .insert(Vec::with_capacity(commands.len())), + ); + } + + commands.drain(..).inspect(|cmd| { + use crate::device::trace::IntoTrace; + + if let Some(ref mut trace) = trace_commands { + trace.push(cmd.clone().to_trace()); + } + }) + }; + + for command in command_iter { if matches!( command, ArcCommand::RunRenderPass { .. } | ArcCommand::RunComputePass { .. } @@ -1002,6 +1019,7 @@ impl CommandEncoder { depth_stencil_attachment, timestamp_writes, occlusion_query_set, + multiview_mask, } => { api_log!( "Begin encoding render pass with '{}' label", @@ -1014,6 +1032,7 @@ impl CommandEncoder { depth_stencil_attachment, timestamp_writes, occlusion_query_set, + multiview_mask, ); match res.as_ref() { Err(err) => api_log!("Finished encoding render pass ({err:?})"), @@ -1179,6 +1198,26 @@ impl CommandEncoder { } impl CommandBuffer { + /// Replay commands from a trace. + /// + /// This is exposed for the `player` crate only. It is not a public API. + /// It is not guaranteed to apply all of the validation that the original + /// entrypoints provide. + #[doc(hidden)] + pub fn from_trace(device: &Arc<Device>, commands: Vec<Command<ArcReferences>>) -> Arc<Self> { + let encoder = device.create_command_encoder(&None).unwrap(); + let mut cmd_enc_status = encoder.data.lock(); + cmd_enc_status.replay(commands); + drop(cmd_enc_status); + + let (cmd_buf, error) = encoder.finish(&wgt::CommandBufferDescriptor { label: None }); + if let Some(err) = error { + panic!("CommandEncoder::finish failed: {err}"); + } + + cmd_buf + } + pub fn take_finished(&self) -> Result<CommandBufferMutable, CommandEncoderError> { use CommandEncoderStatus as St; match mem::replace( @@ -1552,22 +1591,31 @@ impl Global { self.hub.query_sets.get(query_set_id).get() } + /// Finishes a command encoder, creating a command buffer and returning errors that were + /// deferred until now. + /// + /// The returned `String` is the label of the command encoder, supplied so that `wgpu` can + /// include the label when printing deferred errors without having its own copy of the label. + /// This is a kludge and should be replaced if we think of a better solution to propagating + /// labels. pub fn command_encoder_finish( &self, encoder_id: id::CommandEncoderId, desc: &wgt::CommandBufferDescriptor<Label>, id_in: Option<id::CommandBufferId>, - ) -> (id::CommandBufferId, Option<CommandEncoderError>) { + ) -> (id::CommandBufferId, Option<(String, CommandEncoderError)>) { profiling::scope!("CommandEncoder::finish"); let hub = &self.hub; - let cmd_enc = hub.command_encoders.get(encoder_id); - let (cmd_buf, error) = cmd_enc.finish(desc); + let (cmd_buf, opt_error) = cmd_enc.finish(desc); let cmd_buf_id = hub.command_buffers.prepare(id_in).assign(cmd_buf); - (cmd_buf_id, error) + ( + cmd_buf_id, + opt_error.map(|error| (cmd_enc.label.clone(), error)), + ) } pub fn command_encoder_push_debug_group( @@ -1583,11 +1631,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::PushDebugGroup(label.to_owned())); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::PushDebugGroup(label.to_owned())) }) @@ -1606,11 +1649,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::InsertDebugMarker(label.to_owned())); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::InsertDebugMarker(label.to_owned())) }) @@ -1628,11 +1666,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::PopDebugGroup); - } - cmd_buf_data .push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::PopDebugGroup) }) } diff --git a/third_party/rust/wgpu-core/src/command/query.rs b/third_party/rust/wgpu-core/src/command/query.rs @@ -1,8 +1,6 @@ use alloc::{sync::Arc, vec, vec::Vec}; use core::{iter, mem}; -#[cfg(feature = "trace")] -use crate::command::Command as TraceCommand; use crate::{ command::{encoder::EncodingState, ArcCommand, EncoderStateError}, device::{Device, DeviceError, MissingFeatures}, @@ -366,14 +364,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::WriteTimestamp { - query_set_id, - query_index, - }); - } - cmd_buf_data.push_with(|| -> Result<_, QueryError> { Ok(ArcCommand::WriteTimestamp { query_set: self.resolve_query_set(query_set_id)?, @@ -396,17 +386,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::ResolveQuerySet { - query_set_id, - start_query, - query_count, - destination, - destination_offset, - }); - } - cmd_buf_data.push_with(|| -> Result<_, QueryError> { Ok(ArcCommand::ResolveQuerySet { query_set: self.resolve_query_set(query_set_id)?, diff --git a/third_party/rust/wgpu-core/src/command/ray_tracing.rs b/third_party/rust/wgpu-core/src/command/ray_tracing.rs @@ -8,32 +8,28 @@ use core::{ use wgt::{math::align_to, BufferUsages, BufferUses, Features}; use crate::{ - command::CommandBufferMutable, + command::encoder::EncodingState, + ray_tracing::{AsAction, AsBuild, BlasTriangleGeometryInfo, TlasBuild, ValidateAsActionsError}, + resource::InvalidResourceError, + track::Tracker, +}; +use crate::{command::EncoderStateError, device::resource::CommandIndices}; +use crate::{ + command::{ArcCommand, ArcReferences, CommandBufferMutable}, device::queue::TempResource, global::Global, id::CommandEncoderId, init_tracker::MemoryInitKind, ray_tracing::{ - BlasBuildEntry, BlasGeometries, BuildAccelerationStructureError, TlasPackage, - TraceBlasBuildEntry, TraceBlasGeometries, TraceBlasTriangleGeometry, TraceTlasInstance, - TraceTlasPackage, + ArcBlasBuildEntry, ArcBlasGeometries, ArcBlasTriangleGeometry, ArcTlasInstance, + ArcTlasPackage, BlasBuildEntry, BlasGeometries, BuildAccelerationStructureError, + OwnedBlasBuildEntry, OwnedTlasPackage, TlasPackage, }, resource::{Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas}, scratch::ScratchBuffer, snatch::SnatchGuard, track::PendingTransition, }; -use crate::{command::EncoderStateError, device::resource::CommandIndices}; -use crate::{ - command::{encoder::EncodingState, ArcCommand}, - ray_tracing::{ - ArcBlasBuildEntry, ArcBlasGeometries, ArcBlasTriangleGeometry, ArcTlasInstance, - ArcTlasPackage, AsAction, AsBuild, BlasTriangleGeometryInfo, TlasBuild, - ValidateAsActionsError, - }, - resource::InvalidResourceError, - track::Tracker, -}; use crate::{lock::RwLockWriteGuard, resource::RawResourceAccess}; use crate::id::{BlasId, TlasId}; @@ -125,73 +121,14 @@ impl Global { let hub = &self.hub; let cmd_enc = hub.command_encoders.get(command_encoder_id); - - let trace_blas: Vec<TraceBlasBuildEntry> = blas_iter - .map(|blas_entry| { - let geometries = match blas_entry.geometries { - BlasGeometries::TriangleGeometries(triangle_geometries) => { - TraceBlasGeometries::TriangleGeometries( - triangle_geometries - .map(|tg| TraceBlasTriangleGeometry { - size: tg.size.clone(), - vertex_buffer: tg.vertex_buffer, - index_buffer: tg.index_buffer, - transform_buffer: tg.transform_buffer, - first_vertex: tg.first_vertex, - vertex_stride: tg.vertex_stride, - first_index: tg.first_index, - transform_buffer_offset: tg.transform_buffer_offset, - }) - .collect(), - ) - } - }; - TraceBlasBuildEntry { - blas_id: blas_entry.blas_id, - geometries, - } - }) - .collect(); - - let trace_tlas: Vec<TraceTlasPackage> = tlas_iter - .map(|package: TlasPackage| { - let instances = package - .instances - .map(|instance| { - instance.map(|instance| TraceTlasInstance { - blas_id: instance.blas_id, - transform: *instance.transform, - custom_data: instance.custom_data, - mask: instance.mask, - }) - }) - .collect(); - TraceTlasPackage { - tlas_id: package.tlas_id, - instances, - lowest_unmodified: package.lowest_unmodified, - } - }) - .collect(); - let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(crate::command::Command::BuildAccelerationStructures { - blas: trace_blas.clone(), - tlas: trace_tlas.clone(), - }); - } - cmd_buf_data.push_with(|| -> Result<_, BuildAccelerationStructureError> { - let blas = trace_blas - .iter() + let blas = blas_iter .map(|blas_entry| { - let geometries = match &blas_entry.geometries { - TraceBlasGeometries::TriangleGeometries(triangle_geometries) => { + let geometries = match blas_entry.geometries { + BlasGeometries::TriangleGeometries(triangle_geometries) => { let tri_geo = triangle_geometries - .iter() .map(|tg| { Ok(ArcBlasTriangleGeometry { size: tg.size.clone(), @@ -221,19 +158,17 @@ impl Global { }) .collect::<Result<_, BuildAccelerationStructureError>>()?; - let tlas = trace_tlas - .iter() + let tlas = tlas_iter .map(|tlas_package| { let instances = tlas_package .instances - .iter() .map(|instance| { instance .as_ref() .map(|instance| { Ok(ArcTlasInstance { blas: self.resolve_blas_id(instance.blas_id)?, - transform: instance.transform, + transform: *instance.transform, custom_data: instance.custom_data, mask: instance.mask, }) @@ -256,8 +191,8 @@ impl Global { pub(crate) fn build_acceleration_structures( state: &mut EncodingState, - blas: Vec<ArcBlasBuildEntry>, - tlas: Vec<ArcTlasPackage>, + blas: Vec<OwnedBlasBuildEntry<ArcReferences>>, + tlas: Vec<OwnedTlasPackage<ArcReferences>>, ) -> Result<(), BuildAccelerationStructureError> { state .device @@ -282,7 +217,7 @@ pub(crate) fn build_acceleration_structures( &mut scratch_buffer_blas_size, &mut blas_storage, )?; - let mut tlas_lock_store = Vec::<(Option<ArcTlasPackage>, Arc<Tlas>)>::new(); + let mut tlas_lock_store = Vec::<(Option<OwnedTlasPackage<ArcReferences>>, Arc<Tlas>)>::new(); for package in tlas.into_iter() { let tlas = package.tlas.clone(); @@ -615,7 +550,7 @@ impl CommandBufferMutable { ///iterates over the blas iterator, and it's geometry, pushing the buffers into a storage vector (and also some validation). fn iter_blas( - blas_iter: impl Iterator<Item = ArcBlasBuildEntry>, + blas_iter: impl Iterator<Item = OwnedBlasBuildEntry<ArcReferences>>, tracker: &mut Tracker, build_command: &mut AsBuild, buf_storage: &mut Vec<TriangleBufferStore>, diff --git a/third_party/rust/wgpu-core/src/command/render.rs b/third_party/rust/wgpu-core/src/command/render.rs @@ -77,6 +77,9 @@ fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps { } /// Describes an individual channel within a render pass, such as color, depth, or stencil. +/// +/// A channel must either be read-only, or it must specify both load and store +/// operations. See [`ResolvedPassChannel`] for a validated version. #[repr(C)] #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -120,7 +123,12 @@ impl<V: Copy + Default> PassChannel<Option<V>> { } } +/// Describes an individual channel within a render pass, such as color, depth, or stencil. +/// +/// Unlike [`PassChannel`], this version uses the Rust type system to guarantee +/// a valid specification. #[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ResolvedPassChannel<V> { ReadOnly, Operational(wgt::Operations<V>), @@ -185,8 +193,8 @@ pub type ArcRenderPassColorAttachment = RenderPassColorAttachment<Arc<TextureVie // Avoid allocation in the common case that there is only one color attachment, // but don't bloat `ArcCommand::RunRenderPass` excessively. -pub type ArcRenderPassColorAttachmentArray = - SmallVec<[Option<RenderPassColorAttachment<Arc<TextureView>>>; 1]>; +pub type ColorAttachments<TV = Arc<TextureView>> = + SmallVec<[Option<RenderPassColorAttachment<TV>>; 1]>; impl ArcRenderPassColorAttachment { fn hal_ops(&self) -> hal::AttachmentOps { @@ -202,12 +210,14 @@ impl ArcRenderPassColorAttachment { } /// Describes a depth/stencil attachment to a render pass. +/// +/// This version uses the unvalidated [`PassChannel`]. #[repr(C)] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct RenderPassDepthStencilAttachment { +pub struct RenderPassDepthStencilAttachment<TV> { /// The view to use as an attachment. - pub view: id::TextureViewId, + pub view: TV, /// What operations will be performed on the depth part of the attachment. pub depth: PassChannel<Option<f32>>, /// What operations will be performed on the stencil part of the attachment. @@ -215,10 +225,13 @@ pub struct RenderPassDepthStencilAttachment { } /// Describes a depth/stencil attachment to a render pass. +/// +/// This version uses the validated [`ResolvedPassChannel`]. #[derive(Clone, Debug)] -pub struct ArcRenderPassDepthStencilAttachment { +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ResolvedRenderPassDepthStencilAttachment<TV> { /// The view to use as an attachment. - pub view: Arc<TextureView>, + pub view: TV, /// What operations will be performed on the depth part of the attachment. pub depth: ResolvedPassChannel<f32>, /// What operations will be performed on the stencil part of the attachment. @@ -232,11 +245,13 @@ pub struct RenderPassDescriptor<'a> { /// The color attachments of the render pass. pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>, /// The depth and stencil attachment of the render pass, if any. - pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>, + pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment<id::TextureViewId>>, /// Defines where and when timestamp values will be written for this pass. pub timestamp_writes: Option<&'a PassTimestampWrites>, /// Defines where the occlusion query results will be stored for this pass. pub occlusion_query_set: Option<id::QuerySetId>, + /// The multiview array layers that will be used + pub multiview_mask: Option<NonZeroU32>, } /// Describes the attachments of a render pass. @@ -246,11 +261,14 @@ struct ArcRenderPassDescriptor<'a> { pub color_attachments: ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>, /// The depth and stencil attachment of the render pass, if any. - pub depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>, + pub depth_stencil_attachment: + Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>, /// Defines where and when timestamp values will be written for this pass. pub timestamp_writes: Option<ArcPassTimestampWrites>, /// Defines where the occlusion query results will be stored for this pass. pub occlusion_query_set: Option<Arc<QuerySet>>, + /// The multiview array layers that will be used + pub multiview_mask: Option<NonZeroU32>, } pub type RenderBasePass = BasePass<ArcRenderCommand, RenderPassError>; @@ -275,9 +293,10 @@ pub struct RenderPass { color_attachments: ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>, - depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>, + depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>, timestamp_writes: Option<ArcPassTimestampWrites>, occlusion_query_set: Option<Arc<QuerySet>>, + multiview_mask: Option<NonZeroU32>, // Resource binding dedupe state. current_bind_groups: BindGroupStateChange, @@ -293,6 +312,7 @@ impl RenderPass { color_attachments, depth_stencil_attachment, occlusion_query_set, + multiview_mask, } = desc; Self { @@ -302,6 +322,7 @@ impl RenderPass { depth_stencil_attachment, timestamp_writes, occlusion_query_set, + multiview_mask, current_bind_groups: BindGroupStateChange::new(), current_pipeline: StateChange::new(), @@ -316,6 +337,7 @@ impl RenderPass { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, current_bind_groups: BindGroupStateChange::new(), current_pipeline: StateChange::new(), } @@ -339,6 +361,7 @@ impl fmt::Debug for RenderPass { "push constant u32 count", &self.base.push_constant_data.len(), ) + .field("multiview mask", &self.multiview_mask) .finish() } } @@ -792,6 +815,8 @@ pub enum RenderPassErrorInner { "Multiview pass texture views with more than one array layer must have D2Array dimension" )] MultiViewDimensionMismatch, + #[error("Multiview view count limit violated")] + TooManyMultiviewViews, #[error("missing occlusion query set")] MissingOcclusionQuerySet, #[error(transparent)] @@ -893,6 +918,7 @@ impl WebGpuError for RenderPassError { | RenderPassErrorInner::PushConstantOutOfMemory | RenderPassErrorInner::MultiViewMismatch | RenderPassErrorInner::MultiViewDimensionMismatch + | RenderPassErrorInner::TooManyMultiviewViews | RenderPassErrorInner::MissingOcclusionQuerySet | RenderPassErrorInner::PassEnded => return ErrorType::Validation, }; @@ -928,7 +954,7 @@ struct RenderPassInfo { extent: wgt::Extent3d, divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>, - multiview: Option<NonZeroU32>, + multiview_mask: Option<NonZeroU32>, } impl RenderPassInfo { @@ -971,7 +997,9 @@ impl RenderPassInfo { device: &Arc<Device>, hal_label: Option<&str>, color_attachments: &[Option<ArcRenderPassColorAttachment>], - mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>, + mut depth_stencil_attachment: Option< + ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>, + >, mut timestamp_writes: Option<ArcPassTimestampWrites>, mut occlusion_query_set: Option<Arc<QuerySet>>, encoder: &mut dyn hal::DynCommandEncoder, @@ -980,6 +1008,7 @@ impl RenderPassInfo { pending_query_resets: &mut QueryResetMap, pending_discard_init_fixups: &mut SurfacesInDiscardState, snatch_guard: &SnatchGuard<'_>, + multiview_mask: Option<NonZeroU32>, ) -> Result<Self, RenderPassErrorInner> { profiling::scope!("RenderPassInfo::start"); @@ -1024,8 +1053,11 @@ impl RenderPassInfo { } } else { // Multiview is only supported if the feature is enabled - if this_multiview.is_some() { + if let Some(this_multiview) = this_multiview { device.require_features(wgt::Features::MULTIVIEW)?; + if this_multiview.get() > device.limits.max_multiview_view_count { + return Err(RenderPassErrorInner::TooManyMultiviewViews); + } } detected_multiview = Some(this_multiview); @@ -1207,11 +1239,12 @@ impl RenderPassInfo { }, )?; - if !color_view - .desc - .aspects() - .contains(hal::FormatAspects::COLOR) - { + if !color_view.desc.aspects().intersects( + hal::FormatAspects::COLOR + | hal::FormatAspects::PLANE_0 + | hal::FormatAspects::PLANE_1 + | hal::FormatAspects::PLANE_2, + ) { return Err(RenderPassErrorInner::ColorAttachment( ColorAttachmentError::InvalidFormat(color_view.desc.format), )); @@ -1372,7 +1405,20 @@ impl RenderPassInfo { } let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?; - let multiview = detected_multiview.expect("Multiview was not detected, no attachments"); + + let detected_multiview = + detected_multiview.expect("Multiview was not detected, no attachments"); + if let Some(mask) = multiview_mask { + // 0x01 will have msb 0 + let mask_msb = 31 - mask.leading_zeros(); + let detected_mv = detected_multiview.map(NonZeroU32::get).unwrap_or(1); + if mask_msb >= detected_mv { + return Err(RenderPassErrorInner::MultiViewMismatch); + } + if mask.get() != (1 << detected_mv) - 1 { + device.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?; + } + } let attachment_formats = AttachmentData { colors: color_attachments @@ -1397,7 +1443,7 @@ impl RenderPassInfo { let context = RenderPassContext { attachments: attachment_formats, sample_count, - multiview, + multiview_mask, }; let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() { @@ -1433,7 +1479,7 @@ impl RenderPassInfo { sample_count, color_attachments: &color_attachments_hal, depth_stencil_attachment: depth_stencil, - multiview, + multiview_mask, timestamp_writes: timestamp_writes_hal, occlusion_query_set: occlusion_query_set_hal, }; @@ -1468,7 +1514,7 @@ impl RenderPassInfo { is_stencil_read_only, extent, divergent_discarded_depth_stencil_aspect, - multiview, + multiview_mask, }) } @@ -1535,7 +1581,7 @@ impl RenderPassInfo { stencil_ops, clear_value: (0.0, 0), }), - multiview: self.multiview, + multiview_mask: self.multiview_mask, timestamp_writes: None, occlusion_query_set: None, }; @@ -1649,7 +1695,7 @@ impl Global { ))); } - Some(ArcRenderPassDepthStencilAttachment { + Some(ResolvedRenderPassDepthStencilAttachment { view, depth: if format.has_depth_aspect() { depth_stencil_attachment.depth.resolve(|clear| if let Some(clear) = clear { @@ -1696,6 +1742,8 @@ impl Global { None }; + arc_desc.multiview_mask = desc.multiview_mask; + Ok(()) } @@ -1714,6 +1762,7 @@ impl Global { color_attachments: ArrayVec::new(), depth_stencil_attachment: None, occlusion_query_set: None, + multiview_mask: None, }; match fill_arc_desc(hub, desc, &mut arc_desc, &cmd_enc.device) { Ok(()) => (RenderPass::new(cmd_enc, arc_desc), None), @@ -1761,79 +1810,6 @@ impl Global { } } - /// Note that this differs from [`Self::render_pass_end`], it will - /// create a new pass, replay the commands and end the pass. - #[doc(hidden)] - #[cfg(any(feature = "serde", feature = "replay"))] - pub fn render_pass_end_with_unresolved_commands( - &self, - encoder_id: id::CommandEncoderId, - base: BasePass<super::RenderCommand, Infallible>, - color_attachments: &[Option<RenderPassColorAttachment>], - depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, - timestamp_writes: Option<&PassTimestampWrites>, - occlusion_query_set: Option<id::QuerySetId>, - ) { - #[cfg(feature = "trace")] - { - let cmd_enc = self.hub.command_encoders.get(encoder_id); - let mut cmd_buf_data = cmd_enc.data.lock(); - let cmd_buf_data = cmd_buf_data.get_inner(); - - if let Some(ref mut list) = cmd_buf_data.trace_commands { - list.push(crate::command::Command::RunRenderPass { - base: BasePass { - label: base.label.clone(), - error: None, - commands: base.commands.clone(), - dynamic_offsets: base.dynamic_offsets.clone(), - string_data: base.string_data.clone(), - push_constant_data: base.push_constant_data.clone(), - }, - target_colors: color_attachments.to_vec(), - target_depth_stencil: depth_stencil_attachment.cloned(), - timestamp_writes: timestamp_writes.cloned(), - occlusion_query_set_id: occlusion_query_set, - }); - } - } - - let BasePass { - label, - error: _, - commands, - dynamic_offsets, - string_data, - push_constant_data, - } = base; - - let (mut render_pass, encoder_error) = self.command_encoder_begin_render_pass( - encoder_id, - &RenderPassDescriptor { - label: label.as_deref().map(Cow::Borrowed), - color_attachments: Cow::Borrowed(color_attachments), - depth_stencil_attachment, - timestamp_writes, - occlusion_query_set, - }, - ); - if let Some(err) = encoder_error { - panic!("{:?}", err); - }; - - render_pass.base = BasePass { - label, - error: None, - commands: super::RenderCommand::resolve_render_command_ids(&self.hub, &commands) - .unwrap(), - dynamic_offsets, - string_data, - push_constant_data, - }; - - self.render_pass_end(&mut render_pass).unwrap(); - } - pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> { profiling::scope!( "CommandEncoder::run_render_pass {}", @@ -1872,6 +1848,7 @@ impl Global { depth_stencil_attachment: pass.depth_stencil_attachment.take(), timestamp_writes: pass.timestamp_writes.take(), occlusion_query_set: pass.occlusion_query_set.take(), + multiview_mask: pass.multiview_mask, }) }) } @@ -1880,10 +1857,13 @@ impl Global { pub(super) fn encode_render_pass( parent_state: &mut EncodingState<InnerCommandEncoder>, mut base: BasePass<ArcRenderCommand, Infallible>, - color_attachments: ArcRenderPassColorAttachmentArray, - mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>, + color_attachments: ColorAttachments<Arc<TextureView>>, + mut depth_stencil_attachment: Option< + ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>, + >, mut timestamp_writes: Option<ArcPassTimestampWrites>, occlusion_query_set: Option<Arc<QuerySet>>, + multiview_mask: Option<NonZeroU32>, ) -> Result<(), RenderPassError> { let pass_scope = PassErrorScope::Pass; @@ -1922,6 +1902,7 @@ pub(super) fn encode_render_pass( &mut pending_query_resets, &mut pending_discard_init_fixups, parent_state.snatch_guard, + multiview_mask, ) .map_pass_err(pass_scope)?; @@ -2615,6 +2596,26 @@ fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassError Ok(()) } +fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> { + if let Some(mv) = state.info.multiview_mask { + let highest_bit = 31 - mv.leading_zeros(); + + let features = state.pass.base.device.features; + + if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW) + || highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count + { + return Err(RenderPassErrorInner::Draw( + DrawError::MeshPipelineMultiviewLimitsViolated { + highest_view_index: highest_bit, + max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count, + }, + )); + } + } + Ok(()) +} + fn draw( state: &mut State, vertex_count: u32, @@ -2699,7 +2700,9 @@ fn draw_mesh_tasks( api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}"); state.is_ready(DrawCommandFamily::DrawMeshTasks)?; + state.flush_bindings()?; + validate_mesh_draw_multiview(state)?; let groups_size_limit = state .pass @@ -2750,6 +2753,10 @@ fn multi_draw_indirect( state.is_ready(family)?; state.flush_bindings()?; + if family == DrawCommandFamily::DrawMeshTasks { + validate_mesh_draw_multiview(state)?; + } + state .pass .base @@ -2932,6 +2939,10 @@ fn multi_draw_indirect_count( state.is_ready(family)?; state.flush_bindings()?; + if family == DrawCommandFamily::DrawMeshTasks { + validate_mesh_draw_multiview(state)?; + } + let stride = get_stride_of_indirect_args(family); state @@ -3443,8 +3454,8 @@ impl Global { count: 1, family: DrawCommandFamily::Draw, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) @@ -3468,8 +3479,8 @@ impl Global { count: 1, family: DrawCommandFamily::DrawIndexed, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) @@ -3493,8 +3504,8 @@ impl Global { count: 1, family: DrawCommandFamily::DrawMeshTasks, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) @@ -3519,8 +3530,8 @@ impl Global { count, family: DrawCommandFamily::Draw, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) @@ -3545,8 +3556,8 @@ impl Global { count, family: DrawCommandFamily::DrawIndexed, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) @@ -3571,8 +3582,8 @@ impl Global { count, family: DrawCommandFamily::DrawMeshTasks, - vertex_or_index_limit: 0, - instance_limit: 0, + vertex_or_index_limit: None, + instance_limit: None, }); Ok(()) diff --git a/third_party/rust/wgpu-core/src/command/render_command.rs b/third_party/rust/wgpu-core/src/command/render_command.rs @@ -1,34 +1,33 @@ -use alloc::sync::Arc; - use wgt::{BufferAddress, BufferSize, Color}; -use super::{DrawCommandFamily, Rect, RenderBundle}; -use crate::{ - binding_model::BindGroup, - id, - pipeline::RenderPipeline, - resource::{Buffer, QuerySet}, -}; +use super::{DrawCommandFamily, Rect}; +#[cfg(feature = "serde")] +use crate::command::serde_object_reference_struct; +use crate::command::{ArcReferences, ReferenceType}; + +#[cfg(feature = "serde")] +use macro_rules_attribute::apply; +/// cbindgen:ignore #[doc(hidden)] -#[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum RenderCommand { +#[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub enum RenderCommand<R: ReferenceType> { SetBindGroup { index: u32, num_dynamic_offsets: usize, - bind_group_id: Option<id::BindGroupId>, + bind_group: Option<R::BindGroup>, }, - SetPipeline(id::RenderPipelineId), + SetPipeline(R::RenderPipeline), SetIndexBuffer { - buffer_id: id::BufferId, + buffer: R::Buffer, index_format: wgt::IndexFormat, offset: BufferAddress, size: Option<BufferSize>, }, SetVertexBuffer { slot: u32, - buffer_id: id::BufferId, + buffer: R::Buffer, offset: BufferAddress, size: Option<BufferSize>, }, @@ -88,15 +87,19 @@ pub enum RenderCommand { group_count_z: u32, }, DrawIndirect { - buffer_id: id::BufferId, + buffer: R::Buffer, offset: BufferAddress, count: u32, family: DrawCommandFamily, + /// This limit is only populated for commands in a finished [`RenderBundle`]. + vertex_or_index_limit: Option<u64>, + /// This limit is only populated for commands in a finished [`RenderBundle`]. + instance_limit: Option<u64>, }, MultiDrawIndirectCount { - buffer_id: id::BufferId, + buffer: R::Buffer, offset: BufferAddress, - count_buffer_id: id::BufferId, + count_buffer: R::Buffer, count_buffer_offset: BufferAddress, max_count: u32, family: DrawCommandFamily, @@ -111,7 +114,7 @@ pub enum RenderCommand { len: usize, }, WriteTimestamp { - query_set_id: id::QuerySetId, + query_set: R::QuerySet, query_index: u32, }, BeginOcclusionQuery { @@ -119,290 +122,11 @@ pub enum RenderCommand { }, EndOcclusionQuery, BeginPipelineStatisticsQuery { - query_set_id: id::QuerySetId, + query_set: R::QuerySet, query_index: u32, }, EndPipelineStatisticsQuery, - ExecuteBundle(id::RenderBundleId), -} - -impl RenderCommand { - /// Resolves all ids in a list of commands into the corresponding resource Arc. - #[cfg(any(feature = "serde", feature = "replay"))] - pub fn resolve_render_command_ids( - hub: &crate::hub::Hub, - commands: &[RenderCommand], - ) -> Result<alloc::vec::Vec<ArcRenderCommand>, super::RenderPassError> { - use super::{DrawKind, PassErrorScope, RenderPassError}; - use alloc::vec::Vec; - - let buffers_guard = hub.buffers.read(); - let bind_group_guard = hub.bind_groups.read(); - let query_set_guard = hub.query_sets.read(); - let pipelines_guard = hub.render_pipelines.read(); - let render_bundles_guard = hub.render_bundles.read(); - - let resolved_commands: Vec<ArcRenderCommand> = - commands - .iter() - .map(|c| -> Result<ArcRenderCommand, RenderPassError> { - Ok(match *c { - RenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group_id, - } => { - if bind_group_id.is_none() { - return Ok(ArcRenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: None, - }); - } - - let bind_group_id = bind_group_id.unwrap(); - let bg = bind_group_guard.get(bind_group_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::SetBindGroup, - inner: e.into(), - } - })?; - - ArcRenderCommand::SetBindGroup { - index, - num_dynamic_offsets, - bind_group: Some(bg), - } - } - - RenderCommand::SetPipeline(pipeline_id) => ArcRenderCommand::SetPipeline( - pipelines_guard.get(pipeline_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::SetPipelineRender, - inner: e.into(), - } - })?, - ), - - RenderCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - stages, - } => ArcRenderCommand::SetPushConstant { - offset, - size_bytes, - values_offset, - stages, - }, - - RenderCommand::PushDebugGroup { color, len } => { - ArcRenderCommand::PushDebugGroup { color, len } - } - - RenderCommand::PopDebugGroup => ArcRenderCommand::PopDebugGroup, - - RenderCommand::InsertDebugMarker { color, len } => { - ArcRenderCommand::InsertDebugMarker { color, len } - } - - RenderCommand::WriteTimestamp { - query_set_id, - query_index, - } => ArcRenderCommand::WriteTimestamp { - query_set: query_set_guard.get(query_set_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::WriteTimestamp, - inner: e.into(), - } - })?, - query_index, - }, - - RenderCommand::BeginPipelineStatisticsQuery { - query_set_id, - query_index, - } => ArcRenderCommand::BeginPipelineStatisticsQuery { - query_set: query_set_guard.get(query_set_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::BeginPipelineStatisticsQuery, - inner: e.into(), - } - })?, - query_index, - }, - - RenderCommand::EndPipelineStatisticsQuery => { - ArcRenderCommand::EndPipelineStatisticsQuery - } - - RenderCommand::SetIndexBuffer { - buffer_id, - index_format, - offset, - size, - } => ArcRenderCommand::SetIndexBuffer { - buffer: buffers_guard.get(buffer_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::SetIndexBuffer, - inner: e.into(), - } - })?, - index_format, - offset, - size, - }, - - RenderCommand::SetVertexBuffer { - slot, - buffer_id, - offset, - size, - } => ArcRenderCommand::SetVertexBuffer { - slot, - buffer: buffers_guard.get(buffer_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::SetVertexBuffer, - inner: e.into(), - } - })?, - offset, - size, - }, - - RenderCommand::SetBlendConstant(color) => { - ArcRenderCommand::SetBlendConstant(color) - } - - RenderCommand::SetStencilReference(reference) => { - ArcRenderCommand::SetStencilReference(reference) - } - - RenderCommand::SetViewport { - rect, - depth_min, - depth_max, - } => ArcRenderCommand::SetViewport { - rect, - depth_min, - depth_max, - }, - - RenderCommand::SetScissor(scissor) => ArcRenderCommand::SetScissor(scissor), - - RenderCommand::Draw { - vertex_count, - instance_count, - first_vertex, - first_instance, - } => ArcRenderCommand::Draw { - vertex_count, - instance_count, - first_vertex, - first_instance, - }, - - RenderCommand::DrawIndexed { - index_count, - instance_count, - first_index, - base_vertex, - first_instance, - } => ArcRenderCommand::DrawIndexed { - index_count, - instance_count, - first_index, - base_vertex, - first_instance, - }, - RenderCommand::DrawMeshTasks { - group_count_x, - group_count_y, - group_count_z, - } => ArcRenderCommand::DrawMeshTasks { - group_count_x, - group_count_y, - group_count_z, - }, - - RenderCommand::DrawIndirect { - buffer_id, - offset, - count, - family, - } => ArcRenderCommand::DrawIndirect { - buffer: buffers_guard.get(buffer_id).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::Draw { - kind: if count != 1 { - DrawKind::MultiDrawIndirect - } else { - DrawKind::DrawIndirect - }, - family, - }, - inner: e.into(), - } - })?, - offset, - count, - family, - - vertex_or_index_limit: 0, - instance_limit: 0, - }, - - RenderCommand::MultiDrawIndirectCount { - buffer_id, - offset, - count_buffer_id, - count_buffer_offset, - max_count, - family, - } => { - let scope = PassErrorScope::Draw { - kind: DrawKind::MultiDrawIndirectCount, - family, - }; - ArcRenderCommand::MultiDrawIndirectCount { - buffer: buffers_guard.get(buffer_id).get().map_err(|e| { - RenderPassError { - scope, - inner: e.into(), - } - })?, - offset, - count_buffer: buffers_guard.get(count_buffer_id).get().map_err( - |e| RenderPassError { - scope, - inner: e.into(), - }, - )?, - count_buffer_offset, - max_count, - family, - } - } - - RenderCommand::BeginOcclusionQuery { query_index } => { - ArcRenderCommand::BeginOcclusionQuery { query_index } - } - - RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery, - - RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle( - render_bundles_guard.get(bundle).get().map_err(|e| { - RenderPassError { - scope: PassErrorScope::ExecuteBundle, - inner: e.into(), - } - })?, - ), - }) - }) - .collect::<Result<Vec<_>, RenderPassError>>()?; - Ok(resolved_commands) - } + ExecuteBundle(R::RenderBundle), } /// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs. @@ -417,123 +141,6 @@ impl RenderCommand { /// is `finish()`ed and when the bundle is executed. Validation occurs when the /// bundle is finished, which means that parameters stored in an `ArcRenderCommand` /// for a render bundle operation must have been validated. -#[doc(hidden)] -#[derive(Clone, Debug)] -pub enum ArcRenderCommand { - SetBindGroup { - index: u32, - num_dynamic_offsets: usize, - bind_group: Option<Arc<BindGroup>>, - }, - SetPipeline(Arc<RenderPipeline>), - SetIndexBuffer { - buffer: Arc<Buffer>, - index_format: wgt::IndexFormat, - offset: BufferAddress, - size: Option<BufferSize>, - }, - SetVertexBuffer { - slot: u32, - buffer: Arc<Buffer>, - offset: BufferAddress, - size: Option<BufferSize>, - }, - SetBlendConstant(Color), - SetStencilReference(u32), - SetViewport { - rect: Rect<f32>, - depth_min: f32, - depth_max: f32, - }, - SetScissor(Rect<u32>), - - /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. - /// - /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation - /// of the restrictions these commands must satisfy. - SetPushConstant { - /// Which stages we are setting push constant values for. - stages: wgt::ShaderStages, - - /// The byte offset within the push constant storage to write to. This - /// must be a multiple of four. - offset: u32, - - /// The number of bytes to write. This must be a multiple of four. - size_bytes: u32, - - /// Index in [`BasePass::push_constant_data`] of the start of the data - /// to be written. - /// - /// Note: this is not a byte offset like `offset`. Rather, it is the - /// index of the first `u32` element in `push_constant_data` to read. - /// - /// `None` means zeros should be written to the destination range, and - /// there is no corresponding data in `push_constant_data`. This is used - /// by render bundles, which explicitly clear out any state that - /// post-bundle code might see. - values_offset: Option<u32>, - }, - Draw { - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, - }, - DrawIndexed { - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, - }, - DrawMeshTasks { - group_count_x: u32, - group_count_y: u32, - group_count_z: u32, - }, - DrawIndirect { - buffer: Arc<Buffer>, - offset: BufferAddress, - count: u32, - family: DrawCommandFamily, - - /// This limit is only populated for commands in a [`RenderBundle`]. - vertex_or_index_limit: u64, - /// This limit is only populated for commands in a [`RenderBundle`]. - instance_limit: u64, - }, - MultiDrawIndirectCount { - buffer: Arc<Buffer>, - offset: BufferAddress, - count_buffer: Arc<Buffer>, - count_buffer_offset: BufferAddress, - max_count: u32, - family: DrawCommandFamily, - }, - PushDebugGroup { - #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))] - color: u32, - len: usize, - }, - PopDebugGroup, - InsertDebugMarker { - #[cfg_attr(not(any(feature = "serde", feature = "replay")), allow(dead_code))] - color: u32, - len: usize, - }, - WriteTimestamp { - query_set: Arc<QuerySet>, - query_index: u32, - }, - BeginOcclusionQuery { - query_index: u32, - }, - EndOcclusionQuery, - BeginPipelineStatisticsQuery { - query_set: Arc<QuerySet>, - query_index: u32, - }, - EndPipelineStatisticsQuery, - ExecuteBundle(Arc<RenderBundle>), -} +/// +/// cbindgen:ignore +pub type ArcRenderCommand = RenderCommand<ArcReferences>; diff --git a/third_party/rust/wgpu-core/src/command/transfer.rs b/third_party/rust/wgpu-core/src/command/transfer.rs @@ -8,8 +8,6 @@ use wgt::{ TextureUsages, }; -#[cfg(feature = "trace")] -use crate::command::Command as TraceCommand; use crate::{ api_log, command::{ @@ -170,7 +168,7 @@ pub enum TransferError { src_sample_count: u32, dst_sample_count: u32, }, - #[error("Requested mip level {requested} does no exist (count: {count})")] + #[error("Requested mip level {requested} does not exist (count: {count})")] InvalidMipLevel { requested: u32, count: u32 }, } @@ -825,17 +823,6 @@ impl Global { let cmd_enc = hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::CopyBufferToBuffer { - src: source, - src_offset: source_offset, - dst: destination, - dst_offset: destination_offset, - size, - }); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::CopyBufferToBuffer { src: self.resolve_buffer_id(source)?, @@ -864,15 +851,6 @@ impl Global { let cmd_enc = self.hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::CopyBufferToTexture { - src: *source, - dst: *destination, - size: *copy_size, - }); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::CopyBufferToTexture { src: wgt::TexelCopyBufferInfo::<Arc<Buffer>> { @@ -907,15 +885,6 @@ impl Global { let cmd_enc = self.hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(list) = cmd_buf_data.trace() { - list.push(TraceCommand::CopyTextureToBuffer { - src: *source, - dst: *destination, - size: *copy_size, - }); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::CopyTextureToBuffer { src: wgt::TexelCopyTextureInfo::<Arc<Texture>> { @@ -950,15 +919,6 @@ impl Global { let cmd_enc = self.hub.command_encoders.get(command_encoder_id); let mut cmd_buf_data = cmd_enc.data.lock(); - #[cfg(feature = "trace")] - if let Some(ref mut list) = cmd_buf_data.trace() { - list.push(TraceCommand::CopyTextureToTexture { - src: *source, - dst: *destination, - size: *copy_size, - }); - } - cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> { Ok(ArcCommand::CopyTextureToTexture { src: wgt::TexelCopyTextureInfo { diff --git a/third_party/rust/wgpu-core/src/conv.rs b/third_party/rust/wgpu-core/src/conv.rs @@ -111,7 +111,12 @@ pub fn map_texture_usage( flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE), ); } - let is_color = aspect.contains(hal::FormatAspects::COLOR); + let is_color = aspect.intersects( + hal::FormatAspects::COLOR + | hal::FormatAspects::PLANE_0 + | hal::FormatAspects::PLANE_1 + | hal::FormatAspects::PLANE_2, + ); u.set( wgt::TextureUses::COLOR_TARGET, usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) && is_color, diff --git a/third_party/rust/wgpu-core/src/device/global.rs b/third_party/rust/wgpu-core/src/device/global.rs @@ -2,7 +2,7 @@ use alloc::{borrow::Cow, boxed::Box, string::String, sync::Arc, vec::Vec}; use core::{ptr::NonNull, sync::atomic::Ordering}; #[cfg(feature = "trace")] -use crate::device::trace; +use crate::device::trace::{self, IntoTrace}; use crate::{ api_log, binding_model::{ @@ -11,7 +11,7 @@ use crate::{ }, command::{self, CommandEncoder}, conv, - device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure}, + device::{life::WaitIdleError, DeviceError, DeviceLostClosure}, global::Global, id::{self, AdapterId, DeviceId, QueueId, SurfaceId}, instance::{self, Adapter, Surface}, @@ -106,6 +106,13 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); + let buffer = match device.create_buffer(desc) { + Ok(buffer) => buffer, + Err(e) => { + break 'error e; + } + }; + #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { let mut desc = desc.clone(); @@ -113,16 +120,9 @@ impl Global { if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) { desc.usage |= wgt::BufferUsages::COPY_DST; } - trace.add(trace::Action::CreateBuffer(fid.id(), desc)); + trace.add(trace::Action::CreateBuffer(buffer.to_trace(), desc)); } - let buffer = match device.create_buffer(desc) { - Ok(buffer) => buffer, - Err(e) => { - break 'error e; - } - }; - let id = fid.assign(Fallible::Valid(buffer)); api_log!( @@ -215,60 +215,6 @@ impl Global { fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string()))); } - #[cfg(feature = "replay")] - pub fn device_set_buffer_data( - &self, - buffer_id: id::BufferId, - offset: BufferAddress, - data: &[u8], - ) -> BufferAccessResult { - use crate::resource::RawResourceAccess; - - let hub = &self.hub; - - let buffer = hub.buffers.get(buffer_id).get()?; - - let device = &buffer.device; - - device.check_is_valid()?; - buffer.check_usage(wgt::BufferUsages::MAP_WRITE)?; - - let last_submission = device.get_queue().and_then(|queue| { - queue - .lock_life() - .get_buffer_latest_submission_index(&buffer) - }); - - if let Some(last_submission) = last_submission { - device.wait_for_submit(last_submission)?; - } - - let snatch_guard = device.snatchable_lock.read(); - let raw_buf = buffer.try_raw(&snatch_guard)?; - - let mapping = unsafe { - device - .raw() - .map_buffer(raw_buf, offset..offset + data.len() as u64) - } - .map_err(|e| device.handle_hal_error(e))?; - - unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) }; - - if !mapping.is_coherent { - #[allow(clippy::single_range_in_vec_init)] - unsafe { - device - .raw() - .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]) - }; - } - - unsafe { device.raw().unmap_buffer(raw_buf) }; - - Ok(()) - } - pub fn buffer_destroy(&self, buffer_id: id::BufferId) { profiling::scope!("Buffer::destroy"); api_log!("Buffer::destroy {buffer_id:?}"); @@ -282,13 +228,10 @@ impl Global { #[cfg(feature = "trace")] if let Some(trace) = buffer.device.trace.lock().as_mut() { - trace.add(trace::Action::FreeBuffer(buffer_id)); + trace.add(trace::Action::FreeBuffer(buffer.to_trace())); } - let _ = buffer.unmap( - #[cfg(feature = "trace")] - buffer_id, - ); + let _ = buffer.unmap(); buffer.destroy(); } @@ -308,13 +251,10 @@ impl Global { #[cfg(feature = "trace")] if let Some(t) = buffer.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyBuffer(buffer_id)); + t.add(trace::Action::DestroyBuffer(buffer.to_trace())); } - let _ = buffer.unmap( - #[cfg(feature = "trace")] - buffer_id, - ); + let _ = buffer.unmap(); } pub fn device_create_texture( @@ -332,16 +272,19 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateTexture(fid.id(), desc.clone())); - } - let texture = match device.create_texture(desc) { Ok(texture) => texture, Err(error) => break 'error error, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateTexture( + texture.to_trace(), + desc.clone(), + )); + } + let id = fid.assign(Fallible::Valid(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); @@ -373,18 +316,21 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); + let texture = match device.create_texture_from_hal(hal_texture, desc) { + Ok(texture) => texture, + Err(error) => break 'error error, + }; + // NB: Any change done through the raw texture handle will not be // recorded in the replay #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateTexture(fid.id(), desc.clone())); + trace.add(trace::Action::CreateTexture( + texture.to_trace(), + desc.clone(), + )); } - let texture = match device.create_texture_from_hal(hal_texture, desc) { - Ok(texture) => texture, - Err(error) => break 'error error, - }; - let id = fid.assign(Fallible::Valid(texture)); api_log!("Device::create_texture({desc:?}) -> {id:?}"); @@ -415,15 +361,20 @@ impl Global { let device = self.hub.devices.get(device_id); + let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) }; + // NB: Any change done through the raw buffer handle will not be // recorded in the replay #[cfg(feature = "trace")] if let Some(trace) = device.trace.lock().as_mut() { - trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone())); + match &buffer { + Fallible::Valid(arc) => { + trace.add(trace::Action::CreateBuffer(arc.to_trace(), desc.clone())) + } + Fallible::Invalid(_) => {} + } } - let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) }; - let id = fid.assign(buffer); api_log!("Device::create_buffer -> {id:?}"); @@ -443,7 +394,7 @@ impl Global { #[cfg(feature = "trace")] if let Some(trace) = texture.device.trace.lock().as_mut() { - trace.add(trace::Action::FreeTexture(texture_id)); + trace.add(trace::Action::FreeTexture(texture.to_trace())); } texture.destroy(); @@ -459,7 +410,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(texture) = _texture.get() { if let Some(t) = texture.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyTexture(texture_id)); + t.add(trace::Action::DestroyTexture(texture.to_trace())); } } } @@ -483,20 +434,20 @@ impl Global { }; let device = &texture.device; + let view = match device.create_texture_view(&texture, desc) { + Ok(view) => view, + Err(e) => break 'error e, + }; + #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { trace.add(trace::Action::CreateTextureView { - id: fid.id(), - parent_id: texture_id, + id: view.to_trace(), + parent: texture.to_trace(), desc: desc.clone(), }); } - let view = match device.create_texture_view(&texture, desc) { - Ok(view) => view, - Err(e) => break 'error e, - }; - let id = fid.assign(Fallible::Valid(view)); api_log!("Texture::create_view({texture_id:?}) -> {id:?}"); @@ -522,7 +473,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(view) = _view.get() { if let Some(t) = view.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyTextureView(texture_view_id)); + t.add(trace::Action::DestroyTextureView(view.to_trace())); } } Ok(()) @@ -547,16 +498,6 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - let planes = Box::from(planes); - trace.add(trace::Action::CreateExternalTexture { - id: fid.id(), - desc: desc.clone(), - planes, - }); - } - let planes = planes .iter() .map(|plane_id| self.hub.texture_views.get(*plane_id).get()) @@ -571,6 +512,21 @@ impl Global { Err(error) => break 'error error, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + let planes = Box::from( + planes + .into_iter() + .map(|plane| plane.to_trace()) + .collect::<Vec<_>>(), + ); + trace.add(trace::Action::CreateExternalTexture { + id: external_texture.to_trace(), + desc: desc.clone(), + planes, + }); + } + let id = fid.assign(Fallible::Valid(external_texture)); api_log!("Device::create_external_texture({desc:?}) -> {id:?}"); @@ -594,7 +550,9 @@ impl Global { #[cfg(feature = "trace")] if let Some(trace) = external_texture.device.trace.lock().as_mut() { - trace.add(trace::Action::FreeExternalTexture(external_texture_id)); + trace.add(trace::Action::FreeExternalTexture( + external_texture.to_trace(), + )); } external_texture.destroy(); @@ -611,7 +569,9 @@ impl Global { #[cfg(feature = "trace")] if let Ok(external_texture) = _external_texture.get() { if let Some(t) = external_texture.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyExternalTexture(external_texture_id)); + t.add(trace::Action::DestroyExternalTexture( + external_texture.to_trace(), + )); } } } @@ -630,16 +590,19 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateSampler(fid.id(), desc.clone())); - } - let sampler = match device.create_sampler(desc) { Ok(sampler) => sampler, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateSampler( + sampler.to_trace(), + desc.clone(), + )); + } + let id = fid.assign(Fallible::Valid(sampler)); api_log!("Device::create_sampler -> {id:?}"); @@ -661,7 +624,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(sampler) = _sampler.get() { if let Some(t) = sampler.device.trace.lock().as_mut() { - t.add(trace::Action::DestroySampler(sampler_id)); + t.add(trace::Action::DestroySampler(sampler.to_trace())); } } } @@ -683,35 +646,19 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateBindGroupLayout(fid.id(), desc.clone())); - } - - // this check can't go in the body of `create_bind_group_layout` since the closure might not get called - if let Err(e) = device.check_is_valid() { - break 'error e.into(); - } - - let entry_map = match bgl::EntryMap::from_entries(&desc.entries) { - Ok(map) => map, - Err(e) => break 'error e, - }; - - let bgl_result = device.bgl_pool.get_or_init(entry_map, |entry_map| { - let bgl = - device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?; - bgl.exclusive_pipeline - .set(binding_model::ExclusivePipeline::None) - .unwrap(); - Ok(bgl) - }); - - let layout = match bgl_result { + let layout = match device.create_bind_group_layout(desc) { Ok(layout) => layout, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateBindGroupLayout( + layout.to_trace(), + desc.clone(), + )); + } + let id = fid.assign(Fallible::Valid(layout.clone())); api_log!("Device::create_bind_group_layout -> {id:?}"); @@ -733,7 +680,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(layout) = _layout.get() { if let Some(t) = layout.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyBindGroupLayout(bind_group_layout_id)); + t.add(trace::Action::DestroyBindGroupLayout(layout.to_trace())); } } } @@ -755,11 +702,6 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreatePipelineLayout(fid.id(), desc.clone())); - } - if let Err(e) = device.check_is_valid() { break 'error e.into(); } @@ -788,6 +730,14 @@ impl Global { Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreatePipelineLayout( + layout.to_trace(), + desc.to_trace(), + )); + } + let id = fid.assign(Fallible::Valid(layout)); api_log!("Device::create_pipeline_layout -> {id:?}"); return (id, None); @@ -808,7 +758,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(layout) = _layout.get() { if let Some(t) = layout.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyPipelineLayout(pipeline_layout_id)); + t.add(trace::Action::DestroyPipelineLayout(layout.to_trace())); } } } @@ -827,11 +777,6 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateBindGroup(fid.id(), desc.clone())); - } - if let Err(e) = device.check_is_valid() { break 'error e.into(); } @@ -959,12 +904,22 @@ impl Global { layout, entries, }; + #[cfg(feature = "trace")] + let trace_desc = (&desc).to_trace(); let bind_group = match device.create_bind_group(desc) { Ok(bind_group) => bind_group, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateBindGroup( + bind_group.to_trace(), + trace_desc, + )); + } + let id = fid.assign(Fallible::Valid(bind_group)); api_log!("Device::create_bind_group -> {id:?}"); @@ -985,9 +940,9 @@ impl Global { let _bind_group = hub.bind_groups.remove(bind_group_id); #[cfg(feature = "trace")] - if let Ok(_bind_group) = _bind_group.get() { - if let Some(t) = _bind_group.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyBindGroup(bind_group_id)); + if let Ok(bind_group) = _bind_group.get() { + if let Some(t) = bind_group.device.trace.lock().as_mut() { + t.add(trace::Action::DestroyBindGroup(bind_group.to_trace())); } } } @@ -1025,42 +980,50 @@ impl Global { let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - let data = match source { - #[cfg(feature = "wgsl")] - pipeline::ShaderModuleSource::Wgsl(ref code) => { - trace.make_binary("wgsl", code.as_bytes()) - } - #[cfg(feature = "glsl")] - pipeline::ShaderModuleSource::Glsl(ref code, _) => { - trace.make_binary("glsl", code.as_bytes()) - } - #[cfg(feature = "spirv")] - pipeline::ShaderModuleSource::SpirV(ref code, _) => { - trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code)) - } - pipeline::ShaderModuleSource::Naga(ref module) => { - let string = - ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default()) - .unwrap(); - trace.make_binary("ron", string.as_bytes()) - } - pipeline::ShaderModuleSource::Dummy(_) => { - panic!("found `ShaderModuleSource::Dummy`") - } - }; - trace.add(trace::Action::CreateShaderModule { - id: fid.id(), - desc: desc.clone(), - data, - }); - }; + let data = device.trace.lock().as_mut().map(|trace| match source { + #[cfg(feature = "wgsl")] + pipeline::ShaderModuleSource::Wgsl(ref code) => { + trace.make_binary("wgsl", code.as_bytes()) + } + #[cfg(feature = "glsl")] + pipeline::ShaderModuleSource::Glsl(ref code, _) => { + trace.make_binary("glsl", code.as_bytes()) + } + #[cfg(feature = "spirv")] + pipeline::ShaderModuleSource::SpirV(ref code, _) => { + trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code)) + } + pipeline::ShaderModuleSource::Naga(ref module) => { + let string = + ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default()) + .unwrap(); + trace.make_binary("ron", string.as_bytes()) + } + pipeline::ShaderModuleSource::Dummy(_) => { + panic!("found `ShaderModuleSource::Dummy`") + } + }); let shader = match device.create_shader_module(desc, source) { Ok(shader) => shader, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(data) = data { + // We don't need these two operations with the trace to be atomic. + device + .trace + .lock() + .as_mut() + .expect("trace went away during create_shader_module?") + .add(trace::Action::CreateShaderModule { + id: shader.to_trace(), + desc: desc.clone(), + data, + }); + }; + let id = fid.assign(Fallible::Valid(shader)); api_log!("Device::create_shader_module -> {id:?}"); return (id, None); @@ -1092,6 +1055,13 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); + let result = unsafe { device.create_shader_module_passthrough(desc) }; + + let shader = match result { + Ok(shader) => shader, + Err(e) => break 'error e, + }; + #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { let mut file_names = Vec::new(); @@ -1108,7 +1078,7 @@ impl Global { } } trace.add(trace::Action::CreateShaderModulePassthrough { - id: fid.id(), + id: shader.to_trace(), data: file_names, entry_point: desc.entry_point.clone(), @@ -1118,12 +1088,6 @@ impl Global { }); }; - let result = unsafe { device.create_shader_module_passthrough(desc) }; - - let shader = match result { - Ok(shader) => shader, - Err(e) => break 'error e, - }; let id = fid.assign(Fallible::Valid(shader)); api_log!("Device::create_shader_module_spirv -> {id:?}"); return (id, None); @@ -1144,7 +1108,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(shader_module) = _shader_module.get() { if let Some(t) = shader_module.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyShaderModule(shader_module_id)); + t.add(trace::Action::DestroyShaderModule(shader_module.to_trace())); } } } @@ -1203,7 +1167,7 @@ impl Global { ) { profiling::scope!("Device::create_render_bundle_encoder"); api_log!("Device::device_create_render_bundle_encoder"); - let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id, None) { + let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id) { Ok(encoder) => (encoder, None), Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)), }; @@ -1226,24 +1190,27 @@ impl Global { let device = self.hub.devices.get(bundle_encoder.parent()); #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateRenderBundle { - id: fid.id(), - desc: trace::new_render_bundle_encoder_descriptor( - desc.label.clone(), - &bundle_encoder.context, - bundle_encoder.is_depth_read_only, - bundle_encoder.is_stencil_read_only, - ), - base: bundle_encoder.to_base_pass(), - }); - } + let trace_desc = trace::new_render_bundle_encoder_descriptor( + desc.label.clone(), + &bundle_encoder.context, + bundle_encoder.is_depth_read_only, + bundle_encoder.is_stencil_read_only, + ); let render_bundle = match bundle_encoder.finish(desc, &device, hub) { Ok(bundle) => bundle, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateRenderBundle { + id: render_bundle.to_trace(), + desc: trace_desc, + base: render_bundle.to_base_pass().to_trace(), + }); + } + let id = fid.assign(Fallible::Valid(render_bundle)); api_log!("RenderBundleEncoder::finish -> {id:?}"); @@ -1265,7 +1232,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(bundle) = _bundle.get() { if let Some(t) = bundle.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyRenderBundle(render_bundle_id)); + t.add(trace::Action::DestroyRenderBundle(bundle.to_trace())); } } } @@ -1284,19 +1251,19 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); + let query_set = match device.create_query_set(desc) { + Ok(query_set) => query_set, + Err(err) => break 'error err, + }; + #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { trace.add(trace::Action::CreateQuerySet { - id: fid.id(), + id: query_set.to_trace(), desc: desc.clone(), }); } - let query_set = match device.create_query_set(desc) { - Ok(query_set) => query_set, - Err(err) => break 'error err, - }; - let id = fid.assign(Fallible::Valid(query_set)); api_log!("Device::create_query_set -> {id:?}"); @@ -1318,7 +1285,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(query_set) = _query_set.get() { if let Some(trace) = query_set.device.trace.lock().as_mut() { - trace.add(trace::Action::DestroyQuerySet(query_set_id)); + trace.add(trace::Action::DestroyQuerySet(query_set.to_trace())); } } } @@ -1339,13 +1306,7 @@ impl Global { let fid = hub.render_pipelines.prepare(id_in); let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateRenderPipeline { - id: fid.id(), - desc: desc.clone(), - }); - } + self.device_create_general_render_pipeline(desc.clone().into(), device, fid) } @@ -1363,13 +1324,6 @@ impl Global { let fid = hub.render_pipelines.prepare(id_in); let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateMeshPipeline { - id: fid.id(), - desc: desc.clone(), - }); - } self.device_create_general_render_pipeline(desc.clone().into(), device, fid) } @@ -1524,15 +1478,26 @@ impl Global { depth_stencil: desc.depth_stencil.clone(), multisample: desc.multisample, fragment, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, cache, }; + #[cfg(feature = "trace")] + let trace_desc = desc.clone().into_trace(); + let pipeline = match device.create_render_pipeline(desc) { Ok(pair) => pair, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateGeneralRenderPipeline { + id: pipeline.to_trace(), + desc: trace_desc, + }); + } + let id = fid.assign(Fallible::Valid(pipeline)); api_log!("Device::create_render_pipeline -> {id:?}"); @@ -1588,7 +1553,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(pipeline) = _pipeline.get() { if let Some(t) = pipeline.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyRenderPipeline(render_pipeline_id)); + t.add(trace::Action::DestroyRenderPipeline(pipeline.to_trace())); } } } @@ -1611,14 +1576,6 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreateComputePipeline { - id: fid.id(), - desc: desc.clone(), - }); - } - if let Err(e) = device.check_is_valid() { break 'error e.into(); } @@ -1660,11 +1617,22 @@ impl Global { cache, }; + #[cfg(feature = "trace")] + let trace_desc = desc.clone().into_trace(); + let pipeline = match device.create_compute_pipeline(desc) { Ok(pair) => pair, Err(e) => break 'error e, }; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreateComputePipeline { + id: pipeline.to_trace(), + desc: trace_desc, + }); + } + let id = fid.assign(Fallible::Valid(pipeline)); api_log!("Device::create_compute_pipeline -> {id:?}"); @@ -1722,7 +1690,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(pipeline) = _pipeline.get() { if let Some(t) = pipeline.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyComputePipeline(compute_pipeline_id)); + t.add(trace::Action::DestroyComputePipeline(pipeline.to_trace())); } } } @@ -1747,17 +1715,17 @@ impl Global { let error: pipeline::CreatePipelineCacheError = 'error: { let device = self.hub.devices.get(device_id); - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::CreatePipelineCache { - id: fid.id(), - desc: desc.clone(), - }); - } - let cache = unsafe { device.create_pipeline_cache(desc) }; match cache { Ok(cache) => { + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::CreatePipelineCache { + id: cache.to_trace(), + desc: desc.clone(), + }); + } + let id = fid.assign(Fallible::Valid(cache)); api_log!("Device::create_pipeline_cache -> {id:?}"); return (id, None); @@ -1782,7 +1750,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(cache) = _cache.get() { if let Some(t) = cache.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyPipelineCache(pipeline_cache_id)); + t.add(trace::Action::DestroyPipelineCache(cache.to_trace())); } } } @@ -1793,276 +1761,18 @@ impl Global { device_id: DeviceId, config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>, ) -> Option<present::ConfigureSurfaceError> { - use present::ConfigureSurfaceError as E; - profiling::scope!("surface_configure"); - - fn validate_surface_configuration( - config: &mut hal::SurfaceConfiguration, - caps: &hal::SurfaceCapabilities, - max_texture_dimension_2d: u32, - ) -> Result<(), E> { - let width = config.extent.width; - let height = config.extent.height; - - if width > max_texture_dimension_2d || height > max_texture_dimension_2d { - return Err(E::TooLarge { - width, - height, - max_texture_dimension_2d, - }); - } - - if !caps.present_modes.contains(&config.present_mode) { - // Automatic present mode checks. - // - // The "Automatic" modes are never supported by the backends. - let fallbacks = match config.present_mode { - wgt::PresentMode::AutoVsync => { - &[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..] - } - // Always end in FIFO to make sure it's always supported - wgt::PresentMode::AutoNoVsync => &[ - wgt::PresentMode::Immediate, - wgt::PresentMode::Mailbox, - wgt::PresentMode::Fifo, - ][..], - _ => { - return Err(E::UnsupportedPresentMode { - requested: config.present_mode, - available: caps.present_modes.clone(), - }); - } - }; - - let new_mode = fallbacks - .iter() - .copied() - .find(|fallback| caps.present_modes.contains(fallback)) - .unwrap_or_else(|| { - unreachable!( - "Fallback system failed to choose present mode. \ - This is a bug. Mode: {:?}, Options: {:?}", - config.present_mode, &caps.present_modes - ); - }); - - api_log!( - "Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}", - config.present_mode - ); - config.present_mode = new_mode; - } - if !caps.formats.contains(&config.format) { - return Err(E::UnsupportedFormat { - requested: config.format, - available: caps.formats.clone(), - }); - } - if !caps - .composite_alpha_modes - .contains(&config.composite_alpha_mode) - { - let new_alpha_mode = 'alpha: { - // Automatic alpha mode checks. - let fallbacks = match config.composite_alpha_mode { - wgt::CompositeAlphaMode::Auto => &[ - wgt::CompositeAlphaMode::Opaque, - wgt::CompositeAlphaMode::Inherit, - ][..], - _ => { - return Err(E::UnsupportedAlphaMode { - requested: config.composite_alpha_mode, - available: caps.composite_alpha_modes.clone(), - }); - } - }; - - for &fallback in fallbacks { - if caps.composite_alpha_modes.contains(&fallback) { - break 'alpha fallback; - } - } - - unreachable!( - "Fallback system failed to choose alpha mode. This is a bug. \ - AlphaMode: {:?}, Options: {:?}", - config.composite_alpha_mode, &caps.composite_alpha_modes - ); - }; + let device = self.hub.devices.get(device_id); + let surface = self.surfaces.get(surface_id); - api_log!( - "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}", - config.composite_alpha_mode - ); - config.composite_alpha_mode = new_alpha_mode; - } - if !caps.usage.contains(config.usage) { - return Err(E::UnsupportedUsage { - requested: config.usage, - available: caps.usage, - }); - } - if width == 0 || height == 0 { - return Err(E::ZeroArea); - } - Ok(()) + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::ConfigureSurface( + surface.to_trace(), + config.clone(), + )); } - log::debug!("configuring surface with {config:?}"); - - let error = 'error: { - // User callbacks must not be called while we are holding locks. - let user_callbacks; - { - let device = self.hub.devices.get(device_id); - - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::ConfigureSurface(surface_id, config.clone())); - } - - if let Err(e) = device.check_is_valid() { - break 'error e.into(); - } - - let surface = self.surfaces.get(surface_id); - - let caps = match surface.get_capabilities(&device.adapter) { - Ok(caps) => caps, - Err(_) => break 'error E::UnsupportedQueueFamily, - }; - - let mut hal_view_formats = Vec::new(); - for format in config.view_formats.iter() { - if *format == config.format { - continue; - } - if !caps.formats.contains(&config.format) { - break 'error E::UnsupportedFormat { - requested: config.format, - available: caps.formats, - }; - } - if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() { - break 'error E::InvalidViewFormat(*format, config.format); - } - hal_view_formats.push(*format); - } - - if !hal_view_formats.is_empty() { - if let Err(missing_flag) = - device.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS) - { - break 'error E::MissingDownlevelFlags(missing_flag); - } - } - - let maximum_frame_latency = config.desired_maximum_frame_latency.clamp( - *caps.maximum_frame_latency.start(), - *caps.maximum_frame_latency.end(), - ); - let mut hal_config = hal::SurfaceConfiguration { - maximum_frame_latency, - present_mode: config.present_mode, - composite_alpha_mode: config.alpha_mode, - format: config.format, - extent: wgt::Extent3d { - width: config.width, - height: config.height, - depth_or_array_layers: 1, - }, - usage: conv::map_texture_usage( - config.usage, - hal::FormatAspects::COLOR, - wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY - | wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY - | wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE, - ), - view_formats: hal_view_formats, - }; - - if let Err(error) = validate_surface_configuration( - &mut hal_config, - &caps, - device.limits.max_texture_dimension_2d, - ) { - break 'error error; - } - - // Wait for all work to finish before configuring the surface. - let snatch_guard = device.snatchable_lock.read(); - let fence = device.fence.read(); - - let maintain_result; - (user_callbacks, maintain_result) = - device.maintain(fence, wgt::PollType::wait_indefinitely(), snatch_guard); - - match maintain_result { - // We're happy - Ok(wgt::PollStatus::QueueEmpty) => {} - Ok(wgt::PollStatus::WaitSucceeded) => { - // After the wait, the queue should be empty. It can only be non-empty - // if another thread is submitting at the same time. - break 'error E::GpuWaitTimeout; - } - Ok(wgt::PollStatus::Poll) => { - unreachable!("Cannot get a Poll result from a Wait action.") - } - Err(WaitIdleError::Timeout) if cfg!(target_arch = "wasm32") => { - // On wasm, you cannot actually successfully wait for the surface. - // However WebGL does not actually require you do this, so ignoring - // the failure is totally fine. See https://github.com/gfx-rs/wgpu/issues/7363 - } - Err(e) => { - break 'error e.into(); - } - } - - // All textures must be destroyed before the surface can be re-configured. - if let Some(present) = surface.presentation.lock().take() { - if present.acquired_texture.is_some() { - break 'error E::PreviousOutputExists; - } - } - - // TODO: Texture views may still be alive that point to the texture. - // this will allow the user to render to the surface texture, long after - // it has been removed. - // - // https://github.com/gfx-rs/wgpu/issues/4105 - - let surface_raw = surface.raw(device.backend()).unwrap(); - match unsafe { surface_raw.configure(device.raw(), &hal_config) } { - Ok(()) => (), - Err(error) => { - break 'error match error { - hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { - E::InvalidSurface - } - hal::SurfaceError::Device(error) => { - E::Device(device.handle_hal_error(error)) - } - hal::SurfaceError::Other(message) => { - log::error!("surface configuration failed: {message}"); - E::InvalidSurface - } - } - } - } - - let mut presentation = surface.presentation.lock(); - *presentation = Some(present::Presentation { - device, - config: config.clone(), - acquired_texture: None, - }); - } - - user_callbacks.fire(); - return None; - }; - - Some(error) + device.configure_surface(&surface, config) } /// Check `device_id` for freeable resources and completed buffer mappings. @@ -2077,30 +1787,13 @@ impl Global { let device = self.hub.devices.get(device_id); - let (closures, result) = Self::poll_single_device(&device, poll_type); + let (closures, result) = device.poll_and_return_closures(poll_type); closures.fire(); result } - fn poll_single_device( - device: &crate::device::Device, - poll_type: wgt::PollType<crate::SubmissionIndex>, - ) -> (UserClosures, Result<wgt::PollStatus, WaitIdleError>) { - let snatch_guard = device.snatchable_lock.read(); - let fence = device.fence.read(); - let maintain_result = device.maintain(fence, poll_type, snatch_guard); - - device.lose_if_oom(); - - // Some deferred destroys are scheduled in maintain so run this right after - // to avoid holding on to them until the next device poll. - device.deferred_resource_destruction(); - - maintain_result - } - /// Poll all devices belonging to the specified backend. /// /// If `force_wait` is true, block until all buffer mappings are done. @@ -2127,7 +1820,7 @@ impl Global { wgt::PollType::Poll }; - let (closures, result) = Self::poll_single_device(device, poll_type); + let (closures, result) = device.poll_and_return_closures(poll_type); let is_queue_empty = matches!(result, Ok(wgt::PollStatus::QueueEmpty)); @@ -2162,14 +1855,12 @@ impl Global { /// /// [api]: ../../wgpu/struct.Device.html#method.start_graphics_debugger_capture pub unsafe fn device_start_graphics_debugger_capture(&self, device_id: DeviceId) { - api_log!("Device::start_graphics_debugger_capture"); - - let device = self.hub.devices.get(device_id); - - if !device.is_valid() { - return; + unsafe { + self.hub + .devices + .get(device_id) + .start_graphics_debugger_capture(); } - unsafe { device.raw().start_graphics_debugger_capture() }; } /// # Safety @@ -2178,14 +1869,12 @@ impl Global { /// /// [api]: ../../wgpu/struct.Device.html#method.stop_graphics_debugger_capture pub unsafe fn device_stop_graphics_debugger_capture(&self, device_id: DeviceId) { - api_log!("Device::stop_graphics_debugger_capture"); - - let device = self.hub.devices.get(device_id); - - if !device.is_valid() { - return; + unsafe { + self.hub + .devices + .get(device_id) + .stop_graphics_debugger_capture(); } - unsafe { device.raw().stop_graphics_debugger_capture() }; } pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option<Vec<u8>> { @@ -2327,69 +2016,9 @@ impl Global { let buffer = hub.buffers.get(buffer_id).get()?; - { - let snatch_guard = buffer.device.snatchable_lock.read(); - buffer.check_destroyed(&snatch_guard)?; - } - - let range_size = if let Some(size) = size { - size - } else { - buffer.size.saturating_sub(offset) - }; - - if offset % wgt::MAP_ALIGNMENT != 0 { - return Err(BufferAccessError::UnalignedOffset { offset }); - } - if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 { - return Err(BufferAccessError::UnalignedRangeSize { range_size }); - } - let map_state = &*buffer.map_state.lock(); - match *map_state { - resource::BufferMapState::Init { ref staging_buffer } => { - // offset (u64) can not be < 0, so no need to validate the lower bound - if offset + range_size > buffer.size { - return Err(BufferAccessError::OutOfBoundsOverrun { - index: offset + range_size - 1, - max: buffer.size, - }); - } - let ptr = unsafe { staging_buffer.ptr() }; - let ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr().offset(offset as isize)) }; - Ok((ptr, range_size)) - } - resource::BufferMapState::Active { - ref mapping, - ref range, - .. - } => { - if offset < range.start { - return Err(BufferAccessError::OutOfBoundsUnderrun { - index: offset, - min: range.start, - }); - } - if offset + range_size > range.end { - return Err(BufferAccessError::OutOfBoundsOverrun { - index: offset + range_size - 1, - max: range.end, - }); - } - // ptr points to the beginning of the range we mapped in map_async - // rather than the beginning of the buffer. - let relative_offset = (offset - range.start) as isize; - unsafe { - Ok(( - NonNull::new_unchecked(mapping.ptr.as_ptr().offset(relative_offset)), - range_size, - )) - } - } - resource::BufferMapState::Idle | resource::BufferMapState::Waiting(_) => { - Err(BufferAccessError::NotMapped) - } - } + buffer.get_mapped_range(offset, size) } + pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult { profiling::scope!("unmap", "Buffer"); api_log!("Buffer::unmap {buffer_id:?}"); @@ -2403,9 +2032,6 @@ impl Global { drop(snatch_guard); buffer.device.check_is_valid()?; - buffer.unmap( - #[cfg(feature = "trace")] - buffer_id, - ) + buffer.unmap() } } diff --git a/third_party/rust/wgpu-core/src/device/mod.rs b/third_party/rust/wgpu-core/src/device/mod.rs @@ -61,7 +61,7 @@ impl<T: PartialEq> Eq for AttachmentData<T> {} pub(crate) struct RenderPassContext { pub attachments: AttachmentData<TextureFormat>, pub sample_count: u32, - pub multiview: Option<NonZeroU32>, + pub multiview_mask: Option<NonZeroU32>, } #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -144,10 +144,10 @@ impl RenderPassContext { res: res.error_ident(), }); } - if self.multiview != other.multiview { + if self.multiview_mask != other.multiview_mask { return Err(RenderPassCompatibilityError::IncompatibleMultiview { - expected: self.multiview, - actual: other.multiview, + expected: self.multiview_mask, + actual: other.multiview_mask, res: res.error_ident(), }); } @@ -510,6 +510,10 @@ pub fn create_validator( Caps::TEXTURE_EXTERNAL, features.intersects(wgt::Features::EXTERNAL_TEXTURE), ); + caps.set( + Caps::SHADER_BARYCENTRICS, + features.intersects(wgt::Features::SHADER_BARYCENTRICS), + ); 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 @@ -15,7 +15,7 @@ use wgt::{ use super::{life::LifetimeTracker, Device}; #[cfg(feature = "trace")] -use crate::device::trace::Action; +use crate::device::trace::{Action, IntoTrace}; use crate::{ api_log, command::{ @@ -521,7 +521,7 @@ impl WebGpuError for QueueSubmitError { impl Queue { pub fn write_buffer( &self, - buffer: Fallible<Buffer>, + buffer: Arc<Buffer>, buffer_offset: wgt::BufferAddress, data: &[u8], ) -> Result<(), QueueWriteError> { @@ -530,8 +530,6 @@ impl Queue { self.device.check_is_valid()?; - let buffer = buffer.get()?; - let data_size = data.len() as wgt::BufferAddress; self.same_device_as(buffer.as_ref())?; @@ -728,7 +726,7 @@ impl Queue { pub fn write_texture( &self, - destination: wgt::TexelCopyTextureInfo<Fallible<Texture>>, + destination: wgt::TexelCopyTextureInfo<Arc<Texture>>, data: &[u8], data_layout: &wgt::TexelCopyBufferLayout, size: &wgt::Extent3d, @@ -738,7 +736,7 @@ impl Queue { self.device.check_is_valid()?; - let dst = destination.texture.get()?; + let dst = destination.texture; let destination = wgt::TexelCopyTextureInfo { texture: (), mip_level: destination.mip_level, @@ -1559,19 +1557,19 @@ impl Global { data: &[u8], ) -> Result<(), QueueWriteError> { let queue = self.hub.queues.get(queue_id); + let buffer = self.hub.buffers.get(buffer_id).get()?; #[cfg(feature = "trace")] if let Some(ref mut trace) = *queue.device.trace.lock() { let data_path = trace.make_binary("bin", data); trace.add(Action::WriteBuffer { - id: buffer_id, + id: buffer.to_trace(), data: data_path, range: buffer_offset..buffer_offset + data.len() as u64, queued: true, }); } - let buffer = self.hub.buffers.get(buffer_id); queue.write_buffer(buffer, buffer_offset, data) } @@ -1624,24 +1622,25 @@ impl Global { size: &wgt::Extent3d, ) -> Result<(), QueueWriteError> { let queue = self.hub.queues.get(queue_id); + let texture = self.hub.textures.get(destination.texture).get()?; + let destination = wgt::TexelCopyTextureInfo { + texture, + mip_level: destination.mip_level, + origin: destination.origin, + aspect: destination.aspect, + }; #[cfg(feature = "trace")] if let Some(ref mut trace) = *queue.device.trace.lock() { let data_path = trace.make_binary("bin", data); trace.add(Action::WriteTexture { - to: *destination, + to: destination.to_trace(), data: data_path, layout: *data_layout, size: *size, }); } - let destination = wgt::TexelCopyTextureInfo { - texture: self.hub.textures.get(destination.texture), - mip_level: destination.mip_level, - origin: destination.origin, - aspect: destination.aspect, - }; queue.write_texture(destination, data, data_layout, size) } diff --git a/third_party/rust/wgpu-core/src/device/ray_tracing.rs b/third_party/rust/wgpu-core/src/device/ray_tracing.rs @@ -2,7 +2,7 @@ use alloc::{string::ToString as _, sync::Arc, vec::Vec}; use core::mem::{size_of, ManuallyDrop}; #[cfg(feature = "trace")] -use crate::device::trace; +use crate::device::trace::{Action, IntoTrace}; use crate::device::DeviceError; use crate::{ api_log, @@ -25,7 +25,7 @@ use hal::AccelerationStructureTriangleIndices; use wgt::Features; impl Device { - fn create_blas( + pub fn create_blas( self: &Arc<Self>, blas_desc: &resource::BlasDescriptor, sizes: wgt::BlasGeometrySizeDescriptors, @@ -172,7 +172,7 @@ impl Device { })) } - fn create_tlas( + pub fn create_tlas( self: &Arc<Self>, desc: &resource::TlasDescriptor, ) -> Result<Arc<resource::Tlas>, CreateTlasError> { @@ -273,13 +273,7 @@ impl Global { let device = self.hub.devices.get(device_id); #[cfg(feature = "trace")] - if let Some(trace) = device.trace.lock().as_mut() { - trace.add(trace::Action::CreateBlas { - id: fid.id(), - desc: desc.clone(), - sizes: sizes.clone(), - }); - } + let trace_sizes = sizes.clone(); let blas = match device.create_blas(desc, sizes) { Ok(blas) => blas, @@ -287,6 +281,15 @@ impl Global { }; let handle = blas.handle; + #[cfg(feature = "trace")] + if let Some(trace) = device.trace.lock().as_mut() { + trace.add(Action::CreateBlas { + id: blas.to_trace(), + desc: desc.clone(), + sizes: trace_sizes, + }); + } + let id = fid.assign(Fallible::Valid(blas)); api_log!("Device::create_blas -> {id:?}"); @@ -310,19 +313,19 @@ impl Global { let error = 'error: { let device = self.hub.devices.get(device_id); + let tlas = match device.create_tlas(desc) { + Ok(tlas) => tlas, + Err(e) => break 'error e, + }; + #[cfg(feature = "trace")] if let Some(trace) = device.trace.lock().as_mut() { - trace.add(trace::Action::CreateTlas { - id: fid.id(), + trace.add(Action::CreateTlas { + id: tlas.to_trace(), desc: desc.clone(), }); } - let tlas = match device.create_tlas(desc) { - Ok(tlas) => tlas, - Err(e) => break 'error e, - }; - let id = fid.assign(Fallible::Valid(tlas)); api_log!("Device::create_tlas -> {id:?}"); @@ -342,7 +345,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(blas) = _blas.get() { if let Some(t) = blas.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyBlas(blas_id)); + t.add(Action::DestroyBlas(blas.to_trace())); } } } @@ -356,7 +359,7 @@ impl Global { #[cfg(feature = "trace")] if let Ok(tlas) = _tlas.get() { if let Some(t) = tlas.device.trace.lock().as_mut() { - t.add(trace::Action::DestroyTlas(tlas_id)); + t.add(Action::DestroyTlas(tlas.to_trace())); } } } diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs @@ -24,6 +24,7 @@ use wgt::{ #[cfg(feature = "trace")] use crate::device::trace; use crate::{ + api_log, binding_model::{self, BindGroup, BindGroupLayout, BindGroupLayoutEntryError}, command, conv, device::{ @@ -39,6 +40,7 @@ use crate::{ lock::{rank, Mutex, RwLock}, pipeline, pool::ResourcePool, + present, resource::{ self, Buffer, ExternalTexture, Fallible, Labeled, ParentDevice, QuerySet, RawResourceAccess, Sampler, StagingBuffer, Texture, TextureView, @@ -336,6 +338,34 @@ impl Device { Err(MissingDownlevelFlags(flags)) } } + + /// # Safety + /// + /// - See [wgpu::Device::start_graphics_debugger_capture][api] for details the safety. + /// + /// [api]: ../../wgpu/struct.Device.html#method.start_graphics_debugger_capture + pub unsafe fn start_graphics_debugger_capture(&self) { + api_log!("Device::start_graphics_debugger_capture"); + + if !self.is_valid() { + return; + } + unsafe { self.raw().start_graphics_debugger_capture() }; + } + + /// # Safety + /// + /// - See [wgpu::Device::stop_graphics_debugger_capture][api] for details the safety. + /// + /// [api]: ../../wgpu/struct.Device.html#method.stop_graphics_debugger_capture + pub unsafe fn stop_graphics_debugger_capture(&self) { + api_log!("Device::stop_graphics_debugger_capture"); + + if !self.is_valid() { + return; + } + unsafe { self.raw().stop_graphics_debugger_capture() }; + } } impl Device { @@ -682,6 +712,38 @@ impl Device { assert!(self.queue.set(Arc::downgrade(queue)).is_ok()); } + pub fn poll( + &self, + poll_type: wgt::PollType<crate::SubmissionIndex>, + ) -> Result<wgt::PollStatus, WaitIdleError> { + let (user_closures, result) = self.poll_and_return_closures(poll_type); + user_closures.fire(); + result + } + + /// Poll the device, returning any `UserClosures` that need to be executed. + /// + /// The caller must invoke the `UserClosures` even if this function returns + /// an error. This is an internal helper, used by `Device::poll` and + /// `Global::poll_all_devices`, so that `poll_all_devices` can invoke + /// closures once after all devices have been polled. + pub(crate) fn poll_and_return_closures( + &self, + poll_type: wgt::PollType<crate::SubmissionIndex>, + ) -> (UserClosures, Result<wgt::PollStatus, WaitIdleError>) { + let snatch_guard = self.snatchable_lock.read(); + let fence = self.fence.read(); + let maintain_result = self.maintain(fence, poll_type, snatch_guard); + + self.lose_if_oom(); + + // Some deferred destroys are scheduled in maintain so run this right after + // to avoid holding on to them until the next device poll. + self.deferred_resource_destruction(); + + maintain_result + } + /// Check the current status of the GPU and process any submissions that have /// finished. /// @@ -851,7 +913,7 @@ impl Device { (user_closures, result) } - pub(crate) fn create_buffer( + pub fn create_buffer( self: &Arc<Self>, desc: &resource::BufferDescriptor, ) -> Result<Arc<Buffer>, resource::CreateBufferError> { @@ -1029,6 +1091,54 @@ impl Device { Ok(buffer) } + #[cfg(feature = "replay")] + pub fn set_buffer_data( + self: &Arc<Self>, + buffer: &Arc<Buffer>, + offset: wgt::BufferAddress, + data: &[u8], + ) -> resource::BufferAccessResult { + use crate::resource::RawResourceAccess; + + let device = &buffer.device; + + device.check_is_valid()?; + buffer.check_usage(wgt::BufferUsages::MAP_WRITE)?; + + let last_submission = device + .get_queue() + .and_then(|queue| queue.lock_life().get_buffer_latest_submission_index(buffer)); + + if let Some(last_submission) = last_submission { + device.wait_for_submit(last_submission)?; + } + + let snatch_guard = device.snatchable_lock.read(); + let raw_buf = buffer.try_raw(&snatch_guard)?; + + let mapping = unsafe { + device + .raw() + .map_buffer(raw_buf, offset..offset + data.len() as u64) + } + .map_err(|e| device.handle_hal_error(e))?; + + unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) }; + + if !mapping.is_coherent { + #[allow(clippy::single_range_in_vec_init)] + unsafe { + device + .raw() + .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64]) + }; + } + + unsafe { device.raw().unmap_buffer(raw_buf) }; + + Ok(()) + } + pub(crate) fn create_texture_from_hal( self: &Arc<Self>, hal_texture: Box<dyn hal::DynTexture>, @@ -1161,7 +1271,7 @@ impl Device { } } - pub(crate) fn create_texture( + pub fn create_texture( self: &Arc<Self>, desc: &resource::TextureDescriptor, ) -> Result<Arc<Texture>, resource::CreateTextureError> { @@ -1250,8 +1360,25 @@ impl Device { } } + let mips = desc.mip_level_count; + let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS); + if mips == 0 || mips > max_levels_allowed { + return Err(CreateTextureError::InvalidMipLevelCount { + requested: mips, + maximum: max_levels_allowed, + }); + } + { - let (width_multiple, height_multiple) = desc.format.size_multiple_requirement(); + let (mut width_multiple, mut height_multiple) = desc.format.size_multiple_requirement(); + + if desc.format.is_multi_planar_format() { + // TODO(https://github.com/gfx-rs/wgpu/issues/8491): fix + // `mip_level_size` calculation for these formats and relax this + // restriction. + width_multiple <<= desc.mip_level_count.saturating_sub(1); + height_multiple <<= desc.mip_level_count.saturating_sub(1); + } if desc.size.width % width_multiple != 0 { return Err(CreateTextureError::InvalidDimension( @@ -1346,16 +1473,24 @@ impl Device { }; } - let mips = desc.mip_level_count; - let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS); - if mips == 0 || mips > max_levels_allowed { - return Err(CreateTextureError::InvalidMipLevelCount { - requested: mips, - maximum: max_levels_allowed, - }); - } + let missing_allowed_usages = match desc.format.planes() { + Some(planes) => { + let mut planes_usages = wgt::TextureUsages::all(); + for plane in 0..planes { + let aspect = wgt::TextureAspect::from_plane(plane).unwrap(); + let format = desc.format.aspect_specific_format(aspect).unwrap(); + let format_features = self + .describe_format_features(format) + .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?; + + planes_usages &= format_features.allowed_usages; + } + + desc.usage - planes_usages + } + None => desc.usage - format_features.allowed_usages, + }; - let missing_allowed_usages = desc.usage - format_features.allowed_usages; if !missing_allowed_usages.is_empty() { // detect downlevel incompatibilities let wgpu_allowed_usages = desc @@ -1482,7 +1617,7 @@ impl Device { Ok(texture) } - pub(crate) fn create_texture_view( + pub fn create_texture_view( self: &Arc<Self>, texture: &Arc<Texture>, desc: &resource::TextureViewDescriptor, @@ -1722,13 +1857,15 @@ impl Device { )); } - if aspects != hal::FormatAspects::from(texture.desc.format) { + if !texture.desc.format.is_multi_planar_format() + && aspects != hal::FormatAspects::from(texture.desc.format) + { break 'error Err(TextureViewNotRenderableReason::Aspects(aspects)); } Ok(texture .desc - .compute_render_extent(desc.range.base_mip_level)) + .compute_render_extent(desc.range.base_mip_level, desc.range.aspect.to_plane())) }; // filter the usages based on the other criteria @@ -1818,7 +1955,7 @@ impl Device { Ok(view) } - pub(crate) fn create_external_texture( + pub fn create_external_texture( self: &Arc<Self>, desc: &resource::ExternalTextureDescriptor, planes: &[Arc<TextureView>], @@ -1896,7 +2033,7 @@ impl Device { }; let params = self.create_buffer(&params_desc)?; self.get_queue().unwrap().write_buffer( - Fallible::Valid(params.clone()), + params.clone(), 0, bytemuck::bytes_of(&params_data), )?; @@ -1913,7 +2050,7 @@ impl Device { Ok(external_texture) } - pub(crate) fn create_sampler( + pub fn create_sampler( self: &Arc<Self>, desc: &resource::SamplerDescriptor, ) -> Result<Arc<Sampler>, resource::CreateSamplerError> { @@ -2024,7 +2161,7 @@ impl Device { Ok(sampler) } - pub(crate) fn create_shader_module<'a>( + pub fn create_shader_module<'a>( self: &Arc<Self>, desc: &pipeline::ShaderModuleDescriptor<'a>, source: pipeline::ShaderModuleSource<'a>, @@ -2152,8 +2289,10 @@ impl Device { Ok(module) } + /// Not a public API. For use by `player` only. #[allow(unused_unsafe)] - pub(crate) unsafe fn create_shader_module_passthrough<'a>( + #[doc(hidden)] + pub unsafe fn create_shader_module_passthrough<'a>( self: &Arc<Self>, descriptor: &pipeline::ShaderModuleDescriptorPassthrough<'a>, ) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> { @@ -2296,7 +2435,32 @@ impl Device { .collect() } - pub(crate) fn create_bind_group_layout( + pub fn create_bind_group_layout( + self: &Arc<Self>, + desc: &binding_model::BindGroupLayoutDescriptor, + ) -> Result<Arc<BindGroupLayout>, binding_model::CreateBindGroupLayoutError> { + self.check_is_valid()?; + + let entry_map = bgl::EntryMap::from_entries(&desc.entries)?; + + let bgl_result = self.bgl_pool.get_or_init(entry_map, |entry_map| { + let bgl = + self.create_bind_group_layout_internal(&desc.label, entry_map, bgl::Origin::Pool)?; + bgl.exclusive_pipeline + .set(binding_model::ExclusivePipeline::None) + .unwrap(); + Ok(bgl) + }); + + match bgl_result { + Ok(layout) => Ok(layout), + Err(e) => Err(e), + } + } + + /// Internal function exposed for use by `player` crate only. + #[doc(hidden)] + pub fn create_bind_group_layout_internal( self: &Arc<Self>, label: &crate::Label, entry_map: bgl::EntryMap, @@ -2913,7 +3077,7 @@ impl Device { // This function expects the provided bind group layout to be resolved // (not passing a duplicate) beforehand. - pub(crate) fn create_bind_group( + pub fn create_bind_group( self: &Arc<Self>, desc: binding_model::ResolvedBindGroupDescriptor, ) -> Result<Arc<BindGroup>, binding_model::CreateBindGroupError> { @@ -3368,7 +3532,7 @@ impl Device { } } - pub(crate) fn create_pipeline_layout( + pub fn create_pipeline_layout( self: &Arc<Self>, desc: &binding_model::ResolvedPipelineLayoutDescriptor, ) -> Result<Arc<binding_model::PipelineLayout>, binding_model::CreatePipelineLayoutError> { @@ -3499,7 +3663,7 @@ impl Device { match unique_bind_group_layouts.entry(bgl_entry_map) { hashbrown::hash_map::Entry::Occupied(v) => Ok(Arc::clone(v.get())), hashbrown::hash_map::Entry::Vacant(e) => { - match self.create_bind_group_layout( + match self.create_bind_group_layout_internal( &None, e.key().clone(), bgl::Origin::Derived, @@ -3525,7 +3689,7 @@ impl Device { Ok(layout) } - pub(crate) fn create_compute_pipeline( + pub fn create_compute_pipeline( self: &Arc<Self>, desc: pipeline::ResolvedComputePipelineDescriptor, ) -> Result<Arc<pipeline::ComputePipeline>, pipeline::CreateComputePipelineError> { @@ -3658,7 +3822,7 @@ impl Device { Ok(pipeline) } - pub(crate) fn create_render_pipeline( + pub fn create_render_pipeline( self: &Arc<Self>, desc: pipeline::ResolvedGeneralRenderPipelineDescriptor, ) -> Result<Arc<pipeline::RenderPipeline>, pipeline::CreateRenderPipelineError> { @@ -4286,8 +4450,11 @@ impl Device { }; // Multiview is only supported if the feature is enabled - if desc.multiview.is_some() { + if let Some(mv_mask) = desc.multiview_mask { self.require_features(wgt::Features::MULTIVIEW)?; + if !(mv_mask.get() + 1).is_power_of_two() { + self.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?; + } } if !self @@ -4337,7 +4504,7 @@ impl Device { multisample: desc.multisample, fragment_stage, color_targets, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, cache: cache.as_ref().map(|it| it.raw()), }; unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err( @@ -4371,7 +4538,7 @@ impl Device { depth_stencil: depth_stencil_state.as_ref().map(|state| state.format), }, sample_count: samples, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, }; let mut flags = pipeline::PipelineFlags::empty(); @@ -4553,7 +4720,7 @@ impl Device { Ok(()) } - pub(crate) fn create_query_set( + pub fn create_query_set( self: &Arc<Self>, desc: &resource::QuerySetDescriptor, ) -> Result<Arc<QuerySet>, resource::CreateQuerySetError> { @@ -4600,6 +4767,274 @@ impl Device { Ok(query_set) } + pub fn configure_surface( + self: &Arc<Self>, + surface: &crate::instance::Surface, + config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>, + ) -> Option<present::ConfigureSurfaceError> { + use present::ConfigureSurfaceError as E; + profiling::scope!("surface_configure"); + + fn validate_surface_configuration( + config: &mut hal::SurfaceConfiguration, + caps: &hal::SurfaceCapabilities, + max_texture_dimension_2d: u32, + ) -> Result<(), E> { + let width = config.extent.width; + let height = config.extent.height; + + if width > max_texture_dimension_2d || height > max_texture_dimension_2d { + return Err(E::TooLarge { + width, + height, + max_texture_dimension_2d, + }); + } + + if !caps.present_modes.contains(&config.present_mode) { + // Automatic present mode checks. + // + // The "Automatic" modes are never supported by the backends. + let fallbacks = match config.present_mode { + wgt::PresentMode::AutoVsync => { + &[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..] + } + // Always end in FIFO to make sure it's always supported + wgt::PresentMode::AutoNoVsync => &[ + wgt::PresentMode::Immediate, + wgt::PresentMode::Mailbox, + wgt::PresentMode::Fifo, + ][..], + _ => { + return Err(E::UnsupportedPresentMode { + requested: config.present_mode, + available: caps.present_modes.clone(), + }); + } + }; + + let new_mode = fallbacks + .iter() + .copied() + .find(|fallback| caps.present_modes.contains(fallback)) + .unwrap_or_else(|| { + unreachable!( + "Fallback system failed to choose present mode. \ + This is a bug. Mode: {:?}, Options: {:?}", + config.present_mode, &caps.present_modes + ); + }); + + api_log!( + "Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}", + config.present_mode + ); + config.present_mode = new_mode; + } + if !caps.formats.contains(&config.format) { + return Err(E::UnsupportedFormat { + requested: config.format, + available: caps.formats.clone(), + }); + } + if !caps + .composite_alpha_modes + .contains(&config.composite_alpha_mode) + { + let new_alpha_mode = 'alpha: { + // Automatic alpha mode checks. + let fallbacks = match config.composite_alpha_mode { + wgt::CompositeAlphaMode::Auto => &[ + wgt::CompositeAlphaMode::Opaque, + wgt::CompositeAlphaMode::Inherit, + ][..], + _ => { + return Err(E::UnsupportedAlphaMode { + requested: config.composite_alpha_mode, + available: caps.composite_alpha_modes.clone(), + }); + } + }; + + for &fallback in fallbacks { + if caps.composite_alpha_modes.contains(&fallback) { + break 'alpha fallback; + } + } + + unreachable!( + "Fallback system failed to choose alpha mode. This is a bug. \ + AlphaMode: {:?}, Options: {:?}", + config.composite_alpha_mode, &caps.composite_alpha_modes + ); + }; + + api_log!( + "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}", + config.composite_alpha_mode + ); + config.composite_alpha_mode = new_alpha_mode; + } + if !caps.usage.contains(config.usage) { + return Err(E::UnsupportedUsage { + requested: config.usage, + available: caps.usage, + }); + } + if width == 0 || height == 0 { + return Err(E::ZeroArea); + } + Ok(()) + } + + log::debug!("configuring surface with {config:?}"); + + let error = 'error: { + // User callbacks must not be called while we are holding locks. + let user_callbacks; + { + if let Err(e) = self.check_is_valid() { + break 'error e.into(); + } + + let caps = match surface.get_capabilities(&self.adapter) { + Ok(caps) => caps, + Err(_) => break 'error E::UnsupportedQueueFamily, + }; + + let mut hal_view_formats = Vec::new(); + for format in config.view_formats.iter() { + if *format == config.format { + continue; + } + if !caps.formats.contains(&config.format) { + break 'error E::UnsupportedFormat { + requested: config.format, + available: caps.formats, + }; + } + if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() { + break 'error E::InvalidViewFormat(*format, config.format); + } + hal_view_formats.push(*format); + } + + if !hal_view_formats.is_empty() { + if let Err(missing_flag) = + self.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS) + { + break 'error E::MissingDownlevelFlags(missing_flag); + } + } + + let maximum_frame_latency = config.desired_maximum_frame_latency.clamp( + *caps.maximum_frame_latency.start(), + *caps.maximum_frame_latency.end(), + ); + let mut hal_config = hal::SurfaceConfiguration { + maximum_frame_latency, + present_mode: config.present_mode, + composite_alpha_mode: config.alpha_mode, + format: config.format, + extent: wgt::Extent3d { + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }, + usage: conv::map_texture_usage( + config.usage, + hal::FormatAspects::COLOR, + wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY + | wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY + | wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE, + ), + view_formats: hal_view_formats, + }; + + if let Err(error) = validate_surface_configuration( + &mut hal_config, + &caps, + self.limits.max_texture_dimension_2d, + ) { + break 'error error; + } + + // Wait for all work to finish before configuring the surface. + let snatch_guard = self.snatchable_lock.read(); + let fence = self.fence.read(); + + let maintain_result; + (user_callbacks, maintain_result) = + self.maintain(fence, wgt::PollType::wait_indefinitely(), snatch_guard); + + match maintain_result { + // We're happy + Ok(wgt::PollStatus::QueueEmpty) => {} + Ok(wgt::PollStatus::WaitSucceeded) => { + // After the wait, the queue should be empty. It can only be non-empty + // if another thread is submitting at the same time. + break 'error E::GpuWaitTimeout; + } + Ok(wgt::PollStatus::Poll) => { + unreachable!("Cannot get a Poll result from a Wait action.") + } + Err(WaitIdleError::Timeout) if cfg!(target_arch = "wasm32") => { + // On wasm, you cannot actually successfully wait for the surface. + // However WebGL does not actually require you do this, so ignoring + // the failure is totally fine. See https://github.com/gfx-rs/wgpu/issues/7363 + } + Err(e) => { + break 'error e.into(); + } + } + + // All textures must be destroyed before the surface can be re-configured. + if let Some(present) = surface.presentation.lock().take() { + if present.acquired_texture.is_some() { + break 'error E::PreviousOutputExists; + } + } + + // TODO: Texture views may still be alive that point to the texture. + // this will allow the user to render to the surface texture, long after + // it has been removed. + // + // https://github.com/gfx-rs/wgpu/issues/4105 + + let surface_raw = surface.raw(self.backend()).unwrap(); + match unsafe { surface_raw.configure(self.raw(), &hal_config) } { + Ok(()) => (), + Err(error) => { + break 'error match error { + hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { + E::InvalidSurface + } + hal::SurfaceError::Device(error) => { + E::Device(self.handle_hal_error(error)) + } + hal::SurfaceError::Other(message) => { + log::error!("surface configuration failed: {message}"); + E::InvalidSurface + } + } + } + } + + let mut presentation = surface.presentation.lock(); + *presentation = Some(present::Presentation { + device: Arc::clone(self), + config: config.clone(), + acquired_texture: None, + }); + } + + user_callbacks.fire(); + return None; + }; + + Some(error) + } + fn lose(&self, message: &str) { // Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device. diff --git a/third_party/rust/wgpu-core/src/device/trace.rs b/third_party/rust/wgpu-core/src/device/trace.rs @@ -1,100 +1,88 @@ -use alloc::{string::String, vec::Vec}; +#[cfg(feature = "trace")] +mod record; + use core::{convert::Infallible, ops::Range}; -#[cfg(feature = "trace")] -use {alloc::borrow::Cow, std::io::Write as _}; +use alloc::{string::String, vec::Vec}; +use macro_rules_attribute::apply; -use crate::{command::Command, id}; +use crate::{ + command::{serde_object_reference_struct, BasePass, Command, ReferenceType, RenderCommand}, + id::{markers, PointerId}, + pipeline::GeneralRenderPipelineDescriptor, +}; -//TODO: consider a readable Id that doesn't include the backend +#[cfg(feature = "trace")] +pub use record::*; type FileName = String; pub const FILE_NAME: &str = "trace.ron"; -#[cfg(feature = "trace")] -pub(crate) fn new_render_bundle_encoder_descriptor<'a>( - label: crate::Label<'a>, - context: &'a super::RenderPassContext, - depth_read_only: bool, - stencil_read_only: bool, -) -> crate::command::RenderBundleEncoderDescriptor<'a> { - crate::command::RenderBundleEncoderDescriptor { - label, - color_formats: Cow::Borrowed(&context.attachments.colors), - depth_stencil: context.attachments.depth_stencil.map(|format| { - wgt::RenderBundleDepthStencil { - format, - depth_read_only, - stencil_read_only, - } - }), - sample_count: context.sample_count, - multiview: context.multiview, - } -} - #[allow(clippy::large_enum_variant)] #[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Action<'a> { +#[apply(serde_object_reference_struct)] +pub enum Action<'a, R: ReferenceType> { Init { desc: crate::device::DeviceDescriptor<'a>, backend: wgt::Backend, }, ConfigureSurface( - id::SurfaceId, + R::Surface, wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>, ), - CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>), - FreeBuffer(id::BufferId), - DestroyBuffer(id::BufferId), - CreateTexture(id::TextureId, crate::resource::TextureDescriptor<'a>), - FreeTexture(id::TextureId), - DestroyTexture(id::TextureId), + CreateBuffer(R::Buffer, crate::resource::BufferDescriptor<'a>), + FreeBuffer(R::Buffer), + DestroyBuffer(R::Buffer), + CreateTexture(R::Texture, crate::resource::TextureDescriptor<'a>), + FreeTexture(R::Texture), + DestroyTexture(R::Texture), CreateTextureView { - id: id::TextureViewId, - parent_id: id::TextureId, + id: R::TextureView, + parent: R::Texture, desc: crate::resource::TextureViewDescriptor<'a>, }, - DestroyTextureView(id::TextureViewId), + DestroyTextureView(R::TextureView), CreateExternalTexture { - id: id::ExternalTextureId, + id: R::ExternalTexture, desc: crate::resource::ExternalTextureDescriptor<'a>, - planes: alloc::boxed::Box<[id::TextureViewId]>, + planes: alloc::boxed::Box<[R::TextureView]>, }, - FreeExternalTexture(id::ExternalTextureId), - DestroyExternalTexture(id::ExternalTextureId), - CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>), - DestroySampler(id::SamplerId), + FreeExternalTexture(R::ExternalTexture), + DestroyExternalTexture(R::ExternalTexture), + CreateSampler( + PointerId<markers::Sampler>, + crate::resource::SamplerDescriptor<'a>, + ), + DestroySampler(PointerId<markers::Sampler>), GetSurfaceTexture { - id: id::TextureId, - parent_id: id::SurfaceId, + id: R::Texture, + parent: R::Surface, }, - Present(id::SurfaceId), - DiscardSurfaceTexture(id::SurfaceId), + Present(R::Surface), + DiscardSurfaceTexture(R::Surface), CreateBindGroupLayout( - id::BindGroupLayoutId, + PointerId<markers::BindGroupLayout>, crate::binding_model::BindGroupLayoutDescriptor<'a>, ), - DestroyBindGroupLayout(id::BindGroupLayoutId), + DestroyBindGroupLayout(PointerId<markers::BindGroupLayout>), CreatePipelineLayout( - id::PipelineLayoutId, - crate::binding_model::PipelineLayoutDescriptor<'a>, - ), - DestroyPipelineLayout(id::PipelineLayoutId), - CreateBindGroup( - id::BindGroupId, - crate::binding_model::BindGroupDescriptor<'a>, + PointerId<markers::PipelineLayout>, + crate::binding_model::ResolvedPipelineLayoutDescriptor< + 'a, + PointerId<markers::BindGroupLayout>, + >, ), - DestroyBindGroup(id::BindGroupId), + DestroyPipelineLayout(PointerId<markers::PipelineLayout>), + CreateBindGroup(PointerId<markers::BindGroup>, TraceBindGroupDescriptor<'a>), + DestroyBindGroup(PointerId<markers::BindGroup>), CreateShaderModule { - id: id::ShaderModuleId, + id: PointerId<markers::ShaderModule>, desc: crate::pipeline::ShaderModuleDescriptor<'a>, data: FileName, }, CreateShaderModulePassthrough { - id: id::ShaderModuleId, + id: PointerId<markers::ShaderModule>, data: Vec<FileName>, entry_point: String, @@ -102,108 +90,88 @@ pub enum Action<'a> { num_workgroups: (u32, u32, u32), runtime_checks: wgt::ShaderRuntimeChecks, }, - DestroyShaderModule(id::ShaderModuleId), + DestroyShaderModule(PointerId<markers::ShaderModule>), CreateComputePipeline { - id: id::ComputePipelineId, - desc: crate::pipeline::ComputePipelineDescriptor<'a>, + id: PointerId<markers::ComputePipeline>, + desc: TraceComputePipelineDescriptor<'a>, }, - DestroyComputePipeline(id::ComputePipelineId), - CreateRenderPipeline { - id: id::RenderPipelineId, - desc: crate::pipeline::RenderPipelineDescriptor<'a>, + DestroyComputePipeline(PointerId<markers::ComputePipeline>), + CreateGeneralRenderPipeline { + id: PointerId<markers::RenderPipeline>, + desc: TraceGeneralRenderPipelineDescriptor<'a>, }, - CreateMeshPipeline { - id: id::RenderPipelineId, - desc: crate::pipeline::MeshPipelineDescriptor<'a>, - }, - DestroyRenderPipeline(id::RenderPipelineId), + DestroyRenderPipeline(PointerId<markers::RenderPipeline>), CreatePipelineCache { - id: id::PipelineCacheId, + id: PointerId<markers::PipelineCache>, desc: crate::pipeline::PipelineCacheDescriptor<'a>, }, - DestroyPipelineCache(id::PipelineCacheId), + DestroyPipelineCache(PointerId<markers::PipelineCache>), CreateRenderBundle { - id: id::RenderBundleId, + id: R::RenderBundle, desc: crate::command::RenderBundleEncoderDescriptor<'a>, - base: crate::command::BasePass<crate::command::RenderCommand, Infallible>, + base: BasePass<RenderCommand<R>, Infallible>, }, - DestroyRenderBundle(id::RenderBundleId), + DestroyRenderBundle(PointerId<markers::RenderBundle>), CreateQuerySet { - id: id::QuerySetId, + id: PointerId<markers::QuerySet>, desc: crate::resource::QuerySetDescriptor<'a>, }, - DestroyQuerySet(id::QuerySetId), + DestroyQuerySet(PointerId<markers::QuerySet>), WriteBuffer { - id: id::BufferId, + id: R::Buffer, data: FileName, range: Range<wgt::BufferAddress>, queued: bool, }, WriteTexture { - to: wgt::TexelCopyTextureInfo<id::TextureId>, + to: wgt::TexelCopyTextureInfo<R::Texture>, data: FileName, layout: wgt::TexelCopyBufferLayout, size: wgt::Extent3d, }, - Submit(crate::SubmissionIndex, Vec<Command>), + Submit(crate::SubmissionIndex, Vec<Command<R>>), CreateBlas { - id: id::BlasId, + id: R::Blas, desc: crate::resource::BlasDescriptor<'a>, sizes: wgt::BlasGeometrySizeDescriptors, }, - DestroyBlas(id::BlasId), + DestroyBlas(R::Blas), CreateTlas { - id: id::TlasId, + id: R::Tlas, desc: crate::resource::TlasDescriptor<'a>, }, - DestroyTlas(id::TlasId), -} - -#[cfg(feature = "trace")] -#[derive(Debug)] -pub struct Trace { - path: std::path::PathBuf, - file: std::fs::File, - config: ron::ser::PrettyConfig, - binary_id: usize, + DestroyTlas(R::Tlas), } -#[cfg(feature = "trace")] -impl Trace { - pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> { - log::info!("Tracing into '{path:?}'"); - let mut file = std::fs::File::create(path.join(FILE_NAME))?; - file.write_all(b"[\n")?; - Ok(Self { - path, - file, - config: ron::ser::PrettyConfig::default(), - binary_id: 0, - }) - } - - pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String { - self.binary_id += 1; - let name = std::format!("data{}.{}", self.binary_id, kind); - let _ = std::fs::write(self.path.join(&name), data); - name - } +/// cbindgen:ignore +pub type TraceBindGroupDescriptor<'a> = crate::binding_model::BindGroupDescriptor< + 'a, + PointerId<markers::BindGroupLayout>, + PointerId<markers::Buffer>, + PointerId<markers::Sampler>, + PointerId<markers::TextureView>, + PointerId<markers::Tlas>, + PointerId<markers::ExternalTexture>, +>; - pub(crate) fn add(&mut self, action: Action) { - match ron::ser::to_string_pretty(&action, self.config.clone()) { - Ok(string) => { - let _ = writeln!(self.file, "{string},"); - } - Err(e) => { - log::warn!("RON serialization failure: {e:?}"); - } - } - } -} +/// Not a public API. For use by `player` only. +/// +/// cbindgen:ignore +#[doc(hidden)] +pub type TraceGeneralRenderPipelineDescriptor<'a> = GeneralRenderPipelineDescriptor< + 'a, + PointerId<markers::PipelineLayout>, + PointerId<markers::ShaderModule>, + PointerId<markers::PipelineCache>, +>; -#[cfg(feature = "trace")] -impl Drop for Trace { - fn drop(&mut self) { - let _ = self.file.write_all(b"]"); - } -} +/// Not a public API. For use by `player` only. +/// +/// cbindgen:ignore +#[doc(hidden)] +pub type TraceComputePipelineDescriptor<'a> = crate::pipeline::ComputePipelineDescriptor< + 'a, + PointerId<markers::PipelineLayout>, + PointerId<markers::ShaderModule>, + PointerId<markers::PipelineCache>, +>; diff --git a/third_party/rust/wgpu-core/src/device/trace/record.rs b/third_party/rust/wgpu-core/src/device/trace/record.rs @@ -0,0 +1,760 @@ +use alloc::{ + borrow::Cow, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; +use core::convert::Infallible; +use std::io::Write as _; + +use crate::{ + command::{ + ArcCommand, ArcComputeCommand, ArcPassTimestampWrites, ArcReferences, ArcRenderCommand, + BasePass, ColorAttachments, Command, ComputeCommand, PointerReferences, RenderCommand, + RenderPassColorAttachment, ResolvedRenderPassDepthStencilAttachment, + }, + id::{markers, PointerId}, + storage::StorageItem, +}; + +use super::{ + Action, TraceBindGroupDescriptor, TraceComputePipelineDescriptor, + TraceGeneralRenderPipelineDescriptor, FILE_NAME, +}; + +pub(crate) fn new_render_bundle_encoder_descriptor( + label: crate::Label<'_>, + context: &crate::device::RenderPassContext, + depth_read_only: bool, + stencil_read_only: bool, +) -> crate::command::RenderBundleEncoderDescriptor<'static> { + crate::command::RenderBundleEncoderDescriptor { + label: label.map(|l| Cow::from(l.to_string())), + color_formats: Cow::from(context.attachments.colors.to_vec()), + depth_stencil: context.attachments.depth_stencil.map(|format| { + wgt::RenderBundleDepthStencil { + format, + depth_read_only, + stencil_read_only, + } + }), + sample_count: context.sample_count, + multiview: context.multiview_mask, + } +} + +#[derive(Debug)] +pub struct Trace { + path: std::path::PathBuf, + file: std::fs::File, + config: ron::ser::PrettyConfig, + binary_id: usize, +} + +impl Trace { + pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> { + log::info!("Tracing into '{path:?}'"); + let mut file = std::fs::File::create(path.join(FILE_NAME))?; + file.write_all(b"[\n")?; + Ok(Self { + path, + file, + config: ron::ser::PrettyConfig::default(), + binary_id: 0, + }) + } + + pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String { + self.binary_id += 1; + let name = std::format!("data{}.{}", self.binary_id, kind); + let _ = std::fs::write(self.path.join(&name), data); + name + } + + pub(crate) fn add(&mut self, action: Action<'_, PointerReferences>) + where + for<'a> Action<'a, PointerReferences>: serde::Serialize, + { + match ron::ser::to_string_pretty(&action, self.config.clone()) { + Ok(string) => { + let _ = writeln!(self.file, "{string},"); + } + Err(e) => { + log::warn!("RON serialization failure: {e:?}"); + } + } + } +} + +impl Drop for Trace { + fn drop(&mut self) { + let _ = self.file.write_all(b"]"); + } +} + +pub(crate) trait IntoTrace { + type Output; + fn into_trace(self) -> Self::Output; + + fn to_trace(&self) -> Self::Output + where + Self: Sized + Clone, + { + self.clone().into_trace() + } +} + +impl<T: StorageItem> IntoTrace for Arc<T> { + type Output = PointerId<T::Marker>; + fn into_trace(self) -> Self::Output { + self.to_trace() + } + + fn to_trace(&self) -> Self::Output { + PointerId::from(self) + } +} + +impl IntoTrace for ArcCommand { + type Output = Command<PointerReferences>; + fn into_trace(self) -> Self::Output { + match self { + ArcCommand::CopyBufferToBuffer { + src, + src_offset, + dst, + dst_offset, + size, + } => Command::CopyBufferToBuffer { + src: src.to_trace(), + src_offset, + dst: dst.to_trace(), + dst_offset, + size, + }, + ArcCommand::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture { + src: src.into_trace(), + dst: dst.into_trace(), + size, + }, + ArcCommand::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer { + src: src.into_trace(), + dst: dst.into_trace(), + size, + }, + ArcCommand::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture { + src: src.into_trace(), + dst: dst.into_trace(), + size, + }, + ArcCommand::ClearBuffer { dst, offset, size } => Command::ClearBuffer { + dst: dst.to_trace(), + offset, + size, + }, + ArcCommand::ClearTexture { + dst, + subresource_range, + } => Command::ClearTexture { + dst: dst.to_trace(), + subresource_range, + }, + ArcCommand::WriteTimestamp { + query_set, + query_index, + } => Command::WriteTimestamp { + query_set: query_set.to_trace(), + query_index, + }, + ArcCommand::ResolveQuerySet { + query_set, + start_query, + query_count, + destination, + destination_offset, + } => Command::ResolveQuerySet { + query_set: query_set.to_trace(), + start_query, + query_count, + destination: destination.to_trace(), + destination_offset, + }, + ArcCommand::PushDebugGroup(label) => Command::PushDebugGroup(label), + ArcCommand::PopDebugGroup => Command::PopDebugGroup, + ArcCommand::InsertDebugMarker(label) => Command::InsertDebugMarker(label), + ArcCommand::RunComputePass { + pass, + timestamp_writes, + } => Command::RunComputePass { + pass: pass.into_trace(), + timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()), + }, + ArcCommand::RunRenderPass { + pass, + color_attachments, + depth_stencil_attachment, + timestamp_writes, + occlusion_query_set, + multiview_mask, + } => Command::RunRenderPass { + pass: pass.into_trace(), + color_attachments: color_attachments.into_trace(), + depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()), + timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()), + occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()), + multiview_mask, + }, + ArcCommand::BuildAccelerationStructures { blas, tlas } => { + Command::BuildAccelerationStructures { + blas: blas.into_iter().map(|b| b.into_trace()).collect(), + tlas: tlas.into_iter().map(|b| b.into_trace()).collect(), + } + } + ArcCommand::TransitionResources { + buffer_transitions: _, + texture_transitions: _, + } => { + // TransitionResources does not exist in Command, so skip or handle as needed. + // If you want to ignore, you could panic or return a default. + panic!("TransitionResources cannot be converted to Command"); + } + } + } +} + +impl<T: IntoTrace> IntoTrace for wgt::TexelCopyBufferInfo<T> { + type Output = wgt::TexelCopyBufferInfo<T::Output>; + fn into_trace(self) -> Self::Output { + wgt::TexelCopyBufferInfo { + buffer: self.buffer.into_trace(), + layout: self.layout, + } + } +} + +impl<T: IntoTrace> IntoTrace for wgt::TexelCopyTextureInfo<T> { + type Output = wgt::TexelCopyTextureInfo<T::Output>; + fn into_trace(self) -> Self::Output { + wgt::TexelCopyTextureInfo { + texture: self.texture.into_trace(), + mip_level: self.mip_level, + origin: self.origin, + aspect: self.aspect, + } + } +} + +impl IntoTrace for ArcPassTimestampWrites { + type Output = crate::command::PassTimestampWrites<PointerId<markers::QuerySet>>; + fn into_trace(self) -> Self::Output { + crate::command::PassTimestampWrites { + query_set: self.query_set.into_trace(), + beginning_of_pass_write_index: self.beginning_of_pass_write_index, + end_of_pass_write_index: self.end_of_pass_write_index, + } + } +} + +impl IntoTrace for ColorAttachments { + type Output = ColorAttachments<PointerId<markers::TextureView>>; + fn into_trace(self) -> Self::Output { + self.into_iter() + .map(|opt| { + opt.map(|att| RenderPassColorAttachment { + view: att.view.into_trace(), + depth_slice: att.depth_slice, + resolve_target: att.resolve_target.map(|r| r.into_trace()), + load_op: att.load_op, + store_op: att.store_op, + }) + }) + .collect() + } +} + +impl<TV: IntoTrace> IntoTrace for ResolvedRenderPassDepthStencilAttachment<TV> { + type Output = ResolvedRenderPassDepthStencilAttachment<TV::Output>; + fn into_trace(self) -> Self::Output { + ResolvedRenderPassDepthStencilAttachment { + view: self.view.into_trace(), + depth: self.depth, + stencil: self.stencil, + } + } +} + +impl IntoTrace for crate::ray_tracing::OwnedBlasBuildEntry<ArcReferences> { + type Output = crate::ray_tracing::OwnedBlasBuildEntry<PointerReferences>; + fn into_trace(self) -> Self::Output { + crate::ray_tracing::OwnedBlasBuildEntry { + blas: self.blas.into_trace(), + geometries: self.geometries.into_trace(), + } + } +} + +impl IntoTrace for crate::ray_tracing::OwnedBlasGeometries<ArcReferences> { + type Output = crate::ray_tracing::OwnedBlasGeometries<PointerReferences>; + fn into_trace(self) -> Self::Output { + match self { + crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => { + crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries( + geos.into_iter().map(|g| g.into_trace()).collect(), + ) + } + } + } +} + +impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> { + type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>; + fn into_trace(self) -> Self::Output { + crate::ray_tracing::OwnedBlasTriangleGeometry { + size: self.size, + vertex_buffer: self.vertex_buffer.into_trace(), + index_buffer: self.index_buffer.map(|b| b.into_trace()), + transform_buffer: self.transform_buffer.map(|b| b.into_trace()), + first_vertex: self.first_vertex, + vertex_stride: self.vertex_stride, + first_index: self.first_index, + transform_buffer_offset: self.transform_buffer_offset, + } + } +} + +impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> { + type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>; + fn into_trace(self) -> Self::Output { + crate::ray_tracing::OwnedTlasPackage { + tlas: self.tlas.into_trace(), + instances: self + .instances + .into_iter() + .map(|opt| opt.map(|inst| inst.into_trace())) + .collect(), + lowest_unmodified: self.lowest_unmodified, + } + } +} + +impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> { + type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>; + fn into_trace(self) -> Self::Output { + crate::ray_tracing::OwnedTlasInstance { + blas: self.blas.into_trace(), + transform: self.transform, + custom_data: self.custom_data, + mask: self.mask, + } + } +} + +impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> { + type Output = BasePass<C::Output, Infallible>; + + fn into_trace(self) -> Self::Output { + BasePass { + label: self.label, + error: self.error, + commands: self + .commands + .into_iter() + .map(|cmd| cmd.into_trace()) + .collect(), + dynamic_offsets: self.dynamic_offsets, + string_data: self.string_data, + push_constant_data: self.push_constant_data, + } + } +} + +impl IntoTrace for ArcComputeCommand { + type Output = ComputeCommand<PointerReferences>; + fn into_trace(self) -> Self::Output { + use ComputeCommand as C; + match self { + C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group.map(|bg| bg.into_trace()), + }, + C::SetPipeline(id) => C::SetPipeline(id.into_trace()), + C::SetPushConstant { + offset, + size_bytes, + values_offset, + } => C::SetPushConstant { + offset, + size_bytes, + values_offset, + }, + C::Dispatch(groups) => C::Dispatch(groups), + C::DispatchIndirect { buffer, offset } => C::DispatchIndirect { + buffer: buffer.into_trace(), + offset, + }, + C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len }, + C::PopDebugGroup => C::PopDebugGroup, + C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len }, + C::WriteTimestamp { + query_set, + query_index, + } => C::WriteTimestamp { + query_set: query_set.into_trace(), + query_index, + }, + C::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => C::BeginPipelineStatisticsQuery { + query_set: query_set.into_trace(), + query_index, + }, + C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery, + } + } +} + +impl IntoTrace for ArcRenderCommand { + type Output = RenderCommand<PointerReferences>; + fn into_trace(self) -> Self::Output { + use RenderCommand as C; + match self { + C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group, + } => C::SetBindGroup { + index, + num_dynamic_offsets, + bind_group: bind_group.map(|bg| bg.into_trace()), + }, + C::SetPipeline(id) => C::SetPipeline(id.into_trace()), + C::SetIndexBuffer { + buffer, + index_format, + offset, + size, + } => C::SetIndexBuffer { + buffer: buffer.into_trace(), + index_format, + offset, + size, + }, + C::SetVertexBuffer { + slot, + buffer, + offset, + size, + } => C::SetVertexBuffer { + slot, + buffer: buffer.into_trace(), + offset, + size, + }, + C::SetBlendConstant(color) => C::SetBlendConstant(color), + C::SetStencilReference(val) => C::SetStencilReference(val), + C::SetViewport { + rect, + depth_min, + depth_max, + } => C::SetViewport { + rect, + depth_min, + depth_max, + }, + C::SetScissor(rect) => C::SetScissor(rect), + C::SetPushConstant { + stages, + offset, + size_bytes, + values_offset, + } => C::SetPushConstant { + stages, + offset, + size_bytes, + values_offset, + }, + C::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + } => C::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }, + C::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + } => C::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }, + C::DrawMeshTasks { + group_count_x, + group_count_y, + group_count_z, + } => C::DrawMeshTasks { + group_count_x, + group_count_y, + group_count_z, + }, + C::DrawIndirect { + buffer, + offset, + count, + family, + vertex_or_index_limit, + instance_limit, + } => C::DrawIndirect { + buffer: buffer.into_trace(), + offset, + count, + family, + vertex_or_index_limit, + instance_limit, + }, + C::MultiDrawIndirectCount { + buffer, + offset, + count_buffer, + count_buffer_offset, + max_count, + family, + } => C::MultiDrawIndirectCount { + buffer: buffer.into_trace(), + offset, + count_buffer: count_buffer.into_trace(), + count_buffer_offset, + max_count, + family, + }, + C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len }, + C::PopDebugGroup => C::PopDebugGroup, + C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len }, + C::WriteTimestamp { + query_set, + query_index, + } => C::WriteTimestamp { + query_set: query_set.into_trace(), + query_index, + }, + C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index }, + C::EndOcclusionQuery => C::EndOcclusionQuery, + C::BeginPipelineStatisticsQuery { + query_set, + query_index, + } => C::BeginPipelineStatisticsQuery { + query_set: query_set.into_trace(), + query_index, + }, + C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery, + C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()), + } + } +} + +impl<'a> IntoTrace for crate::binding_model::ResolvedPipelineLayoutDescriptor<'a> { + type Output = + crate::binding_model::PipelineLayoutDescriptor<'a, PointerId<markers::BindGroupLayout>>; + fn into_trace(self) -> Self::Output { + crate::binding_model::PipelineLayoutDescriptor { + label: self.label.map(|l| Cow::Owned(l.into_owned())), + bind_group_layouts: self + .bind_group_layouts + .iter() + .map(|bgl| bgl.to_trace()) + .collect(), + push_constant_ranges: self.push_constant_ranges.clone(), + } + } +} + +impl<'a> IntoTrace for &'_ crate::binding_model::ResolvedBindGroupDescriptor<'a> { + type Output = TraceBindGroupDescriptor<'a>; + + fn into_trace(self) -> Self::Output { + use crate::binding_model::{ + BindGroupEntry, BindingResource, BufferBinding, ResolvedBindingResource, + }; + TraceBindGroupDescriptor { + label: self.label.clone(), + layout: self.layout.to_trace(), + entries: Cow::Owned( + self.entries + .iter() + .map(|entry| { + let resource = match &entry.resource { + ResolvedBindingResource::Buffer(buffer_binding) => { + BindingResource::Buffer(BufferBinding { + buffer: buffer_binding.buffer.to_trace(), + offset: buffer_binding.offset, + size: buffer_binding.size, + }) + } + ResolvedBindingResource::BufferArray(buffer_bindings) => { + let resolved_buffers: Vec<_> = buffer_bindings + .iter() + .map(|bb| BufferBinding { + buffer: bb.buffer.to_trace(), + offset: bb.offset, + size: bb.size, + }) + .collect(); + BindingResource::BufferArray(Cow::Owned(resolved_buffers)) + } + ResolvedBindingResource::Sampler(sampler_id) => { + BindingResource::Sampler(sampler_id.to_trace()) + } + ResolvedBindingResource::SamplerArray(sampler_ids) => { + let resolved: Vec<_> = + sampler_ids.iter().map(|id| id.to_trace()).collect(); + BindingResource::SamplerArray(Cow::Owned(resolved)) + } + ResolvedBindingResource::TextureView(texture_view_id) => { + BindingResource::TextureView(texture_view_id.to_trace()) + } + ResolvedBindingResource::TextureViewArray(texture_view_ids) => { + let resolved: Vec<_> = + texture_view_ids.iter().map(|id| id.to_trace()).collect(); + BindingResource::TextureViewArray(Cow::Owned(resolved)) + } + ResolvedBindingResource::AccelerationStructure(tlas_id) => { + BindingResource::AccelerationStructure(tlas_id.to_trace()) + } + ResolvedBindingResource::ExternalTexture(external_texture_id) => { + BindingResource::ExternalTexture(external_texture_id.to_trace()) + } + }; + BindGroupEntry { + binding: entry.binding, + resource, + } + }) + .collect(), + ), + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> { + type Output = TraceGeneralRenderPipelineDescriptor<'a>; + + fn into_trace(self) -> Self::Output { + TraceGeneralRenderPipelineDescriptor { + label: self.label, + layout: self.layout.into_trace(), + vertex: self.vertex.into_trace(), + primitive: self.primitive, + depth_stencil: self.depth_stencil, + multisample: self.multisample, + fragment: self.fragment.map(|f| f.into_trace()), + multiview_mask: self.multiview_mask, + cache: self.cache.map(|c| c.into_trace()), + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedComputePipelineDescriptor<'a> { + type Output = TraceComputePipelineDescriptor<'a>; + + fn into_trace(self) -> Self::Output { + TraceComputePipelineDescriptor { + label: self.label, + layout: self.layout.into_trace(), + stage: self.stage.into_trace(), + cache: self.cache.map(|c| c.into_trace()), + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedProgrammableStageDescriptor<'a> { + type Output = + crate::pipeline::ProgrammableStageDescriptor<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + crate::pipeline::ProgrammableStageDescriptor { + module: self.module.into_trace(), + entry_point: self.entry_point, + constants: self.constants, + zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory, + } + } +} + +impl<'a> IntoTrace + for crate::pipeline::RenderPipelineVertexProcessor<'a, Arc<crate::pipeline::ShaderModule>> +{ + type Output = + crate::pipeline::RenderPipelineVertexProcessor<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + match self { + crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => { + crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex.into_trace()) + } + crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => { + crate::pipeline::RenderPipelineVertexProcessor::Mesh( + task.map(|t| t.into_trace()), + mesh.into_trace(), + ) + } + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedTaskState<'a> { + type Output = crate::pipeline::TaskState<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + crate::pipeline::TaskState { + stage: self.stage.into_trace(), + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedMeshState<'a> { + type Output = crate::pipeline::MeshState<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + crate::pipeline::MeshState { + stage: self.stage.into_trace(), + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedVertexState<'a> { + type Output = crate::pipeline::VertexState<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + crate::pipeline::VertexState { + stage: self.stage.into_trace(), + buffers: self.buffers, + } + } +} + +impl<'a> IntoTrace for crate::pipeline::ResolvedFragmentState<'a> { + type Output = crate::pipeline::FragmentState<'a, PointerId<markers::ShaderModule>>; + fn into_trace(self) -> Self::Output { + crate::pipeline::FragmentState { + stage: self.stage.into_trace(), + targets: self.targets, + } + } +} + +impl<T: IntoTrace> IntoTrace for Option<T> { + type Output = Option<T::Output>; + fn into_trace(self) -> Self::Output { + self.map(|v| v.into_trace()) + } +} diff --git a/third_party/rust/wgpu-core/src/id.rs b/third_party/rust/wgpu-core/src/id.rs @@ -82,22 +82,20 @@ impl RawId { /// [`Registry`]: crate::registry::Registry /// [`Noop`]: hal::api::Noop #[repr(transparent)] -#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))] -#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))] -#[cfg_attr( - any(feature = "serde", feature = "trace", feature = "replay"), - serde(transparent) -)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] pub struct Id<T: Marker>(RawId, PhantomData<T>); // This type represents Id in a more readable (and editable) way. -#[allow(dead_code)] +#[cfg(feature = "serde")] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -enum SerialId { +#[derive(Clone, Debug)] +pub enum SerialId { // The only variant forces RON to not ignore "Id" Id(Index, Epoch), } +#[cfg(feature = "serde")] impl From<RawId> for SerialId { fn from(id: RawId) -> Self { let (index, epoch) = id.unzip(); @@ -105,14 +103,17 @@ impl From<RawId> for SerialId { } } +#[cfg(feature = "serde")] pub struct ZeroIdError; +#[cfg(feature = "serde")] impl fmt::Display for ZeroIdError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IDs may not be zero") } } +#[cfg(feature = "serde")] impl TryFrom<SerialId> for RawId { type Error = ZeroIdError; fn try_from(id: SerialId) -> Result<Self, ZeroIdError> { @@ -125,6 +126,61 @@ impl TryFrom<SerialId> for RawId { } } +/// Identify an object by the pointer returned by `Arc::as_ptr`. +/// +/// This is used for tracing. +#[allow(dead_code)] +#[cfg(feature = "serde")] +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum PointerId<T: Marker> { + // The only variant forces RON to not ignore "Id" + PointerId(usize, #[serde(skip)] PhantomData<T>), +} + +#[cfg(feature = "serde")] +impl<T: Marker> Copy for PointerId<T> {} + +#[cfg(feature = "serde")] +impl<T: Marker> Clone for PointerId<T> { + fn clone(&self) -> Self { + *self + } +} + +#[cfg(feature = "serde")] +impl<T: Marker> PartialEq for PointerId<T> { + fn eq(&self, other: &Self) -> bool { + let PointerId::PointerId(this, _) = self; + let PointerId::PointerId(other, _) = other; + this == other + } +} + +#[cfg(feature = "serde")] +impl<T: Marker> Eq for PointerId<T> {} + +#[cfg(feature = "serde")] +impl<T: Marker> Hash for PointerId<T> { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + let PointerId::PointerId(this, _) = self; + this.hash(state); + } +} + +#[cfg(feature = "serde")] +impl<T: crate::storage::StorageItem> From<&alloc::sync::Arc<T>> for PointerId<T::Marker> { + fn from(arc: &alloc::sync::Arc<T>) -> Self { + // Since the memory representation of `Arc<T>` is just a pointer to + // `ArcInner<T>`, it would be nice to use that pointer as the trace ID, + // since many `into_trace` implementations would then be no-ops at + // runtime. However, `Arc::as_ptr` returns a pointer to the contained + // data, not to the `ArcInner`. The `ArcInner` stores the reference + // counts before the data, so the machine code for this conversion has + // to add an offset to the pointer. + PointerId::PointerId(alloc::sync::Arc::as_ptr(arc) as usize, PhantomData) + } +} + impl<T> Id<T> where T: Marker, diff --git a/third_party/rust/wgpu-core/src/pipeline.rs b/third_party/rust/wgpu-core/src/pipeline.rs @@ -425,9 +425,17 @@ pub struct MeshState<'a, SM = ShaderModuleId> { pub type ResolvedMeshState<'a> = MeshState<'a, Arc<ShaderModule>>; +/// Describes a vertex processor for either a conventional or mesh shading +/// pipeline architecture. +/// +/// This is not a public API. It is for use by `player` only. The public APIs +/// are [`VertexState`], [`TaskState`], and [`MeshState`]. +/// +/// cbindgen:ignore +#[doc(hidden)] #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub(crate) enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> { +pub enum RenderPipelineVertexProcessor<'a, SM = ShaderModuleId> { Vertex(VertexState<'a, SM>), Mesh(Option<TaskState<'a, SM>>, MeshState<'a, SM>), } @@ -459,7 +467,7 @@ pub struct RenderPipelineDescriptor< pub fragment: Option<FragmentState<'a, SM>>, /// If the pipeline will be used with a multiview render pass, this indicates how many array /// layers the attachments will have. - pub multiview: Option<NonZeroU32>, + pub multiview_mask: Option<NonZeroU32>, /// The pipeline cache to use when creating this pipeline. pub cache: Option<PLC>, } @@ -497,10 +505,17 @@ pub struct MeshPipelineDescriptor< pub cache: Option<PLC>, } -/// Describes a render (graphics) pipeline. +/// Describes a render (graphics) pipeline, with either conventional or mesh +/// shading architecture. +/// +/// This is not a public API. It is for use by `player` only. The public APIs +/// are [`RenderPipelineDescriptor`] and [`MeshPipelineDescriptor`]. +/// +/// cbindgen:ignore +#[doc(hidden)] #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub(crate) struct GeneralRenderPipelineDescriptor< +pub struct GeneralRenderPipelineDescriptor< 'a, PLL = PipelineLayoutId, SM = ShaderModuleId, @@ -524,7 +539,7 @@ pub(crate) struct GeneralRenderPipelineDescriptor< pub fragment: Option<FragmentState<'a, SM>>, /// If the pipeline will be used with a multiview render pass, this indicates how many array /// layers the attachments will have. - pub multiview: Option<NonZeroU32>, + pub multiview_mask: Option<NonZeroU32>, /// The pipeline cache to use when creating this pipeline. pub cache: Option<PLC>, } @@ -540,7 +555,7 @@ impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>> depth_stencil: value.depth_stencil, multisample: value.multisample, fragment: value.fragment, - multiview: value.multiview, + multiview_mask: value.multiview_mask, cache: value.cache, } } @@ -557,14 +572,16 @@ impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>> depth_stencil: value.depth_stencil, multisample: value.multisample, fragment: value.fragment, - multiview: value.multiview, + multiview_mask: value.multiview, cache: value.cache, } } } +/// Not a public API. For use by `player` only. +/// /// cbindgen:ignore -pub(crate) type ResolvedGeneralRenderPipelineDescriptor<'a> = +pub type ResolvedGeneralRenderPipelineDescriptor<'a> = GeneralRenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>; #[derive(Clone, Debug)] diff --git a/third_party/rust/wgpu-core/src/present.rs b/third_party/rust/wgpu-core/src/present.rs @@ -13,7 +13,7 @@ use alloc::{sync::Arc, vec::Vec}; use core::mem::ManuallyDrop; #[cfg(feature = "trace")] -use crate::device::trace::Action; +use crate::device::trace::{Action, IntoTrace}; use crate::{ conv, device::{Device, DeviceError, MissingDownlevelFlags, WaitIdleError}, @@ -363,10 +363,12 @@ impl Global { #[cfg(feature = "trace")] if let Some(present) = surface.presentation.lock().as_ref() { if let Some(ref mut trace) = *present.device.trace.lock() { - trace.add(Action::GetSurfaceTexture { - id: fid.id(), - parent_id: surface_id, - }); + if let Some(texture) = present.acquired_texture.as_ref() { + trace.add(Action::GetSurfaceTexture { + id: texture.to_trace(), + parent: surface.to_trace(), + }); + } } } @@ -389,7 +391,7 @@ impl Global { #[cfg(feature = "trace")] if let Some(present) = surface.presentation.lock().as_ref() { if let Some(ref mut trace) = *present.device.trace.lock() { - trace.add(Action::Present(surface_id)); + trace.add(Action::Present(surface.to_trace())); } } @@ -402,7 +404,7 @@ impl Global { #[cfg(feature = "trace")] if let Some(present) = surface.presentation.lock().as_ref() { if let Some(ref mut trace) = *present.device.trace.lock() { - trace.add(Action::DiscardSurfaceTexture(surface_id)); + trace.add(Action::DiscardSurfaceTexture(surface.to_trace())); } } diff --git a/third_party/rust/wgpu-core/src/ray_tracing.rs b/third_party/rust/wgpu-core/src/ray_tracing.rs @@ -10,18 +10,22 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec}; +#[cfg(feature = "serde")] +use macro_rules_attribute::apply; use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, AccelerationStructureGeometryFlags, BufferAddress, IndexFormat, VertexFormat, }; +#[cfg(feature = "serde")] +use crate::command::serde_object_reference_struct; use crate::{ - command::EncoderStateError, + command::{ArcReferences, EncoderStateError, IdReferences, ReferenceType}, device::{DeviceError, MissingFeatures}, id::{BlasId, BufferId, TlasId}, resource::{ - Blas, BlasCompactCallback, BlasPrepareCompactResult, Buffer, DestroyedResourceError, + Blas, BlasCompactCallback, BlasPrepareCompactResult, DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, Tlas, }, }; @@ -306,60 +310,62 @@ pub(crate) enum AsAction { /// Like [`BlasTriangleGeometry`], but with owned data. #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TraceBlasTriangleGeometry { +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub struct OwnedBlasTriangleGeometry<R: ReferenceType> { pub size: wgt::BlasTriangleGeometrySizeDescriptor, - pub vertex_buffer: BufferId, - pub index_buffer: Option<BufferId>, - pub transform_buffer: Option<BufferId>, + pub vertex_buffer: R::Buffer, + pub index_buffer: Option<R::Buffer>, + pub transform_buffer: Option<R::Buffer>, pub first_vertex: u32, pub vertex_stride: BufferAddress, pub first_index: Option<u32>, pub transform_buffer_offset: Option<BufferAddress>, } +pub type ArcBlasTriangleGeometry = OwnedBlasTriangleGeometry<ArcReferences>; +pub type TraceBlasTriangleGeometry = OwnedBlasTriangleGeometry<IdReferences>; + #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum TraceBlasGeometries { - TriangleGeometries(Vec<TraceBlasTriangleGeometry>), +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub enum OwnedBlasGeometries<R: ReferenceType> { + TriangleGeometries(Vec<OwnedBlasTriangleGeometry<R>>), } +pub type ArcBlasGeometries = OwnedBlasGeometries<ArcReferences>; +pub type TraceBlasGeometries = OwnedBlasGeometries<IdReferences>; + #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TraceBlasBuildEntry { - pub blas_id: BlasId, - pub geometries: TraceBlasGeometries, +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub struct OwnedBlasBuildEntry<R: ReferenceType> { + pub blas: R::Blas, + pub geometries: OwnedBlasGeometries<R>, } +pub type ArcBlasBuildEntry = OwnedBlasBuildEntry<ArcReferences>; +pub type TraceBlasBuildEntry = OwnedBlasBuildEntry<IdReferences>; + #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TraceTlasInstance { - pub blas_id: BlasId, +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub struct OwnedTlasInstance<R: ReferenceType> { + pub blas: R::Blas, pub transform: [f32; 12], pub custom_data: u32, pub mask: u8, } +pub type ArcTlasInstance = OwnedTlasInstance<ArcReferences>; +pub type TraceTlasInstance = OwnedTlasInstance<IdReferences>; + #[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct TraceTlasPackage { - pub tlas_id: TlasId, - pub instances: Vec<Option<TraceTlasInstance>>, +#[cfg_attr(feature = "serde", apply(serde_object_reference_struct))] +pub struct OwnedTlasPackage<R: ReferenceType> { + pub tlas: R::Tlas, + pub instances: Vec<Option<OwnedTlasInstance<R>>>, pub lowest_unmodified: u32, } -/// Like [`BlasTriangleGeometry`], but with `Arc`s. -#[derive(Debug, Clone)] -pub struct ArcBlasTriangleGeometry { - pub size: wgt::BlasTriangleGeometrySizeDescriptor, - pub vertex_buffer: Arc<Buffer>, - pub index_buffer: Option<Arc<Buffer>>, - pub transform_buffer: Option<Arc<Buffer>>, - pub first_vertex: u32, - pub vertex_stride: BufferAddress, - pub first_index: Option<u32>, - pub transform_buffer_offset: Option<BufferAddress>, -} +pub type TraceTlasPackage = OwnedTlasPackage<IdReferences>; +pub type ArcTlasPackage = OwnedTlasPackage<ArcReferences>; /// [`BlasTriangleGeometry`], without the resources. #[derive(Debug, Clone)] @@ -371,32 +377,6 @@ pub struct BlasTriangleGeometryInfo { pub transform_buffer_offset: Option<BufferAddress>, } -#[derive(Debug, Clone)] -pub enum ArcBlasGeometries { - TriangleGeometries(Vec<ArcBlasTriangleGeometry>), -} - -#[derive(Debug, Clone)] -pub struct ArcBlasBuildEntry { - pub blas: Arc<Blas>, - pub geometries: ArcBlasGeometries, -} - -#[derive(Debug, Clone)] -pub struct ArcTlasInstance { - pub blas: Arc<Blas>, - pub transform: [f32; 12], - pub custom_data: u32, - pub mask: u8, -} - -#[derive(Debug, Clone)] -pub struct ArcTlasPackage { - pub tlas: Arc<Tlas>, - pub instances: Vec<Option<ArcTlasInstance>>, - pub lowest_unmodified: u32, -} - #[derive(Clone, Debug, Error)] pub enum BlasPrepareCompactError { #[error(transparent)] diff --git a/third_party/rust/wgpu-core/src/registry.rs b/third_party/rust/wgpu-core/src/registry.rs @@ -55,11 +55,6 @@ pub(crate) struct FutureId<'a, T: StorageItem> { } impl<T: StorageItem> FutureId<'_, T> { - #[cfg(feature = "trace")] - pub fn id(&self) -> Id<T::Marker> { - self.id - } - /// Assign a new resource to this ID. /// /// Registers it with the registry. diff --git a/third_party/rust/wgpu-core/src/resource.rs b/third_party/rust/wgpu-core/src/resource.rs @@ -573,7 +573,7 @@ impl Buffer { /// Returns the mapping callback in case of error so that the callback can be fired outside /// of the locks that are held in this function. - pub(crate) fn map_async( + pub fn map_async( self: &Arc<Self>, offset: wgt::BufferAddress, size: Option<wgt::BufferAddress>, @@ -677,6 +677,72 @@ impl Buffer { Ok(submit_index) } + pub fn get_mapped_range( + self: &Arc<Self>, + offset: wgt::BufferAddress, + size: Option<wgt::BufferAddress>, + ) -> Result<(NonNull<u8>, u64), BufferAccessError> { + { + let snatch_guard = self.device.snatchable_lock.read(); + self.check_destroyed(&snatch_guard)?; + } + + let range_size = if let Some(size) = size { + size + } else { + self.size.saturating_sub(offset) + }; + + if offset % wgt::MAP_ALIGNMENT != 0 { + return Err(BufferAccessError::UnalignedOffset { offset }); + } + if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 { + return Err(BufferAccessError::UnalignedRangeSize { range_size }); + } + let map_state = &*self.map_state.lock(); + match *map_state { + BufferMapState::Init { ref staging_buffer } => { + // offset (u64) can not be < 0, so no need to validate the lower bound + if offset + range_size > self.size { + return Err(BufferAccessError::OutOfBoundsOverrun { + index: offset + range_size - 1, + max: self.size, + }); + } + let ptr = unsafe { staging_buffer.ptr() }; + let ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr().offset(offset as isize)) }; + Ok((ptr, range_size)) + } + BufferMapState::Active { + ref mapping, + ref range, + .. + } => { + if offset < range.start { + return Err(BufferAccessError::OutOfBoundsUnderrun { + index: offset, + min: range.start, + }); + } + if offset + range_size > range.end { + return Err(BufferAccessError::OutOfBoundsOverrun { + index: offset + range_size - 1, + max: range.end, + }); + } + // ptr points to the beginning of the range we mapped in map_async + // rather than the beginning of the buffer. + let relative_offset = (offset - range.start) as isize; + unsafe { + Ok(( + NonNull::new_unchecked(mapping.ptr.as_ptr().offset(relative_offset)), + range_size, + )) + } + } + BufferMapState::Idle | BufferMapState::Waiting(_) => Err(BufferAccessError::NotMapped), + } + } /// This function returns [`None`] only if [`Self::map_state`] is not [`BufferMapState::Waiting`]. #[must_use] pub(crate) fn map(&self, snatch_guard: &SnatchGuard) -> Option<BufferMapPendingClosure> { @@ -731,14 +797,8 @@ impl Buffer { } // Note: This must not be called while holding a lock. - pub(crate) fn unmap( - self: &Arc<Self>, - #[cfg(feature = "trace")] buffer_id: crate::id::BufferId, - ) -> Result<(), BufferAccessError> { - if let Some((mut operation, status)) = self.unmap_inner( - #[cfg(feature = "trace")] - buffer_id, - )? { + pub fn unmap(self: &Arc<Self>) -> Result<(), BufferAccessError> { + if let Some((mut operation, status)) = self.unmap_inner()? { if let Some(callback) = operation.callback.take() { callback(status); } @@ -747,10 +807,7 @@ impl Buffer { Ok(()) } - fn unmap_inner( - self: &Arc<Self>, - #[cfg(feature = "trace")] buffer_id: crate::id::BufferId, - ) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> { + fn unmap_inner(self: &Arc<Self>) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> { let device = &self.device; let snatch_guard = device.snatchable_lock.read(); let raw_buf = self.try_raw(&snatch_guard)?; @@ -758,9 +815,11 @@ impl Buffer { BufferMapState::Init { staging_buffer } => { #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { + use crate::device::trace::IntoTrace; + let data = trace.make_binary("bin", staging_buffer.get_data()); trace.add(trace::Action::WriteBuffer { - id: buffer_id, + id: self.to_trace(), data, range: 0..self.size, queued: true, @@ -820,12 +879,14 @@ impl Buffer { if host == HostMap::Write { #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { + use crate::device::trace::IntoTrace; + let size = range.end - range.start; let data = trace.make_binary("bin", unsafe { core::slice::from_raw_parts(mapping.ptr.as_ptr(), size as usize) }); trace.add(trace::Action::WriteBuffer { - id: buffer_id, + id: self.to_trace(), data, range: range.clone(), queued: false, @@ -841,7 +902,7 @@ impl Buffer { Ok(None) } - pub(crate) fn destroy(self: &Arc<Self>) { + pub fn destroy(self: &Arc<Self>) { let device = &self.device; let temp = { @@ -1343,7 +1404,7 @@ impl Texture { } } - pub(crate) fn destroy(self: &Arc<Self>) { + pub fn destroy(self: &Arc<Self>) { let device = &self.device; let temp = { @@ -1843,7 +1904,7 @@ impl Drop for ExternalTexture { } impl ExternalTexture { - pub(crate) fn destroy(self: &Arc<Self>) { + pub fn destroy(self: &Arc<Self>) { self.params.destroy(); } } diff --git a/third_party/rust/wgpu-core/src/storage.rs b/third_party/rust/wgpu-core/src/storage.rs @@ -19,7 +19,9 @@ where Occupied(T, Epoch), } -pub(crate) trait StorageItem: ResourceType { +/// Not a public API. For use only by `player`. +#[doc(hidden)] +pub trait StorageItem: ResourceType { type Marker: Marker; } diff --git a/third_party/rust/wgpu-core/src/validation.rs b/third_party/rust/wgpu-core/src/validation.rs @@ -1094,6 +1094,8 @@ impl Interface { wgt::ShaderStages::VERTEX => naga::ShaderStage::Vertex, wgt::ShaderStages::FRAGMENT => naga::ShaderStage::Fragment, wgt::ShaderStages::COMPUTE => naga::ShaderStage::Compute, + wgt::ShaderStages::MESH => naga::ShaderStage::Mesh, + wgt::ShaderStages::TASK => naga::ShaderStage::Task, _ => unreachable!(), } } @@ -1238,7 +1240,7 @@ impl Interface { } // check workgroup size limits - if shader_stage == naga::ShaderStage::Compute { + if shader_stage.compute_like() { let max_workgroup_size_limits = [ self.limits.max_compute_workgroup_size_x, self.limits.max_compute_workgroup_size_y, 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":"c9fb3a416136835a876f6d44bcc350f57d666f20f50f88cd704b33432bf7fa80","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"4861eedb91ca024ede5b18e6db5a861b03f21108de9566bcc4d71bb5720df62a","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"5f4cfa893e99dfec559803bc513457793dcc549154c604385fb287f99a3ea675","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":"7c9cd88b5a20d0daad5c09c3b6a9cab0e1289db229be3839f05c9ea67de2a19f","src/dx12/command.rs":"9aa909aaa12ab9bf09e73f26b7197eee620fe6e9b742b3df90dc352e612d874d","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"53bde57557d80e571257f76933d66475a765e063d8b635675f9dd2563039a4c5","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"592d9336e807e5bbafe204923e6546547160eb660ade038f5707cbd3cb9306fe","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"592a110924259e8754a919bfbc3efda1292f7416a447d585fe56fe910e6225d0","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"014e9ec4a94519b877ad3adc2ea5d182aa6cdf502248009d28dc5833a9edb93c","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"9635dea15d8a885011d2b8b6b9cc5ffe2126cc3f141f47f7aaf46e1f201abea9","src/dynamic/device.rs":"f77c2406f2c42fed77fce29d731b490ac615dae2c5ddb9e01fee4f8ece1b3a34","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"2577d3aef6441f5b42b427d80ba3cf7fee2a97b2fc12335a1fba383e8a79a9b2","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"2a3348204f7489e856d6c37c7e39f92adfbb65308eaeb684c0296e68dc6d76e2","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"6ffb8688de38c2fdd956571dd549535259e2811225adc1df02509e8e642ee775","src/gles/device.rs":"7a8679a4e990bb237cab961b0a2dbdbf5414c57b943048f63f7ddb189932db58","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":"ed0cee8844447b461ed5340f81eb55bb051ceaac67a5768985318ceac133cbe4","src/lib.rs":"b5354488fbffb0ae575700c8f4addec0d8466a402df4eb4ab338a41aae9b683b","src/metal/adapter.rs":"75ddf04c2005238d69e4eed5ac86ea43644089eccf23b39a77ab94753e85f61c","src/metal/command.rs":"20bf613b67ccc043de6e8ad3f3d332bbb678cc06c1593cf1880083de090574ba","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"a293d260b5618b8b8fcb0137c51302989a7982f3db06ca051b5fe898266776f7","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"1bbd3f19d1e518cae6f388da7327279495410e9e50446e1d4bead300855045a5","src/metal/surface.rs":"22dc6da86ac74b044b6498764920f0467bb5060f4dffb156b6c1e260db0c48b7","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"619eb69530736fdcc9fc076eca30191d8d1227abb9cefcf54d717ea93cc4b1a9","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"6bdc81c83dbb651e71bb16dba0d028dd51a415271f086a903784b9c49b4bf717","src/vulkan/command.rs":"22fd05428c141ce58000c8f3541d39195023ffdfb72c4b00379a5c50a3ecea82","src/vulkan/conv.rs":"03eb28b81d3e41ccfcb2b3f7f029cd671ccdf9556594c6d8b6cc2b22144ec4f2","src/vulkan/device.rs":"e034e43f9f344695a44d11186505411549dd1397027977645cbfd56950096289","src/vulkan/drm.rs":"45f7bf1dd854688a65261e4674d80f90c997b193a162fd2ae658acf4e2003552","src/vulkan/instance.rs":"435fb4f22c3c39463f1a33f1a946180656cc7177eeb97035c0458f5d97a1591f","src/vulkan/mod.rs":"d8e724879230eca5a09bf166b103a66a2f1d7a2a8a382bdb1fd1e2c6abc5fdcd","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":"1dfc62b0ffc591efa3f1830df8ac2b7ed566a98667c3a49b2d2c535d3afb6dac","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":"9cb0220f8280070dc8e4e4ab0918ec1dd2c4b7779afee8aaa68638ccda631ea2","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"53bde57557d80e571257f76933d66475a765e063d8b635675f9dd2563039a4c5","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"592d9336e807e5bbafe204923e6546547160eb660ade038f5707cbd3cb9306fe","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"592a110924259e8754a919bfbc3efda1292f7416a447d585fe56fe910e6225d0","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"014e9ec4a94519b877ad3adc2ea5d182aa6cdf502248009d28dc5833a9edb93c","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":"ed0cee8844447b461ed5340f81eb55bb051ceaac67a5768985318ceac133cbe4","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 diff --git a/third_party/rust/wgpu-hal/Cargo.toml b/third_party/rust/wgpu-hal/Cargo.toml @@ -117,6 +117,7 @@ metal = [ "dep:objc", "dep:parking_lot", "dep:profiling", + "dep:smallvec", ] portable-atomic = [ "dep:portable-atomic", diff --git a/third_party/rust/wgpu-hal/examples/halmark/main.rs b/third_party/rust/wgpu-hal/examples/halmark/main.rs @@ -280,7 +280,7 @@ impl<A: hal::Api> Example<A> { blend: Some(wgpu_types::BlendState::ALPHA_BLENDING), write_mask: wgpu_types::ColorWrites::default(), })], - multiview: None, + multiview_mask: None, cache: None, }; let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() }; @@ -727,7 +727,7 @@ impl<A: hal::Api> Example<A> { }, })], depth_stencil_attachment: None, - multiview: None, + multiview_mask: None, timestamp_writes: None, occlusion_query_set: None, }; diff --git a/third_party/rust/wgpu-hal/examples/raw-gles.rs b/third_party/rust/wgpu-hal/examples/raw-gles.rs @@ -329,7 +329,7 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height clear_value: wgpu_types::Color::BLUE, })], depth_stencil_attachment: None, - multiview: None, + multiview_mask: None, timestamp_writes: None, occlusion_query_set: None, }; diff --git a/third_party/rust/wgpu-hal/src/dx12/adapter.rs b/third_party/rust/wgpu-hal/src/dx12/adapter.rs @@ -180,9 +180,9 @@ impl super::Adapter { && features2.DepthBoundsTestSupported.as_bool() }; - let casting_fully_typed_format_supported = { + let (casting_fully_typed_format_supported, view_instancing) = { let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default(); - unsafe { + if unsafe { device.CheckFeatureSupport( Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3, <*mut _>::cast(&mut features3), @@ -190,7 +190,14 @@ impl super::Adapter { ) } .is_ok() - && features3.CastingFullyTypedFormatSupported.as_bool() + { + ( + features3.CastingFullyTypedFormatSupported.as_bool(), + features3.ViewInstancingTier.0 >= Direct3D12::D3D12_VIEW_INSTANCING_TIER_1.0, + ) + } else { + (false, false) + } }; let heap_create_not_zeroed = { @@ -568,6 +575,32 @@ impl super::Adapter { wgt::Features::EXPERIMENTAL_MESH_SHADER, mesh_shader_supported, ); + let shader_barycentrics_supported = { + let mut features3 = Direct3D12::D3D12_FEATURE_DATA_D3D12_OPTIONS3::default(); + unsafe { + device.CheckFeatureSupport( + Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3, + <*mut _>::cast(&mut features3), + size_of_val(&features3) as u32, + ) + } + .is_ok() + && features3.BarycentricsSupported.as_bool() + && shader_model >= naga::back::hlsl::ShaderModel::V6_1 + }; + features.set( + wgt::Features::SHADER_BARYCENTRICS, + 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::EXPERIMENTAL_MESH_SHADER_MULTIVIEW, + mesh_shader_supported && view_instancing, + ); // TODO: Determine if IPresentationManager is supported let presentation_timer = auxil::dxgi::time::PresentationTimer::new_dxgi(); @@ -595,6 +628,9 @@ impl super::Adapter { max_srv_count / 2 }; + // See https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#maximum-viewinstancecount + let max_multiview_view_count = if view_instancing { 4 } else { 0 }; + Some(crate::ExposedAdapter { adapter: super::Adapter { raw: adapter, @@ -694,7 +730,11 @@ impl super::Adapter { max_task_workgroups_per_dimension: Direct3D12::D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, // Multiview not supported by WGPU yet - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: if mesh_shader_supported { + max_multiview_view_count + } else { + 0 + }, // This seems to be right, and I can't find anything to suggest it would be less than the 2048 provided here max_mesh_output_layers: Direct3D12::D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION, @@ -718,6 +758,8 @@ impl super::Adapter { } else { 0 }, + + max_multiview_view_count, }, alignments: crate::Alignments { buffer_copy_offset: wgt::BufferSize::new( diff --git a/third_party/rust/wgpu-hal/src/dx12/command.rs b/third_party/rust/wgpu-hal/src/dx12/command.rs @@ -1024,6 +1024,14 @@ impl crate::CommandEncoder for super::CommandEncoder { } } + if let Some(multiview_mask) = desc.multiview_mask { + unsafe { + list.cast::<Direct3D12::ID3D12GraphicsCommandList2>() + .unwrap() + .SetViewInstanceMask(multiview_mask.get()); + } + } + let raw_vp = Direct3D12::D3D12_VIEWPORT { TopLeftX: 0.0, TopLeftY: 0.0, diff --git a/third_party/rust/wgpu-hal/src/dynamic/command.rs b/third_party/rust/wgpu-hal/src/dynamic/command.rs @@ -415,7 +415,7 @@ impl<C: CommandEncoder + DynResource> DynCommandEncoder for C { .depth_stencil_attachment .as_ref() .map(|ds| ds.expect_downcast()), - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, timestamp_writes: desc .timestamp_writes .as_ref() diff --git a/third_party/rust/wgpu-hal/src/dynamic/device.rs b/third_party/rust/wgpu-hal/src/dynamic/device.rs @@ -407,7 +407,7 @@ impl<D: Device + DynResource> DynDevice for D { multisample: desc.multisample, fragment_stage: desc.fragment_stage.clone().map(|f| f.expect_downcast()), color_targets: desc.color_targets, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, cache: desc.cache.map(|c| c.expect_downcast_ref()), }; diff --git a/third_party/rust/wgpu-hal/src/gles/adapter.rs b/third_party/rust/wgpu-hal/src/gles/adapter.rs @@ -805,13 +805,15 @@ impl super::Adapter { max_task_workgroup_total_count: 0, max_task_workgroups_per_dimension: 0, - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: 0, max_mesh_output_layers: 0, max_blas_primitive_count: 0, max_blas_geometry_count: 0, max_tlas_instance_count: 0, max_acceleration_structures_per_shader_stage: 0, + + max_multiview_view_count: 0, }; let mut workarounds = super::Workarounds::empty(); diff --git a/third_party/rust/wgpu-hal/src/gles/device.rs b/third_party/rust/wgpu-hal/src/gles/device.rs @@ -22,7 +22,7 @@ struct CompilationContext<'a> { sampler_map: &'a mut super::SamplerBindMap, name_binding_map: &'a mut NameBindingMap, push_constant_items: &'a mut Vec<naga::back::glsl::PushConstantItem>, - multiview: Option<NonZeroU32>, + multiview_mask: Option<NonZeroU32>, clip_distance_count: &'a mut u32, } @@ -218,7 +218,9 @@ impl super::Device { let pipeline_options = glsl::PipelineOptions { shader_stage: naga_stage, entry_point: stage.entry_point.to_owned(), - multiview: context.multiview, + multiview: context + .multiview_mask + .map(|a| NonZeroU32::new(a.get().count_ones()).unwrap()), }; let (module, info) = naga::back::pipeline_constants::process_overrides( @@ -306,7 +308,7 @@ impl super::Device { shaders: ArrayVec<ShaderStage<'a>, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, - multiview: Option<NonZeroU32>, + multiview_mask: Option<NonZeroU32>, ) -> Result<Arc<super::PipelineInner>, crate::PipelineError> { let mut program_stages = ArrayVec::new(); let mut group_to_binding_to_slot = Vec::with_capacity(layout.group_infos.len()); @@ -339,7 +341,7 @@ impl super::Device { shaders, layout, label, - multiview, + multiview_mask, self.shared.shading_language_version, self.shared.private_caps, ) @@ -355,7 +357,7 @@ impl super::Device { shaders: ArrayVec<ShaderStage<'a>, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, - multiview: Option<NonZeroU32>, + multiview_mask: Option<NonZeroU32>, glsl_version: naga::back::glsl::Version, private_caps: PrivateCapabilities, ) -> Result<Arc<super::PipelineInner>, crate::PipelineError> { @@ -390,7 +392,7 @@ impl super::Device { sampler_map: &mut sampler_map, name_binding_map: &mut name_binding_map, push_constant_items: pc_item, - multiview, + multiview_mask, clip_distance_count: &mut clip_distance_count, }; @@ -1376,8 +1378,9 @@ impl crate::Device for super::Device { if let Some(ref fs) = desc.fragment_stage { shaders.push((naga::ShaderStage::Fragment, fs)); } - let inner = - unsafe { self.create_pipeline(gl, shaders, desc.layout, desc.label, desc.multiview) }?; + let inner = unsafe { + self.create_pipeline(gl, shaders, desc.layout, desc.label, desc.multiview_mask) + }?; let (vertex_buffers, vertex_attributes) = { let mut buffers = Vec::new(); diff --git a/third_party/rust/wgpu-hal/src/lib.rs b/third_party/rust/wgpu-hal/src/lib.rs @@ -2361,7 +2361,7 @@ pub struct RenderPipelineDescriptor< pub color_targets: &'a [Option<wgt::ColorTargetState>], /// If the pipeline will be used with a multiview render pass, this indicates how many array /// layers the attachments will have. - pub multiview: Option<NonZeroU32>, + pub multiview_mask: Option<NonZeroU32>, /// The cache which will be used and filled when compiling this pipeline pub cache: Option<&'a Pc>, } @@ -2521,7 +2521,7 @@ pub struct RenderPassDescriptor<'a, Q: DynQuerySet + ?Sized, T: DynTextureView + pub sample_count: u32, pub color_attachments: &'a [Option<ColorAttachment<'a, T>>], pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, T>>, - pub multiview: Option<NonZeroU32>, + pub multiview_mask: Option<NonZeroU32>, pub timestamp_writes: Option<PassTimestampWrites<'a, Q>>, pub occlusion_query_set: Option<&'a Q>, } diff --git a/third_party/rust/wgpu-hal/src/metal/adapter.rs b/third_party/rust/wgpu-hal/src/metal/adapter.rs @@ -902,6 +902,17 @@ 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), + supported_vertex_amplification_factor: { + let mut factor = 1; + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=8 + // The table specifies either none, 2, 8, or unsupported, implying it is a relatively small power of 2 + // The bitmask only uses 32 bits, so it can't be higher even if the device for some reason claims to support that. + while factor < 32 && device.supports_vertex_amplification_count(factor * 2) { + factor *= 2 + } + factor as u32 + }, + shader_barycentrics: device.supports_shader_barycentric_coordinates(), // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=3 supports_memoryless_storage: if family_check { device.supports_family(MTLGPUFamily::Apple2) @@ -1003,10 +1014,19 @@ impl super::PrivateCapabilities { features.set(F::RG11B10UFLOAT_RENDERABLE, self.format_rg11b10_all); + features.set( + F::SHADER_BARYCENTRICS, + self.shader_barycentrics && self.msl_version >= MTLLanguageVersion::V2_2, + ); + if self.supports_simd_scoped_operations { features.insert(F::SUBGROUP | F::SUBGROUP_BARRIER); } + if self.supported_vertex_amplification_factor > 1 { + features.insert(F::MULTIVIEW); + } + features } @@ -1037,7 +1057,6 @@ impl super::PrivateCapabilities { downlevel .flags .set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, true); - let base = wgt::Limits::default(); crate::Capabilities { limits: wgt::Limits { @@ -1085,7 +1104,7 @@ impl super::PrivateCapabilities { max_task_workgroup_total_count: 0, max_task_workgroups_per_dimension: 0, - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: 0, max_mesh_output_layers: 0, max_blas_primitive_count: 0, // When added: 2^28 from https://developer.apple.com/documentation/metal/mtlaccelerationstructureusage/extendedlimits @@ -1098,6 +1117,12 @@ impl super::PrivateCapabilities { // > [Acceleration structures] are opaque objects that can be bound directly using // buffer binding points or via argument buffers max_acceleration_structures_per_shader_stage: 0, + + max_multiview_view_count: if self.supported_vertex_amplification_factor > 1 { + self.supported_vertex_amplification_factor + } else { + 0 + }, }, alignments: crate::Alignments { buffer_copy_offset: wgt::BufferSize::new(self.buffer_alignment).unwrap(), diff --git a/third_party/rust/wgpu-hal/src/metal/command.rs b/third_party/rust/wgpu-hal/src/metal/command.rs @@ -9,6 +9,7 @@ use metal::{ MTLIndexType, MTLLoadAction, MTLPrimitiveType, MTLScissorRect, MTLSize, MTLStoreAction, MTLViewport, MTLVisibilityResultMode, NSRange, }; +use smallvec::SmallVec; // has to match `Temp::binding_sizes` const WORD_SIZE: usize = 4; @@ -653,9 +654,33 @@ impl crate::CommandEncoder for super::CommandEncoder { descriptor .set_visibility_result_buffer(Some(occlusion_query_set.raw_buffer.as_ref())) } - + // This strangely isn't mentioned in https://developer.apple.com/documentation/metal/improving-rendering-performance-with-vertex-amplification. + // The docs for [`renderTargetArrayLength`](https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor/rendertargetarraylength) + // also say "The number of active layers that all attachments must have for layered rendering," implying it is only for layered rendering. + // However, when I don't set this, I get undefined behavior in nonzero layers, and all non-apple examples of vertex amplification set it. + // So this is just one of those undocumented requirements. + if let Some(mv) = desc.multiview_mask { + descriptor.set_render_target_array_length(32 - mv.leading_zeros() as u64); + } let raw = self.raw_cmd_buf.as_ref().unwrap(); let encoder = raw.new_render_command_encoder(descriptor); + if let Some(mv) = desc.multiview_mask { + // Most likely the API just wasn't thought about enough. It's not like they ever allow you + // to use enough views to overflow a 32-bit bitmask. + let mv = mv.get(); + let msb = 32 - mv.leading_zeros(); + let mut maps: SmallVec<[metal::VertexAmplificationViewMapping; 32]> = + SmallVec::new(); + for i in 0..msb { + if (mv & (1 << i)) != 0 { + maps.push(metal::VertexAmplificationViewMapping { + renderTargetArrayIndexOffset: i, + viewportArrayIndexOffset: i, + }); + } + } + encoder.set_vertex_amplification_count(mv.count_ones() as u64, Some(&maps)); + } if let Some(label) = desc.label { encoder.set_label(label); } diff --git a/third_party/rust/wgpu-hal/src/metal/device.rs b/third_party/rust/wgpu-hal/src/metal/device.rs @@ -1353,6 +1353,10 @@ impl crate::Device for super::Device { 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 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,8 @@ struct PrivateCapabilities { int64_atomics: bool, float_atomics: bool, supports_shared_event: bool, + supported_vertex_amplification_factor: u32, + shader_barycentrics: bool, supports_memoryless_storage: bool, } diff --git a/third_party/rust/wgpu-hal/src/noop/mod.rs b/third_party/rust/wgpu-hal/src/noop/mod.rs @@ -194,15 +194,17 @@ pub const CAPABILITIES: crate::Capabilities = { max_push_constant_size: ALLOC_MAX_U32, max_non_sampler_bindings: ALLOC_MAX_U32, - max_task_workgroup_total_count: 0, - max_task_workgroups_per_dimension: 0, - max_mesh_multiview_count: 0, - max_mesh_output_layers: 0, + max_task_workgroup_total_count: ALLOC_MAX_U32, + max_task_workgroups_per_dimension: ALLOC_MAX_U32, + max_mesh_multiview_view_count: ALLOC_MAX_U32, + max_mesh_output_layers: ALLOC_MAX_U32, max_blas_primitive_count: ALLOC_MAX_U32, max_blas_geometry_count: ALLOC_MAX_U32, max_tlas_instance_count: ALLOC_MAX_U32, max_acceleration_structures_per_shader_stage: ALLOC_MAX_U32, + + max_multiview_view_count: ALLOC_MAX_U32, }, alignments: crate::Alignments { // All maximally permissive diff --git a/third_party/rust/wgpu-hal/src/vulkan/adapter.rs b/third_party/rust/wgpu-hal/src/vulkan/adapter.rs @@ -19,7 +19,6 @@ const INDEXING_FEATURES: wgt::Features = wgt::Features::TEXTURE_BINDING_ARRAY .union(wgt::Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) .union(wgt::Features::UNIFORM_BUFFER_BINDING_ARRAYS) .union(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY); - #[expect(rustdoc::private_intra_doc_links)] /// Features supported by a [`vk::PhysicalDevice`] and its extensions. /// @@ -128,6 +127,9 @@ pub struct PhysicalDeviceFeatures { /// Features provided by `VK_KHR_shader_integer_dot_product`, promoted to Vulkan 1.3. shader_integer_dot_product: Option<vk::PhysicalDeviceShaderIntegerDotProductFeaturesKHR<'static>>, + + /// Features provided by `VK_KHR_fragment_shader_barycentric` + shader_barycentrics: Option<vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR<'static>>, } impl PhysicalDeviceFeatures { @@ -201,6 +203,9 @@ impl PhysicalDeviceFeatures { if let Some(ref mut feature) = self.shader_integer_dot_product { info = info.push_next(feature); } + if let Some(ref mut feature) = self.shader_barycentrics { + info = info.push_next(feature); + } info } @@ -535,6 +540,17 @@ impl PhysicalDeviceFeatures { } else { None }, + shader_barycentrics: if enabled_extensions + .contains(&khr::fragment_shader_barycentric::NAME) + { + let needed = requested_features.intersects(wgt::Features::SHADER_BARYCENTRICS); + Some( + vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR::default() + .fragment_shader_barycentric(needed), + ) + } else { + None + }, } } @@ -669,6 +685,13 @@ impl PhysicalDeviceFeatures { ); } + if let Some(ref shader_barycentrics) = self.shader_barycentrics { + features.set( + F::SHADER_BARYCENTRICS, + shader_barycentrics.fragment_shader_barycentric != 0, + ); + } + //if caps.supports_extension(khr::sampler_mirror_clamp_to_edge::NAME) { //if caps.supports_extension(ext::sampler_filter_minmax::NAME) { features.set( @@ -724,6 +747,7 @@ impl PhysicalDeviceFeatures { if let Some(ref multiview) = self.multiview { features.set(F::MULTIVIEW, multiview.multiview != 0); + features.set(F::SELECTIVE_MULTIVIEW, multiview.multiview != 0); } features.set( @@ -965,6 +989,9 @@ pub struct PhysicalDeviceProperties { mesh_shader: Option<vk::PhysicalDeviceMeshShaderPropertiesEXT<'static>>, /// Additional `vk::PhysicalDevice` properties from the + /// `VK_KHR_multiview` extension. + multiview: Option<vk::PhysicalDeviceMultiviewPropertiesKHR<'static>>, + /// `VK_EXT_pci_bus_info` extension. pci_bus_info: Option<vk::PhysicalDevicePCIBusInfoPropertiesEXT<'static>>, @@ -1184,6 +1211,11 @@ impl PhysicalDeviceProperties { extensions.push(ext::mesh_shader::NAME); } + // Require `VK_KHR_fragment_shader_barycentric` if the associated feature was requested + if requested_features.intersects(wgt::Features::SHADER_BARYCENTRICS) { + extensions.push(khr::fragment_shader_barycentric::NAME); + } + extensions } @@ -1197,7 +1229,7 @@ impl PhysicalDeviceProperties { let ( max_task_workgroup_total_count, max_task_workgroups_per_dimension, - max_mesh_multiview_count, + max_mesh_multiview_view_count, max_mesh_output_layers, ) = match self.mesh_shader { Some(m) => ( @@ -1259,6 +1291,11 @@ impl PhysicalDeviceProperties { properties.max_per_stage_descriptor_acceleration_structures; } + let max_multiview_view_count = self + .multiview + .map(|a| a.max_multiview_view_count.min(32)) + .unwrap_or(0); + wgt::Limits { max_texture_dimension_1d: limits.max_image_dimension1_d, max_texture_dimension_2d: limits.max_image_dimension2_d, @@ -1319,13 +1356,15 @@ impl PhysicalDeviceProperties { max_task_workgroup_total_count, max_task_workgroups_per_dimension, - max_mesh_multiview_count, + max_mesh_multiview_view_count, max_mesh_output_layers, max_blas_primitive_count, max_blas_geometry_count, max_tlas_instance_count, max_acceleration_structures_per_shader_stage, + + max_multiview_view_count, } } @@ -1384,6 +1423,9 @@ impl super::InstanceShared { capabilities.properties = unsafe { self.raw.get_physical_device_properties(phd) }; capabilities.device_api_version = capabilities.properties.api_version; + let supports_multiview = capabilities.device_api_version >= vk::API_VERSION_1_1 + || capabilities.supports_extension(khr::multiview::NAME); + if let Some(ref get_device_properties) = self.get_physical_device_properties { // Get these now to avoid borrowing conflicts later let supports_maintenance3 = capabilities.device_api_version >= vk::API_VERSION_1_1 @@ -1470,6 +1512,13 @@ impl super::InstanceShared { properties2 = properties2.push_next(next); } + if supports_multiview { + let next = capabilities + .multiview + .insert(vk::PhysicalDeviceMultiviewProperties::default()); + properties2 = properties2.push_next(next); + } + unsafe { get_device_properties.get_physical_device_properties2(phd, &mut properties2) }; @@ -1638,6 +1687,13 @@ impl super::InstanceShared { features2 = features2.push_next(next); } + if capabilities.supports_extension(khr::fragment_shader_barycentric::NAME) { + let next = features + .shader_barycentrics + .insert(vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR::default()); + features2 = features2.push_next(next); + } + unsafe { get_device_properties.get_physical_device_features2(phd, &mut features2) }; features2.features } else { @@ -1858,6 +1914,10 @@ impl super::Instance { shader_int8: phd_features .shader_float16_int8 .is_some_and(|features| features.shader_int8 != 0), + multiview_instance_index_limit: phd_capabilities + .multiview + .map(|a| a.max_multiview_instance_index) + .unwrap_or(0), }; let capabilities = crate::Capabilities { limits: phd_capabilities.to_wgpu_limits(), @@ -2135,6 +2195,10 @@ impl super::Adapter { capabilities.push(spv::Capability::ClipDistance); } + if features.intersects(wgt::Features::SHADER_BARYCENTRICS) { + capabilities.push(spv::Capability::FragmentBarycentricKHR); + } + let mut flags = spv::WriterFlags::empty(); flags.set( spv::WriterFlags::DEBUG, @@ -2157,6 +2221,9 @@ impl super::Adapter { if features.contains(wgt::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN) { capabilities.push(spv::Capability::RayQueryPositionFetchKHR) } + if features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER) { + capabilities.push(spv::Capability::MeshShadingEXT); + } if self.private_caps.shader_integer_dot_product { // See <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_integer_dot_product.html#_new_spir_v_capabilities>. capabilities.extend(&[ diff --git a/third_party/rust/wgpu-hal/src/vulkan/command.rs b/third_party/rust/wgpu-hal/src/vulkan/command.rs @@ -784,7 +784,7 @@ impl crate::CommandEncoder for super::CommandEncoder { colors: ArrayVec::default(), depth_stencil: None, sample_count: desc.sample_count, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, }; let mut fb_key = super::FramebufferKey { raw_pass: vk::RenderPass::null(), @@ -825,15 +825,6 @@ impl crate::CommandEncoder for super::CommandEncoder { vk_clear_values.push(unsafe { mem::zeroed() }); fb_key.push_view(at.view.identified_raw_view()); } - - // Assert this attachment is valid for the detected multiview, as a sanity check - // The driver crash for this is really bad on AMD, so the check is worth it - if let Some(multiview) = desc.multiview { - assert_eq!(cat.target.view.layers, multiview); - if let Some(ref resolve_target) = cat.resolve_target { - assert_eq!(resolve_target.view.layers, multiview); - } - } } else { rp_key.colors.push(None); } @@ -850,12 +841,6 @@ impl crate::CommandEncoder for super::CommandEncoder { stencil_ops: ds.stencil_ops, }); fb_key.push_view(ds.target.view.identified_raw_view()); - - // Assert this attachment is valid for the detected multiview, as a sanity check - // The driver crash for this is really bad on AMD, so the check is worth it - if let Some(multiview) = desc.multiview { - assert_eq!(ds.target.view.layers, multiview); - } } let render_area = vk::Rect2D { @@ -994,6 +979,7 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { unsafe { + self.current_pipeline_is_multiview = pipeline.is_multiview; self.device.raw.cmd_bind_pipeline( self.active, vk::PipelineBindPoint::GRAPHICS, @@ -1081,6 +1067,12 @@ impl crate::CommandEncoder for super::CommandEncoder { first_instance: u32, instance_count: u32, ) { + if self.current_pipeline_is_multiview + && (first_instance as u64 + instance_count as u64 - 1) + > self.device.private_caps.multiview_instance_index_limit as u64 + { + panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)"); + } unsafe { self.device.raw.cmd_draw( self.active, @@ -1099,6 +1091,12 @@ impl crate::CommandEncoder for super::CommandEncoder { first_instance: u32, instance_count: u32, ) { + if self.current_pipeline_is_multiview + && (first_instance as u64 + instance_count as u64 - 1) + > self.device.private_caps.multiview_instance_index_limit as u64 + { + panic!("This vulkan device is affected by [#8333](https://github.com/gfx-rs/wgpu/issues/8333)"); + } unsafe { self.device.raw.cmd_draw_indexed( self.active, diff --git a/third_party/rust/wgpu-hal/src/vulkan/device.rs b/third_party/rust/wgpu-hal/src/vulkan/device.rs @@ -84,7 +84,7 @@ impl super::DeviceShared { ref colors, ref depth_stencil, sample_count, - multiview, + multiview_mask, } = *e.key(); let mut vk_attachments = Vec::new(); @@ -209,15 +209,8 @@ impl super::DeviceShared { let mut multiview_info; let mask; - if let Some(multiview) = multiview { - // Sanity checks, better to panic here than cause a driver crash - assert!(multiview.get() <= 8); - assert!(multiview.get() > 1); - - // Right now we enable all bits on the view masks and correlation masks. - // This means we're rendering to all views in the subpass, and that all views - // can be rendered concurrently. - mask = [(1 << multiview.get()) - 1]; + if let Some(multiview_mask) = multiview_mask { + mask = [multiview_mask.get()]; // On Vulkan 1.1 or later, this is an alias for core functionality multiview_info = vk::RenderPassMultiviewCreateInfoKHR::default() @@ -590,7 +583,8 @@ impl super::Device { } } if desc.format.is_multi_planar_format() { - raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT; + raw_flags |= + vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE; } let mut vk_info = vk::ImageCreateInfo::default() @@ -1260,7 +1254,7 @@ impl crate::Device for super::Device { Ok(super::TextureView { raw_texture: texture.raw, raw, - layers, + _layers: layers, format: desc.format, raw_format, base_mip_level: desc.range.base_mip_level, @@ -1367,6 +1361,7 @@ impl crate::Device for super::Device { framebuffers: Default::default(), temp_texture_views: Default::default(), counters: Arc::clone(&self.counters), + current_pipeline_is_multiview: false, }) } @@ -1886,7 +1881,7 @@ impl crate::Device for super::Device { ]; let mut compatible_rp_key = super::RenderPassKey { sample_count: desc.multisample.count, - multiview: desc.multiview, + multiview_mask: desc.multiview_mask, ..Default::default() }; let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); @@ -2155,7 +2150,10 @@ impl crate::Device for super::Device { self.counters.render_pipelines.add(1); - Ok(super::RenderPipeline { raw }) + Ok(super::RenderPipeline { + raw, + is_multiview: desc.multiview_mask.is_some(), + }) } unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) { diff --git a/third_party/rust/wgpu-hal/src/vulkan/mod.rs b/third_party/rust/wgpu-hal/src/vulkan/mod.rs @@ -376,6 +376,17 @@ struct PrivateCapabilities { /// [`VK_KHR_shader_float16_int8`]: https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_shader_float16_int8.html /// [see spec]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDeviceShaderFloat16Int8Features.html#extension-features-shaderInt8 shader_int8: bool, + + /// This is done to panic before undefined behavior, and is imperfect. + /// Basically, to allow implementations to emulate mv using instancing, if you + /// want to draw `n` instances to VR, you must draw `2n` instances, but you + /// can never draw more than `u32::MAX` instances. Therefore, when drawing + /// multiview on some vulkan implementations, it might restrict the instance + /// count, which isn't usually a thing in webgpu. We don't expose this limit + /// because its strange, i.e. only occurs on certain vulkan implementations + /// if you are drawing more than 128 million instances. We still want to avoid + /// undefined behavior in this situation, so we panic if the limit is violated. + multiview_instance_index_limit: u32, } bitflags::bitflags!( @@ -447,7 +458,7 @@ struct RenderPassKey { colors: ArrayVec<Option<ColorAttachmentKey>, { crate::MAX_COLOR_ATTACHMENTS }>, depth_stencil: Option<DepthStencilAttachmentKey>, sample_count: u32, - multiview: Option<NonZeroU32>, + multiview_mask: Option<NonZeroU32>, } struct DeviceShared { @@ -720,7 +731,7 @@ impl Texture { pub struct TextureView { raw_texture: vk::Image, raw: vk::ImageView, - layers: NonZeroU32, + _layers: NonZeroU32, format: wgt::TextureFormat, raw_format: vk::Format, base_mip_level: u32, @@ -953,6 +964,8 @@ pub struct CommandEncoder { temp_texture_views: FastHashMap<TempTextureViewKey, IdentifiedTextureView>, counters: Arc<wgt::HalCounters>, + + current_pipeline_is_multiview: bool, } impl Drop for CommandEncoder { @@ -1025,6 +1038,7 @@ impl crate::DynShaderModule for ShaderModule {} #[derive(Debug)] pub struct RenderPipeline { raw: vk::Pipeline, + is_multiview: bool, } impl crate::DynRenderPipeline for RenderPipeline {} 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":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"ab880ecf55be2a93244d1a03119d10ee15eddc076f100ae03d13b51eaa815b57","src/instance.rs":"deeb5ca694163baf46c386316a498cee011cf960d48b749d4cd01125e9fca57f","src/lib.rs":"18a96688b43d81dc1537594f103716be27257a63249c1794d1c06e2c46b451b4","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":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","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 diff --git a/third_party/rust/wgpu-types/src/features.rs b/third_party/rust/wgpu-types/src/features.rs @@ -915,12 +915,15 @@ bitflags_array! { /// /// This is a native only feature. const CLEAR_TEXTURE = 1 << 23; - /// Enables multiview render passes and `builtin(view_index)` in vertex shaders. + /// Enables multiview render passes and `builtin(view_index)` in vertex/mesh shaders. /// /// Supported platforms: /// - Vulkan + /// - Metal /// - 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. @@ -1231,6 +1234,27 @@ bitflags_array! { /// /// [`Device::create_shader_module_passthrough`]: https://docs.rs/wgpu/latest/wgpu/struct.Device.html#method.create_shader_module_passthrough const EXPERIMENTAL_PASSTHROUGH_SHADERS = 1 << 52; + + /// Enables shader barycentric coordinates. + /// + /// Supported platforms: + /// - Vulkan (with VK_KHR_fragment_shader_barycentric) + /// - DX12 (with SM 6.1+) + /// - Metal (with MSL 2.2+) + /// + /// This is a native only feature. + const SHADER_BARYCENTRICS = 1 << 53; + + /// Enables using multiview where not all texture array layers are rendered to in a single render pass/render pipeline. Making + /// use of this feature also requires enabling `Features::MULTIVIEW`. + /// + /// Supported platforms + /// - Vulkan + /// + /// 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; } /// Features that are not guaranteed to be supported. diff --git a/third_party/rust/wgpu-types/src/lib.rs b/third_party/rust/wgpu-types/src/lib.rs @@ -519,12 +519,14 @@ macro_rules! with_limits { $macro_name!(max_task_workgroup_total_count, Ordering::Less); $macro_name!(max_task_workgroups_per_dimension, Ordering::Less); - $macro_name!(max_mesh_multiview_count, Ordering::Less); + $macro_name!(max_mesh_multiview_view_count, Ordering::Less); $macro_name!(max_mesh_output_layers, Ordering::Less); $macro_name!(max_blas_primitive_count, Ordering::Less); $macro_name!(max_blas_geometry_count, Ordering::Less); $macro_name!(max_tlas_instance_count, Ordering::Less); + + $macro_name!(max_multiview_view_count, Ordering::Less); }; } @@ -694,8 +696,8 @@ pub struct Limits { pub max_task_workgroups_per_dimension: u32, /// The maximum number of layers that can be output from a mesh shader pub max_mesh_output_layers: u32, - /// The maximum number of views that can be used by a mesh shader - pub max_mesh_multiview_count: u32, + /// The maximum number of views that can be used by a mesh shader in multiview rendering + pub max_mesh_multiview_view_count: u32, /// The maximum number of primitive (ex: triangles, aabbs) a BLAS is allowed to have. Requesting /// more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`] @@ -713,6 +715,9 @@ pub struct Limits { /// Requesting more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`] /// is enabled. pub max_acceleration_structures_per_shader_stage: u32, + + /// The maximum number of views that can be used in multiview rendering + pub max_multiview_view_count: u32, } impl Default for Limits { @@ -767,12 +772,13 @@ impl Limits { /// max_non_sampler_bindings: 1_000_000, /// max_task_workgroup_total_count: 0, /// max_task_workgroups_per_dimension: 0, - /// max_mesh_multiview_count: 0, + /// max_mesh_multiview_view_count: 0, /// max_mesh_output_layers: 0, /// max_blas_primitive_count: 0, /// max_blas_geometry_count: 0, /// max_tlas_instance_count: 0, /// max_acceleration_structures_per_shader_stage: 0, + /// max_multiview_view_count: 0, /// }); /// ``` /// @@ -820,13 +826,15 @@ impl Limits { max_task_workgroup_total_count: 0, max_task_workgroups_per_dimension: 0, - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: 0, max_mesh_output_layers: 0, max_blas_primitive_count: 0, max_blas_geometry_count: 0, max_tlas_instance_count: 0, max_acceleration_structures_per_shader_stage: 0, + + max_multiview_view_count: 0, } } @@ -875,13 +883,15 @@ impl Limits { /// /// max_task_workgroup_total_count: 0, /// max_task_workgroups_per_dimension: 0, - /// max_mesh_multiview_count: 0, + /// max_mesh_multiview_view_count: 0, /// max_mesh_output_layers: 0, /// /// max_blas_primitive_count: 0, /// max_blas_geometry_count: 0, /// max_tlas_instance_count: 0, /// max_acceleration_structures_per_shader_stage: 0, + /// + /// max_multiview_view_count: 0, /// }); /// ``` #[must_use] @@ -898,7 +908,7 @@ impl Limits { max_task_workgroups_per_dimension: 0, max_task_workgroup_total_count: 0, - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: 0, max_mesh_output_layers: 0, ..Self::defaults() } @@ -950,13 +960,15 @@ impl Limits { /// /// max_task_workgroup_total_count: 0, /// max_task_workgroups_per_dimension: 0, - /// max_mesh_multiview_count: 0, + /// max_mesh_multiview_view_count: 0, /// max_mesh_output_layers: 0, /// /// max_blas_primitive_count: 0, /// max_blas_geometry_count: 0, /// max_tlas_instance_count: 0, /// max_acceleration_structures_per_shader_stage: 0, + /// + /// max_multiview_view_count: 0, /// }); /// ``` #[must_use] @@ -1018,7 +1030,7 @@ impl Limits { Self { max_blas_geometry_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum max_tlas_instance_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum - max_blas_primitive_count: 1 << 28, // 2^28: Metal's minimum + max_blas_primitive_count: (1 << 24) - 1, // Should be 2^28: Metal's minimum, but due to an llvmpipe bug it is 2^24 - 1 max_acceleration_structures_per_shader_stage: 16, // Vulkan's minimum ..self } @@ -1051,7 +1063,7 @@ impl Limits { max_task_workgroup_total_count: 65536, max_task_workgroups_per_dimension: 256, // llvmpipe reports 0 multiview count, which just means no multiview is allowed - max_mesh_multiview_count: 0, + max_mesh_multiview_view_count: 0, // llvmpipe once again requires this to be 8. An RTX 3060 supports well over 1024. max_mesh_output_layers: 8, ..self @@ -2772,6 +2784,17 @@ impl TextureAspect { _ => return None, }) } + + /// Returns the plane for a given texture aspect. + #[must_use] + pub fn to_plane(&self) -> Option<u32> { + match self { + TextureAspect::Plane0 => Some(0), + TextureAspect::Plane1 => Some(1), + TextureAspect::Plane2 => Some(2), + _ => None, + } + } } // There are some additional texture format helpers in `wgpu-core/src/conv.rs`, @@ -2858,6 +2881,20 @@ impl TextureFormat { } } + /// Returns the subsampling factor for the indicated plane of a multi-planar format. + #[must_use] + pub fn subsampling_factors(&self, plane: Option<u32>) -> (u32, u32) { + match *self { + Self::NV12 | Self::P010 => match plane { + Some(0) => (1, 1), + Some(1) => (2, 2), + Some(plane) => unreachable!("plane {plane} is not valid for {self:?}"), + None => unreachable!("the plane must be specified for multi-planar formats"), + }, + _ => (1, 1), + } + } + /// Returns `true` if the format has a color aspect #[must_use] pub fn has_color_aspect(&self) -> bool { @@ -2887,6 +2924,10 @@ impl TextureFormat { } /// Returns the size multiple requirement for a texture using this format. + /// + /// `create_texture` currently enforces a stricter restriction than this for + /// mipmapped multi-planar formats. + /// TODO(<https://github.com/gfx-rs/wgpu/issues/8491>): Remove this note. #[must_use] pub fn size_multiple_requirement(&self) -> (u32, u32) { match *self { @@ -5346,6 +5387,8 @@ bitflags::bitflags! { bitflags::bitflags! { /// Similar to `BufferUsages`, but used only for `CommandEncoder::transition_resources`. + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "serde", serde(transparent))] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct BufferUses: u16 { /// The argument to a read-only mapping. @@ -5397,6 +5440,7 @@ bitflags::bitflags! { /// A buffer transition for use with `CommandEncoder::transition_resources`. #[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BufferTransition<T> { /// The buffer to transition. pub buffer: T, @@ -5658,6 +5702,8 @@ bitflags::bitflags! { bitflags::bitflags! { /// Similar to `TextureUsages`, but used only for `CommandEncoder::transition_resources`. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "serde", serde(transparent))] pub struct TextureUses: u16 { /// The texture is in unknown state. const UNINITIALIZED = 1 << 0; @@ -5693,10 +5739,10 @@ bitflags::bitflags! { const TRANSIENT = 1 << 12; /// The combination of states that a texture may be in _at the same time_. /// cbindgen:ignore - const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits(); + const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits() | Self::STORAGE_READ_ONLY.bits(); /// The combination of states that a texture must exclusively be in. /// cbindgen:ignore - const EXCLUSIVE = Self::COPY_DST.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ_ONLY.bits() | Self::STORAGE_WRITE_ONLY.bits() | Self::STORAGE_READ_WRITE.bits() | Self::STORAGE_ATOMIC.bits() | Self::PRESENT.bits(); + const EXCLUSIVE = Self::COPY_DST.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_WRITE_ONLY.bits() | Self::STORAGE_READ_WRITE.bits() | Self::STORAGE_ATOMIC.bits() | Self::PRESENT.bits(); /// The combination of all usages that the are guaranteed to be be ordered by the hardware. /// If a usage is ordered, then if the texture state doesn't change between draw calls, there /// are no barriers needed for synchronization. @@ -5713,6 +5759,7 @@ bitflags::bitflags! { /// A texture transition for use with `CommandEncoder::transition_resources`. #[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TextureTransition<T> { /// The texture to transition. pub texture: T, @@ -5726,6 +5773,7 @@ pub struct TextureTransition<T> { /// Specifies a particular set of subresources in a texture. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TextureSelector { /// Range of mips to use. pub mips: Range<u32>, @@ -5796,25 +5844,40 @@ pub struct SurfaceConfiguration<V> { /// `AutoNoVsync` will gracefully do a designed sets of fallbacks if their primary modes are /// unsupported. pub present_mode: PresentMode, - /// Desired maximum number of frames that the presentation engine should queue in advance. - /// - /// This is a hint to the backend implementation and will always be clamped to the supported range. - /// As a consequence, either the maximum frame latency is set directly on the swap chain, - /// or waits on present are scheduled to avoid exceeding the maximum frame latency if supported, - /// or the swap chain size is set to (max-latency + 1). - /// - /// Defaults to 2 when created via `Surface::get_default_config`. - /// - /// Typical values range from 3 to 1, but higher values are possible: - /// * Choose 2 or higher for potentially smoother frame display, as it allows to be at least one frame - /// to be queued up. This typically avoids starving the GPU's work queue. - /// Higher values are useful for achieving a constant flow of frames to the display under varying load. - /// * Choose 1 for low latency from frame recording to frame display. - /// ⚠️ If the backend does not support waiting on present, this will cause the CPU to wait for the GPU - /// to finish all work related to the previous frame when calling `Surface::get_current_texture`, - /// causing CPU-GPU serialization (i.e. when `Surface::get_current_texture` returns, the GPU might be idle). - /// It is currently not possible to query this. See <https://github.com/gfx-rs/wgpu/issues/2869>. - /// * A value of 0 is generally not supported and always clamped to a higher value. + /// Desired maximum number of monitor refreshes between a [`Surface::get_current_texture`] call and the + /// texture being presented to the screen. This is sometimes called "Frames in Flight". + /// + /// Defaults to `2` when created via [`Surface::get_default_config`] as this is a reasonable default. + /// + /// This is ultimately a hint to the backend implementation and will always be clamped + /// to the supported range. + /// + /// Typical values are `1` to `3`, but higher values are valid, though likely to be clamped. + /// * Choose `1` to minimize latency above all else. This only gives a single monitor refresh for all of + /// the CPU and GPU work to complete. ⚠️ As a result of these short swapchains, the CPU and GPU + /// cannot run in parallel, prioritizing latency over throughput. For applications like GUIs doing + /// a small amount of GPU work each frame that need low latency, this is a reasonable choice. + /// * Choose `2` for a balance between latency and throughput. The CPU and GPU both can each use + /// a full monitor refresh to do their computations. This is a reasonable default for most applications. + /// * Choose `3` or higher to maximize throughput, sacrificing latency when the the CPU and GPU + /// are using less than a full monitor refresh each. For applications that use CPU-side pipelining + /// of frames this may be a reasonable choice. ⚠️ On 60hz displays the latency can be very noticeable. + /// + /// This maps to the backend in the following ways: + /// - Vulkan: Number of frames in the swapchain is `desired_maximum_frame_latency + 1`, + /// clamped to the supported range. + /// - DX12: Calls [`IDXGISwapChain2::SetMaximumFrameLatency(desired_maximum_frame_latency)`][SMFL]. + /// - Metal: Sets the `maximumDrawableCount` of the underlying `CAMetalLayer` to + /// `desired_maximum_frame_latency + 1`, clamped to the supported range. + /// - OpenGL: Ignored + /// + /// It also has various subtle interactions with various present modes and APIs. + /// - DX12 + Mailbox: Limits framerate to `desired_maximum_frame_latency * Monitor Hz` fps. + /// - Vulkan/Metal + Mailbox: If this is set to `2`, limits framerate to `2 * Monitor Hz` fps. `3` or higher is unlimited. + /// + /// [`Surface::get_current_texture`]: ../wgpu/struct.Surface.html#method.get_current_texture + /// [`Surface::get_default_config`]: ../wgpu/struct.Surface.html#method.get_default_config + /// [SMFL]: https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-idxgiswapchain2-setmaximumframelatency pub desired_maximum_frame_latency: u32, /// Specifies how the alpha channel of the textures should be handled during compositing. pub alpha_mode: CompositeAlphaMode, @@ -6141,9 +6204,17 @@ impl Extent3d { } /// Calculates the extent at a given mip level. - /// Does *not* account for memory size being a multiple of block size. + /// + /// This is a low-level helper for internal use. + /// + /// It does *not* account for memory size being a multiple of block size. + /// + /// TODO(<https://github.com/gfx-rs/wgpu/issues/8491>): It also does not + /// consider whether an even dimension is required due to chroma + /// subsampling, but it probably should. /// /// <https://gpuweb.github.io/gpuweb/#logical-miplevel-specific-texture-extent> + #[doc(hidden)] #[must_use] pub fn mip_level_size(&self, level: u32, dim: TextureDimension) -> Self { Self { @@ -6414,12 +6485,30 @@ impl<L, V> TextureDescriptor<L, V> { /// Computes the render extent of this texture. /// + /// This is a low-level helper exported for use by wgpu-core. + /// /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-compute-render-extent> + /// + /// # Panics + /// + /// If the mip level is out of range. + #[doc(hidden)] #[must_use] - pub fn compute_render_extent(&self, mip_level: u32) -> Extent3d { + pub fn compute_render_extent(&self, mip_level: u32, plane: Option<u32>) -> Extent3d { + let Extent3d { + width, + height, + depth_or_array_layers: _, + } = self.mip_level_size(mip_level).expect("invalid mip level"); + + let (w_subsampling, h_subsampling) = self.format.subsampling_factors(plane); + + let width = width / w_subsampling; + let height = height / h_subsampling; + Extent3d { - width: u32::max(1, self.size.width >> mip_level), - height: u32::max(1, self.size.height >> mip_level), + width, + height, depth_or_array_layers: 1, } }