Bug 1976958 - Update wgpu to b83c9cf (2025-07-10) r=webgpu-reviewers,supply-chain-reviewers,teoxoy default tip
authorAndy Leiserson <aleiserson@mozilla.com>
Sat, 19 Jul 2025 16:44:54 +0000 (11 hours ago)
changeset 797257 246e16bb06c941d6f64d807d43c807bfba04ae86
parent 797256 b85e0ca703bb39bca3fc21f999bfebde54b414f8
push id42974
push usercsabou@mozilla.com
push dateSat, 19 Jul 2025 20:32:25 +0000 (7 hours ago)
treeherdermozilla-central@246e16bb06c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
git commit47d731cc857a8a983e03643bda5e0abde5747a12
reviewerswebgpu-reviewers, supply-chain-reviewers, teoxoy
bugs1976958
milestone142.0a1
first release with
nightly linux32
246e16bb06c9 / 142.0a1 / 20250719203225 / files
nightly linux64
246e16bb06c9 / 142.0a1 / 20250719203225 / files
nightly mac
246e16bb06c9 / 142.0a1 / 20250719203225 / files
nightly win32
246e16bb06c9 / 142.0a1 / 20250719203225 / files
nightly win64
246e16bb06c9 / 142.0a1 / 20250719203225 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1976958 - Update wgpu to b83c9cf (2025-07-10) r=webgpu-reviewers,supply-chain-reviewers,teoxoy Differential Revision: https://phabricator.services.mozilla.com/D257047
.cargo/config.toml.in
Cargo.lock
gfx/wgpu_bindings/Cargo.toml
gfx/wgpu_bindings/moz.yaml
gfx/wgpu_bindings/src/server.rs
supply-chain/audits.toml
testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setIndexBuffer/cts.https.html.ini
testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setVertexBuffer/cts.https.html.ini
testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/setBindGroup/cts.https.html.ini
testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/image_copy/layout_related/cts.https.html.ini
third_party/rust/naga/.cargo-checksum.json
third_party/rust/naga/Cargo.toml
third_party/rust/wgpu-core-deps-apple/.cargo-checksum.json
third_party/rust/wgpu-core-deps-apple/Cargo.toml
third_party/rust/wgpu-core-deps-windows-linux-android/.cargo-checksum.json
third_party/rust/wgpu-core-deps-windows-linux-android/Cargo.toml
third_party/rust/wgpu-core/.cargo-checksum.json
third_party/rust/wgpu-core/Cargo.toml
third_party/rust/wgpu-core/src/as_hal.rs
third_party/rust/wgpu-core/src/binding_model.rs
third_party/rust/wgpu-core/src/command/bundle.rs
third_party/rust/wgpu-core/src/command/clear.rs
third_party/rust/wgpu-core/src/command/compute.rs
third_party/rust/wgpu-core/src/command/draw.rs
third_party/rust/wgpu-core/src/command/memory_init.rs
third_party/rust/wgpu-core/src/command/mod.rs
third_party/rust/wgpu-core/src/command/query.rs
third_party/rust/wgpu-core/src/command/ray_tracing.rs
third_party/rust/wgpu-core/src/command/render.rs
third_party/rust/wgpu-core/src/command/render_command.rs
third_party/rust/wgpu-core/src/command/transfer.rs
third_party/rust/wgpu-core/src/device/global.rs
third_party/rust/wgpu-core/src/device/mod.rs
third_party/rust/wgpu-core/src/device/queue.rs
third_party/rust/wgpu-core/src/device/resource.rs
third_party/rust/wgpu-core/src/indirect_validation/dispatch.rs
third_party/rust/wgpu-core/src/indirect_validation/draw.rs
third_party/rust/wgpu-core/src/lib.rs
third_party/rust/wgpu-core/src/lock/mod.rs
third_party/rust/wgpu-core/src/lock/observing.rs
third_party/rust/wgpu-core/src/lock/ranked.rs
third_party/rust/wgpu-core/src/lock/vanilla.rs
third_party/rust/wgpu-core/src/pipeline.rs
third_party/rust/wgpu-core/src/resource.rs
third_party/rust/wgpu-core/src/snatch.rs
third_party/rust/wgpu-core/src/timestamp_normalization/mod.rs
third_party/rust/wgpu-core/src/track/mod.rs
third_party/rust/wgpu-core/src/track/texture.rs
third_party/rust/wgpu-hal/.cargo-checksum.json
third_party/rust/wgpu-hal/Cargo.toml
third_party/rust/wgpu-hal/examples/halmark/main.rs
third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs
third_party/rust/wgpu-hal/src/dx12/command.rs
third_party/rust/wgpu-hal/src/dx12/device.rs
third_party/rust/wgpu-hal/src/lib.rs
third_party/rust/wgpu-hal/src/vulkan/device.rs
third_party/rust/wgpu-hal/src/vulkan/mod.rs
third_party/rust/wgpu-types/.cargo-checksum.json
third_party/rust/wgpu-types/Cargo.toml
third_party/rust/wgpu-types/src/transfers.rs
--- a/.cargo/config.toml.in
+++ b/.cargo/config.toml.in
@@ -30,19 +30,19 @@ git = "https://github.com/beurdouche/nss
 rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63"
 replace-with = "vendored-sources"
 
 [source."git+https://github.com/franziskuskiefer/cose-rust?rev=43c22248d136c8b38fe42ea709d08da6355cf04b"]
 git = "https://github.com/franziskuskiefer/cose-rust"
 rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
 replace-with = "vendored-sources"
 
-[source."git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847"]
+[source."git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a"]
 git = "https://github.com/gfx-rs/wgpu"
-rev = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 replace-with = "vendored-sources"
 
 [source."git+https://github.com/glandium/rust-objc?rev=4de89f5aa9851ceca4d40e7ac1e2759410c04324"]
 git = "https://github.com/glandium/rust-objc"
 rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324"
 replace-with = "vendored-sources"
 
 [source."git+https://github.com/hsivonen/any_all_workaround?rev=7fb1b7034c9f172aade21ee1c8554e8d8a48af80"]
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4632,18 +4632,18 @@ dependencies = [
 [[package]]
 name = "murmurhash3"
 version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
 
 [[package]]
 name = "naga"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "arrayvec",
  "bit-set",
  "bitflags 2.9.0",
  "cfg-if",
  "cfg_aliases",
  "codespan-reporting",
  "half 2.5.0",
@@ -7600,18 +7600,18 @@ version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e"
 dependencies = [
  "nom",
 ]
 
 [[package]]
 name = "wgpu-core"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "arrayvec",
  "bit-set",
  "bit-vec",
  "bitflags 2.9.0",
  "bytemuck",
  "cfg_aliases",
  "document-features",
@@ -7630,34 +7630,34 @@ dependencies = [
  "wgpu-core-deps-apple",
  "wgpu-core-deps-windows-linux-android",
  "wgpu-hal",
  "wgpu-types",
 ]
 
 [[package]]
 name = "wgpu-core-deps-apple"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "wgpu-hal",
 ]
 
 [[package]]
 name = "wgpu-core-deps-windows-linux-android"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "wgpu-hal",
 ]
 
 [[package]]
 name = "wgpu-hal"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "android_system_properties",
  "arrayvec",
  "ash",
  "bit-set",
  "bitflags 2.9.0",
  "block",
  "bytemuck",
@@ -7683,18 +7683,18 @@ dependencies = [
  "thiserror 2.0.9",
  "wgpu-types",
  "windows",
  "windows-core",
 ]
 
 [[package]]
 name = "wgpu-types"
-version = "25.0.0"
-source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847"
+version = "26.0.0"
+source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a"
 dependencies = [
  "bitflags 2.9.0",
  "bytemuck",
  "js-sys",
  "log",
  "serde",
  "thiserror 2.0.9",
  "web-sys",
--- a/gfx/wgpu_bindings/Cargo.toml
+++ b/gfx/wgpu_bindings/Cargo.toml
@@ -12,58 +12,58 @@ publish = false
 [lib]
 
 [features]
 default = []
 
 [dependencies.wgc]
 package = "wgpu-core"
 git = "https://github.com/gfx-rs/wgpu"
-rev = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 # TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182
 features = [
   "serde",
   "replay",
   "trace",
   "strict_asserts",
   "wgsl",
   "api_log_info",
 ]
 
 # We want the wgpu-core Metal backend on macOS and iOS.
 # (We should consider also enabling "vulkan" for Vulkan Portability.)
 [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
 package = "wgpu-core"
 git = "https://github.com/gfx-rs/wgpu"
-rev = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 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 = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 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 = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 features = ["vulkan"]
 
 [dependencies.wgt]
 package = "wgpu-types"
 git = "https://github.com/gfx-rs/wgpu"
-rev = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 
 [dependencies.wgh]
 package = "wgpu-hal"
 git = "https://github.com/gfx-rs/wgpu"
-rev = "12591e42715badafef264609cb29d4a8e0b90847"
+rev = "b83c9cfd578837a6163d980130249c245a9c5f8a"
 features = ["device_lost_panic", "internal_error_panic"]
 
 [target.'cfg(windows)'.dependencies]
 windows = { version = "0.58", default-features = false, features = [
   "Win32_Graphics_Direct3D12",
 ] }
 
 [target.'cfg(target_os = "macos")'.dependencies]
--- a/gfx/wgpu_bindings/moz.yaml
+++ b/gfx/wgpu_bindings/moz.yaml
@@ -3,18 +3,18 @@ schema: 1
 bugzilla:
   product: Core
   component: "Graphics: WebGPU"
 
 origin:
   name: wgpu
   description: A cross-platform pure-Rust graphics API, modeled on the WebGPU standard
   url: https://github.com/gfx-rs/wgpu
-  release: 12591e42715badafef264609cb29d4a8e0b90847 (2025-07-07T02:56:42Z).
-  revision: 12591e42715badafef264609cb29d4a8e0b90847
+  release: b83c9cfd578837a6163d980130249c245a9c5f8a (2025-07-10T18:43:26Z).
+  revision: b83c9cfd578837a6163d980130249c245a9c5f8a
   license: ['MIT', 'Apache-2.0']
 
 updatebot:
     maintainer-phab: "#webgpu-reviewers"
     maintainer-bz: jimb@mozilla.com
     try-preset: webgpu
     tasks:
       - type: vendoring
--- a/gfx/wgpu_bindings/src/server.rs
+++ b/gfx/wgpu_bindings/src/server.rs
@@ -57,16 +57,23 @@ const MAX_TEXTURE_EXTENT: u32 = std::i16
 // the sum of these limits multiplied by the number of shader stages fits
 // maxBindingsPerBindGroup (1000). This restriction is arbitrary and is likely to
 // change eventually. See github.com/gpuweb/gpuweb/pull/4484
 // For now it's impractical for users to have very large numbers of bindings so this
 // limit should not be too restrictive until we add support for a bindless API.
 // Then we may have to ignore the spec or get it changed.
 const MAX_BINDINGS_PER_RESOURCE_TYPE: u32 = 64;
 
+#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
+fn emit_critical_invalid_note(what: &'static str) {
+    // SAFETY: We ensure that the pointer provided is not null.
+    let msg = CString::new(format!("{what} is invalid")).unwrap();
+    unsafe { gfx_critical_note(msg.as_ptr()) }
+}
+
 fn restrict_limits(limits: wgt::Limits) -> wgt::Limits {
     wgt::Limits {
         max_buffer_size: limits.max_buffer_size.min(MAX_BUFFER_SIZE),
         max_texture_dimension_1d: limits.max_texture_dimension_1d.min(MAX_TEXTURE_EXTENT),
         max_texture_dimension_2d: limits.max_texture_dimension_2d.min(MAX_TEXTURE_EXTENT),
         max_texture_dimension_3d: limits.max_texture_dimension_3d.min(MAX_TEXTURE_EXTENT),
         max_sampled_textures_per_shader_stage: limits
             .max_sampled_textures_per_shader_stage
@@ -261,47 +268,44 @@ fn support_use_shared_texture_in_swap_ch
         let support = if backend != wgt::Backend::Vulkan {
             log::info!(concat!(
                 "WebGPU: disabling SharedTexture swapchain: \n",
                 "wgpu backend is not Vulkan"
             ));
             false
         } else {
             unsafe {
-                global.adapter_as_hal::<wgc::api::Vulkan, _, bool>(self_id, |hal_adapter| {
-                    let hal_adapter = match hal_adapter {
-                        None => {
-                            let msg = c"Vulkan adapter is invalid";
-                            gfx_critical_note(msg.as_ptr());
-                            return false;
-                        }
-                        Some(hal_adapter) => hal_adapter,
-                    };
-
-                    let capabilities = hal_adapter.physical_device_capabilities();
-                    static REQUIRED: &[&'static std::ffi::CStr] = &[
-                        khr::external_memory_fd::NAME,
-                        ash::ext::external_memory_dma_buf::NAME,
-                        ash::ext::image_drm_format_modifier::NAME,
-                        khr::external_semaphore_fd::NAME,
-                    ];
-                    REQUIRED.iter().all(|extension| {
-                        let supported = capabilities.supports_extension(extension);
-                        if !supported {
-                            log::info!(
-                                concat!(
-                                    "WebGPU: disabling SharedTexture swapchain: \n",
-                                    "Vulkan extension not supported: {:?}",
-                                ),
-                                extension.to_string_lossy()
-                            );
-                        }
-                        supported
-                    })
-                })
+                match global.adapter_as_hal::<wgc::api::Vulkan>(self_id) {
+                    None => {
+                        emit_critical_invalid_note("Vulkan adapter");
+                        false
+                    }
+                    Some(hal_adapter) => {
+                        let capabilities = hal_adapter.physical_device_capabilities();
+                        static REQUIRED: &[&'static std::ffi::CStr] = &[
+                            khr::external_memory_fd::NAME,
+                            ash::ext::external_memory_dma_buf::NAME,
+                            ash::ext::image_drm_format_modifier::NAME,
+                            khr::external_semaphore_fd::NAME,
+                        ];
+                        REQUIRED.iter().all(|extension| {
+                            let supported = capabilities.supports_extension(extension);
+                            if !supported {
+                                log::info!(
+                                    concat!(
+                                        "WebGPU: disabling SharedTexture swapchain: \n",
+                                        "Vulkan extension not supported: {:?}",
+                                    ),
+                                    extension.to_string_lossy()
+                                );
+                            }
+                            supported
+                        })
+                    }
+                }
             }
         };
         return support;
     }
 
     #[cfg(target_os = "macos")]
     {
         if backend != wgt::Backend::Metal {
@@ -373,144 +377,125 @@ unsafe fn adapter_request_device(
     }
 
     // TODO: in https://github.com/gfx-rs/wgpu/pull/3626/files#diff-033343814319f5a6bd781494692ea626f06f6c3acc0753a12c867b53a646c34eR97
     // which introduced the queue id parameter, the queue id is also the device id. I don't know how applicable this is to
     // other situations (this one in particular).
 
     #[cfg(target_os = "linux")]
     {
-        let support_dma_buf =
-            global.adapter_as_hal::<wgc::api::Vulkan, _, bool>(self_id, |hal_adapter| {
-                let hal_adapter = match hal_adapter {
-                    None => {
-                        let msg = c"Vulkan adapter is invalid";
-                        gfx_critical_note(msg.as_ptr());
-                        return false;
-                    }
-                    Some(hal_adapter) => hal_adapter,
+        let hal_adapter = global.adapter_as_hal::<wgc::api::Vulkan>(self_id);
+
+        let support_dma_buf = hal_adapter.as_ref().is_some_and(|hal_adapter| {
+            let capabilities = hal_adapter.physical_device_capabilities();
+
+            capabilities.supports_extension(khr::external_memory_fd::NAME)
+                && capabilities.supports_extension(ash::ext::external_memory_dma_buf::NAME)
+                && capabilities.supports_extension(ash::ext::image_drm_format_modifier::NAME)
+                && capabilities.supports_extension(khr::external_semaphore_fd::NAME)
+        });
+
+        match (hal_adapter, support_dma_buf) {
+            (None, _) => {
+                emit_critical_invalid_note("Vulkan adapter");
+            }
+            (Some(_), false) => {}
+            (Some(hal_adapter), true) => {
+                let mut enabled_extensions =
+                    hal_adapter.required_device_extensions(desc.required_features);
+                enabled_extensions.push(khr::external_memory_fd::NAME);
+                enabled_extensions.push(ash::ext::external_memory_dma_buf::NAME);
+                enabled_extensions.push(ash::ext::image_drm_format_modifier::NAME);
+                enabled_extensions.push(khr::external_semaphore_fd::NAME);
+
+                let mut enabled_phd_features = hal_adapter
+                    .physical_device_features(&enabled_extensions, desc.required_features);
+
+                let raw_instance = hal_adapter.shared_instance().raw_instance();
+                let raw_physical_device = hal_adapter.raw_physical_device();
+
+                let queue_family_index = raw_instance
+                    .get_physical_device_queue_family_properties(raw_physical_device)
+                    .into_iter()
+                    .enumerate()
+                    .find_map(|(queue_family_index, info)| {
+                        if info.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
+                            Some(queue_family_index as u32)
+                        } else {
+                            None
+                        }
+                    });
+
+                let Some(queue_family_index) = queue_family_index else {
+                    let msg = c"Vulkan device has no graphics queue";
+                    gfx_critical_note(msg.as_ptr());
+                    return Some(format!("Internal Error: Failed to create ash::Device"));
                 };
 
-                let capabilities = hal_adapter.physical_device_capabilities();
-
-                capabilities.supports_extension(khr::external_memory_fd::NAME)
-                    && capabilities.supports_extension(ash::ext::external_memory_dma_buf::NAME)
-                    && capabilities.supports_extension(ash::ext::image_drm_format_modifier::NAME)
-                    && capabilities.supports_extension(khr::external_semaphore_fd::NAME)
-            });
+                let family_info = vk::DeviceQueueCreateInfo::default()
+                    .queue_family_index(queue_family_index)
+                    .queue_priorities(&[1.0]);
+                let family_infos = [family_info];
 
-        if support_dma_buf {
-            let hal_device = global
-                .adapter_as_hal::<wgc::api::Vulkan, _, Option<wgh::OpenDevice<wgh::api::Vulkan>>>(
-                    self_id,
-                    |hal_adapter| {
-                        let hal_adapter = match hal_adapter {
-                            None => {
-                                let msg = c"Vulkan adapter is invalid";
-                                gfx_critical_note(msg.as_ptr());
-                                return None;
-                            }
-                            Some(hal_adapter) => hal_adapter,
-                        };
+                let str_pointers = enabled_extensions
+                    .iter()
+                    .map(|&s| {
+                        // Safe because `enabled_extensions` entries have static lifetime.
+                        s.as_ptr()
+                    })
+                    .collect::<Vec<_>>();
 
-                        let mut enabled_extensions =
-                            hal_adapter.required_device_extensions(desc.required_features);
-                        enabled_extensions.push(khr::external_memory_fd::NAME);
-                        enabled_extensions.push(ash::ext::external_memory_dma_buf::NAME);
-                        enabled_extensions.push(ash::ext::image_drm_format_modifier::NAME);
-                        enabled_extensions.push(khr::external_semaphore_fd::NAME);
-
-                        let mut enabled_phd_features = hal_adapter
-                            .physical_device_features(&enabled_extensions, desc.required_features);
-
-                        let raw_instance = hal_adapter.shared_instance().raw_instance();
-                        let raw_physical_device = hal_adapter.raw_physical_device();
+                let pre_info = vk::DeviceCreateInfo::default()
+                    .queue_create_infos(&family_infos)
+                    .enabled_extension_names(&str_pointers);
+                let info = enabled_phd_features.add_to_device_create(pre_info);
 
-                        let queue_family_index = raw_instance
-                            .get_physical_device_queue_family_properties(raw_physical_device)
-                            .into_iter()
-                            .enumerate()
-                            .find_map(|(queue_family_index, info)| {
-                                if info.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
-                                    Some(queue_family_index as u32)
-                                } else {
-                                    None
-                                }
-                            });
-
-                        let queue_family_index = match queue_family_index {
-                            None => {
-                                let msg = c"Vulkan device has no graphics queue";
-                                gfx_critical_note(msg.as_ptr());
-                                return None;
-                            }
-                            Some(queue_family_index) => queue_family_index,
-                        };
+                let raw_device =
+                    match raw_instance.create_device(raw_physical_device, &info, None) {
+                        Err(err) => {
+                            let msg =
+                                CString::new(format!("create_device() failed: {:?}", err))
+                                    .unwrap();
+                            gfx_critical_note(msg.as_ptr());
+                            return Some(format!("Internal Error: Failed to create ash::Device"));
+                        }
+                        Ok(raw_device) => raw_device,
+                    };
 
-                        let family_info = vk::DeviceQueueCreateInfo::default()
-                            .queue_family_index(queue_family_index)
-                            .queue_priorities(&[1.0]);
-                        let family_infos = [family_info];
-
-                        let str_pointers = enabled_extensions
-                            .iter()
-                            .map(|&s| {
-                                // Safe because `enabled_extensions` entries have static lifetime.
-                                s.as_ptr()
-                            })
-                            .collect::<Vec<_>>();
-
-                        let pre_info = vk::DeviceCreateInfo::default()
-                            .queue_create_infos(&family_infos)
-                            .enabled_extension_names(&str_pointers);
-                        let info = enabled_phd_features.add_to_device_create(pre_info);
-
-                        let raw_device =
-                            match raw_instance.create_device(raw_physical_device, &info, None) {
-                                Err(err) => {
-                                    let msg =
-                                        CString::new(format!("create_device() failed: {:?}", err))
-                                            .unwrap();
-                                    gfx_critical_note(msg.as_ptr());
-                                    return None;
-                                }
-                                Ok(raw_device) => raw_device,
-                            };
+                let hal_device = match hal_adapter.device_from_raw(
+                    raw_device,
+                    None,
+                    &enabled_extensions,
+                    desc.required_features,
+                    &desc.memory_hints,
+                    family_info.queue_family_index,
+                    0,
+                ) {
+                    Err(err) => {
+                        let msg =
+                            CString::new(format!("device_from_raw() failed: {:?}", err))
+                                .unwrap();
+                        gfx_critical_note(msg.as_ptr());
+                        return Some(format!("Internal Error: Failed to create ash::Device"));
+                    }
+                    Ok(hal_device) => hal_device,
+                };
 
-                        let hal_device = hal_adapter.device_from_raw(
-                            raw_device,
-                            None,
-                            &enabled_extensions,
-                            desc.required_features,
-                            &desc.memory_hints,
-                            family_info.queue_family_index,
-                            0,
-                        );
-                        Some(hal_device.unwrap())
-                    },
+                let res = global.create_device_from_hal(
+                    self_id,
+                    hal_device.into(),
+                    &desc,
+                    Some(new_device_id),
+                    Some(new_queue_id),
                 );
-
-            let hal_device = match hal_device {
-                None => {
-                    return Some(format!("Internal Error: Failed to create ash::Device"));
+                if let Err(err) = res {
+                    return Some(format!("{err}"));
                 }
-                Some(hal_device) => hal_device,
-            };
-
-            let res = global.create_device_from_hal(
-                self_id,
-                hal_device.into(),
-                &desc,
-                Some(new_device_id),
-                Some(new_queue_id),
-            );
-            if let Err(err) = res {
-                return Some(format!("{err}"));
+                return None;
             }
-            return None;
         }
     }
 
     let res =
         global.adapter_request_device(self_id, &desc, Some(new_device_id), Some(new_queue_id));
     if let Err(err) = res {
         return Some(format!("{err}"));
     } else {
@@ -773,51 +758,31 @@ pub extern "C" fn wgpu_server_buffer_unm
 
 #[allow(unused_variables)]
 #[no_mangle]
 pub extern "C" fn wgpu_server_get_device_fence_handle(
     global: &Global,
     device_id: id::DeviceId,
 ) -> *mut c_void {
     #[cfg(target_os = "windows")]
-    {
-        let dx12_device = unsafe {
-            global.device_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Device>>(
-                device_id,
-                |hal_device| hal_device.map(|device| device.raw_device().clone()),
-            )
-        };
-        let dx12_device = match dx12_device {
-            Some(device) => device,
-            None => {
-                return ptr::null_mut();
-            }
+    unsafe {
+        let Some(dx12_device) = global.device_as_hal::<wgc::api::Dx12>(device_id)
+                .map(|device| device.raw_device().clone()) else {
+            return ptr::null_mut();
         };
 
-        let dx12_fence = unsafe {
-            global.device_fence_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Fence>>(
-                device_id,
-                |hal_fence| hal_fence.map(|fence| fence.raw_fence().clone()),
-            )
-        };
-        let dx12_fence = match dx12_fence {
-            Some(fence) => fence,
-            None => {
-                return ptr::null_mut();
-            }
+        let Some(dx12_fence) = global.device_fence_as_hal::<wgc::api::Dx12>(device_id)
+                .map(|fence| fence.raw_fence().clone()) else {
+            return ptr::null_mut();
         };
 
-        let res = unsafe {
-            dx12_device.CreateSharedHandle(&dx12_fence, None, Foundation::GENERIC_ALL.0, None)
-        };
-
-        return match res {
+        match dx12_device.CreateSharedHandle(&dx12_fence, None, Foundation::GENERIC_ALL.0, None) {
             Ok(handle) => handle.0,
             Err(_) => ptr::null_mut(),
-        };
+        }
     }
     #[cfg(not(target_os = "windows"))]
     ptr::null_mut()
 }
 
 #[derive(Debug)]
 #[repr(C)]
 pub struct DMABufInfo {
@@ -839,279 +804,252 @@ pub struct VkImageHandle {
     pub modifier: u64,
     pub layouts: Vec<vk::SubresourceLayout>,
 }
 
 #[cfg(target_os = "linux")]
 impl VkImageHandle {
     fn destroy(&self, global: &Global, device_id: id::DeviceId) {
         unsafe {
-            global.device_as_hal::<wgc::api::Vulkan, _, ()>(device_id, |hal_device| {
-                let hal_device = match hal_device {
-                    None => {
-                        return;
-                    }
-                    Some(hal_device) => hal_device,
-                };
-                let device = hal_device.raw_device();
+            let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
+                return;
+            };
 
-                (device.fp_v1_0().destroy_image)(self.device, self.image, ptr::null());
-                (device.fp_v1_0().free_memory)(self.device, self.memory, ptr::null());
-            })
+            let device = hal_device.raw_device();
+
+            (device.fp_v1_0().destroy_image)(self.device, self.image, ptr::null());
+            (device.fp_v1_0().free_memory)(self.device, self.memory, ptr::null());
         };
     }
 }
 
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub extern "C" fn wgpu_vkimage_create_with_dma_buf(
     global: &Global,
     device_id: id::DeviceId,
     width: u32,
     height: u32,
     out_memory_size: *mut u64,
 ) -> *mut VkImageHandle {
-    let image_handle = unsafe {
-        global.device_as_hal::<wgc::api::Vulkan, _, Option<VkImageHandle>>(
-            device_id,
-            |hal_device| {
-                let hal_device = match hal_device {
-                    None => {
-                        let msg = c"Vulkan device is invalid";
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Some(hal_device) => hal_device,
-                };
-
-                let device = hal_device.raw_device();
-                let physical_device = hal_device.raw_physical_device();
-                let instance = hal_device.shared_instance().raw_instance();
-
-                let count = {
-                    let mut drm_format_modifier_props_list =
-                        vk::DrmFormatModifierPropertiesListEXT::default();
-                    let mut format_properties_2 = vk::FormatProperties2::default()
-                        .push_next(&mut drm_format_modifier_props_list);
+    unsafe {
+        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
+            emit_critical_invalid_note("Vulkan device");
+            return ptr::null_mut();
+        };
 
-                    instance.get_physical_device_format_properties2(
-                        physical_device,
-                        vk::Format::R8G8B8A8_UNORM,
-                        &mut format_properties_2,
-                    );
-                    drm_format_modifier_props_list.drm_format_modifier_count
-                };
-
-                if count == 0 {
-                    let msg = c"get_physical_device_format_properties2() failed";
-                    gfx_critical_note(msg.as_ptr());
-                    return None;
-                }
-
-                let mut modifier_props =
-                    vec![vk::DrmFormatModifierPropertiesEXT::default(); count as usize];
-
-                let mut drm_format_modifier_props_list =
-                    vk::DrmFormatModifierPropertiesListEXT::default()
-                        .drm_format_modifier_properties(&mut modifier_props);
-                let mut format_properties_2 =
-                    vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list);
-
-                instance.get_physical_device_format_properties2(
-                    physical_device,
-                    vk::Format::R8G8B8A8_UNORM,
-                    &mut format_properties_2,
-                );
+        let device = hal_device.raw_device();
+        let physical_device = hal_device.raw_physical_device();
+        let instance = hal_device.shared_instance().raw_instance();
 
-                let mut usage_flags = vk::ImageUsageFlags::empty();
-                usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
-
-                modifier_props.retain(|modifier_prop| {
-                    let support = is_dmabuf_supported(
-                        instance,
-                        physical_device,
-                        vk::Format::R8G8B8A8_UNORM,
-                        modifier_prop.drm_format_modifier,
-                        usage_flags,
-                    );
-                    support
-                });
-
-                if modifier_props.is_empty() {
-                    let msg = c"format not supported for dmabuf import";
-                    gfx_critical_note(msg.as_ptr());
-                    return None;
-                }
-
-                let modifiers: Vec<u64> = modifier_props
-                    .iter()
-                    .map(|modifier_prop| modifier_prop.drm_format_modifier)
-                    .collect();
-
-                let mut modifier_list = vk::ImageDrmFormatModifierListCreateInfoEXT::default()
-                    .drm_format_modifiers(&modifiers);
+        let count = {
+            let mut drm_format_modifier_props_list =
+                vk::DrmFormatModifierPropertiesListEXT::default();
+            let mut format_properties_2 = vk::FormatProperties2::default()
+                .push_next(&mut drm_format_modifier_props_list);
 
-                let extent = vk::Extent3D {
-                    width,
-                    height,
-                    depth: 1,
-                };
-
-                let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default()
-                    .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
-
-                let mut export_memory_alloc_info = vk::ExportMemoryAllocateInfo::default()
-                    .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
-
-                let flags = vk::ImageCreateFlags::empty();
+            instance.get_physical_device_format_properties2(
+                physical_device,
+                vk::Format::R8G8B8A8_UNORM,
+                &mut format_properties_2,
+            );
+            drm_format_modifier_props_list.drm_format_modifier_count
+        };
 
-                let vk_info = vk::ImageCreateInfo::default()
-                    .flags(flags)
-                    .image_type(vk::ImageType::TYPE_2D)
-                    .format(vk::Format::R8G8B8A8_UNORM)
-                    .extent(extent)
-                    .mip_levels(1)
-                    .array_layers(1)
-                    .samples(vk::SampleCountFlags::TYPE_1)
-                    .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
-                    .usage(usage_flags)
-                    .sharing_mode(vk::SharingMode::EXCLUSIVE)
-                    .initial_layout(vk::ImageLayout::UNDEFINED)
-                    .push_next(&mut modifier_list)
-                    .push_next(&mut external_image_create_info);
+        if count == 0 {
+            let msg = c"get_physical_device_format_properties2() failed";
+            gfx_critical_note(msg.as_ptr());
+            return ptr::null_mut();
+        }
 
-                let image = match device.create_image(&vk_info, None) {
-                    Err(err) => {
-                        let msg =
-                            CString::new(format!("create_image() failed: {:?}", err)).unwrap();
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Ok(image) => image,
-                };
-
-                let mut image_modifier_properties =
-                    vk::ImageDrmFormatModifierPropertiesEXT::default();
-                let image_drm_format_modifier =
-                    ash::ext::image_drm_format_modifier::Device::new(instance, device);
-                let ret = image_drm_format_modifier.get_image_drm_format_modifier_properties(
-                    image,
-                    &mut image_modifier_properties,
-                );
-                if ret.is_err() {
-                    let msg = CString::new(format!(
-                        "get_image_drm_format_modifier_properties() failed: {:?}",
-                        ret
-                    ))
-                    .unwrap();
-                    gfx_critical_note(msg.as_ptr());
-                    return None;
-                }
-
-                let memory_req = device.get_image_memory_requirements(image);
+        let mut modifier_props =
+            vec![vk::DrmFormatModifierPropertiesEXT::default(); count as usize];
 
-                let mem_properties =
-                    instance.get_physical_device_memory_properties(physical_device);
-
-                let index = mem_properties
-                    .memory_types
-                    .iter()
-                    .enumerate()
-                    .position(|(i, t)| {
-                        ((1 << i) & memory_req.memory_type_bits) != 0
-                            && t.property_flags
-                                .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL)
-                    });
+        let mut drm_format_modifier_props_list =
+            vk::DrmFormatModifierPropertiesListEXT::default()
+                .drm_format_modifier_properties(&mut modifier_props);
+        let mut format_properties_2 =
+            vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list);
 
-                let index = match index {
-                    None => {
-                        let msg = c"Failed to get DEVICE_LOCAL memory index";
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Some(index) => index,
-                };
-
-                let mut dedicated_memory_info =
-                    vk::MemoryDedicatedAllocateInfo::default().image(image);
-
-                let memory_allocate_info = vk::MemoryAllocateInfo::default()
-                    .allocation_size(memory_req.size)
-                    .memory_type_index(index as u32)
-                    .push_next(&mut dedicated_memory_info)
-                    .push_next(&mut export_memory_alloc_info);
+        instance.get_physical_device_format_properties2(
+            physical_device,
+            vk::Format::R8G8B8A8_UNORM,
+            &mut format_properties_2,
+        );
 
-                let memory = match device.allocate_memory(&memory_allocate_info, None) {
-                    Err(err) => {
-                        let msg =
-                            CString::new(format!("allocate_memory() failed: {:?}", err)).unwrap();
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Ok(memory) => memory,
-                };
-
-                let result = device.bind_image_memory(image, memory, /* offset */ 0);
-                if result.is_err() {
-                    let msg =
-                        CString::new(format!("bind_image_memory() failed: {:?}", result)).unwrap();
-                    gfx_critical_note(msg.as_ptr());
-                    return None;
-                }
-
-                *out_memory_size = memory_req.size;
+        let mut usage_flags = vk::ImageUsageFlags::empty();
+        usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
 
-                let modifier_prop = modifier_props.iter().find(|prop| {
-                    prop.drm_format_modifier == image_modifier_properties.drm_format_modifier
-                });
-                let modifier_prop = match modifier_prop {
-                    None => {
-                        let msg = c"failed to find modifier_prop";
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Some(modifier_prop) => modifier_prop,
-                };
-
-                let plane_count = modifier_prop.drm_format_modifier_plane_count;
+        modifier_props.retain(|modifier_prop| {
+            let support = is_dmabuf_supported(
+                instance,
+                physical_device,
+                vk::Format::R8G8B8A8_UNORM,
+                modifier_prop.drm_format_modifier,
+                usage_flags,
+            );
+            support
+        });
 
-                let mut layouts = Vec::new();
-                for i in 0..plane_count {
-                    let flag = match i {
-                        0 => vk::ImageAspectFlags::PLANE_0,
-                        1 => vk::ImageAspectFlags::PLANE_1,
-                        2 => vk::ImageAspectFlags::PLANE_2,
-                        _ => unreachable!(),
-                    };
-                    let subresource = vk::ImageSubresource::default().aspect_mask(flag);
-                    let layout = device.get_image_subresource_layout(image, subresource);
-                    layouts.push(layout);
-                }
-
-                Some(VkImageHandle {
-                    device: device.handle(),
-                    image,
-                    memory,
-                    memory_size: memory_req.size,
-                    memory_type_index: index as u32,
-                    modifier: image_modifier_properties.drm_format_modifier,
-                    layouts,
-                })
-            },
-        )
-    };
-
-    let image_handle = match image_handle {
-        None => {
+        if modifier_props.is_empty() {
+            let msg = c"format not supported for dmabuf import";
+            gfx_critical_note(msg.as_ptr());
             return ptr::null_mut();
         }
-        Some(image_handle) => image_handle,
-    };
+
+        let modifiers: Vec<u64> = modifier_props
+            .iter()
+            .map(|modifier_prop| modifier_prop.drm_format_modifier)
+            .collect();
+
+        let mut modifier_list = vk::ImageDrmFormatModifierListCreateInfoEXT::default()
+            .drm_format_modifiers(&modifiers);
+
+        let extent = vk::Extent3D {
+            width,
+            height,
+            depth: 1,
+        };
+
+        let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default()
+            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
+
+        let mut export_memory_alloc_info = vk::ExportMemoryAllocateInfo::default()
+            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
+
+        let flags = vk::ImageCreateFlags::empty();
+
+        let vk_info = vk::ImageCreateInfo::default()
+            .flags(flags)
+            .image_type(vk::ImageType::TYPE_2D)
+            .format(vk::Format::R8G8B8A8_UNORM)
+            .extent(extent)
+            .mip_levels(1)
+            .array_layers(1)
+            .samples(vk::SampleCountFlags::TYPE_1)
+            .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
+            .usage(usage_flags)
+            .sharing_mode(vk::SharingMode::EXCLUSIVE)
+            .initial_layout(vk::ImageLayout::UNDEFINED)
+            .push_next(&mut modifier_list)
+            .push_next(&mut external_image_create_info);
+
+        let image = match device.create_image(&vk_info, None) {
+            Err(err) => {
+                let msg =
+                    CString::new(format!("create_image() failed: {:?}", err)).unwrap();
+                gfx_critical_note(msg.as_ptr());
+                return ptr::null_mut();
+            }
+            Ok(image) => image,
+        };
+
+        let mut image_modifier_properties =
+            vk::ImageDrmFormatModifierPropertiesEXT::default();
+        let image_drm_format_modifier =
+            ash::ext::image_drm_format_modifier::Device::new(instance, device);
+        let ret = image_drm_format_modifier.get_image_drm_format_modifier_properties(
+            image,
+            &mut image_modifier_properties,
+        );
+        if ret.is_err() {
+            let msg = CString::new(format!(
+                "get_image_drm_format_modifier_properties() failed: {:?}",
+                ret
+            ))
+            .unwrap();
+            gfx_critical_note(msg.as_ptr());
+            return ptr::null_mut();
+        }
+
+        let memory_req = device.get_image_memory_requirements(image);
+
+        let mem_properties =
+            instance.get_physical_device_memory_properties(physical_device);
 
-    Box::into_raw(Box::new(image_handle))
+        let index = mem_properties
+            .memory_types
+            .iter()
+            .enumerate()
+            .position(|(i, t)| {
+                ((1 << i) & memory_req.memory_type_bits) != 0
+                    && t.property_flags
+                        .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL)
+            });
+
+        let Some(index) = index else {
+            let msg = c"Failed to get DEVICE_LOCAL memory index";
+            gfx_critical_note(msg.as_ptr());
+            return ptr::null_mut();
+        };
+
+        let mut dedicated_memory_info =
+            vk::MemoryDedicatedAllocateInfo::default().image(image);
+
+        let memory_allocate_info = vk::MemoryAllocateInfo::default()
+            .allocation_size(memory_req.size)
+            .memory_type_index(index as u32)
+            .push_next(&mut dedicated_memory_info)
+            .push_next(&mut export_memory_alloc_info);
+
+        let memory = match device.allocate_memory(&memory_allocate_info, None) {
+            Err(err) => {
+                let msg =
+                    CString::new(format!("allocate_memory() failed: {:?}", err)).unwrap();
+                gfx_critical_note(msg.as_ptr());
+                return ptr::null_mut();
+            }
+            Ok(memory) => memory,
+        };
+
+        let result = device.bind_image_memory(image, memory, /* offset */ 0);
+        if result.is_err() {
+            let msg = CString::new(format!("bind_image_memory() failed: {:?}", result)).unwrap();
+            gfx_critical_note(msg.as_ptr());
+            return ptr::null_mut();
+        }
+
+        *out_memory_size = memory_req.size;
+
+        let modifier_prop = modifier_props.iter().find(|prop| {
+            prop.drm_format_modifier == image_modifier_properties.drm_format_modifier
+        });
+        let Some(modifier_prop) = modifier_prop else {
+            let msg = c"failed to find modifier_prop";
+            gfx_critical_note(msg.as_ptr());
+            return ptr::null_mut();
+        };
+
+        let plane_count = modifier_prop.drm_format_modifier_plane_count;
+
+        let mut layouts = Vec::new();
+        for i in 0..plane_count {
+            let flag = match i {
+                0 => vk::ImageAspectFlags::PLANE_0,
+                1 => vk::ImageAspectFlags::PLANE_1,
+                2 => vk::ImageAspectFlags::PLANE_2,
+                _ => unreachable!(),
+            };
+            let subresource = vk::ImageSubresource::default().aspect_mask(flag);
+            let layout = device.get_image_subresource_layout(image, subresource);
+            layouts.push(layout);
+        }
+
+        let image_handle = VkImageHandle {
+            device: device.handle(),
+            image,
+            memory,
+            memory_size: memory_req.size,
+            memory_type_index: index as u32,
+            modifier: image_modifier_properties.drm_format_modifier,
+            layouts,
+        };
+
+        Box::into_raw(Box::new(image_handle))
+    }
 }
 
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub unsafe extern "C" fn wgpu_vkimage_destroy(
     global: &Global,
     device_id: id::DeviceId,
     handle: &VkImageHandle,
@@ -1128,40 +1066,31 @@ pub unsafe extern "C" fn wgpu_vkimage_de
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub extern "C" fn wgpu_vkimage_get_file_descriptor(
     global: &Global,
     device_id: id::DeviceId,
     handle: &VkImageHandle,
 ) -> i32 {
     unsafe {
-        global.device_as_hal::<wgc::api::Vulkan, _, i32>(device_id, |hal_device| {
-            let hal_device = match hal_device {
-                None => {
-                    let msg = c"Vulkan device is invalid";
-                    gfx_critical_note(msg.as_ptr());
-                    return -1;
-                }
-                Some(hal_device) => hal_device,
-            };
+        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
+            emit_critical_invalid_note("Vulkan device");
+            return -1;
+        };
+
+        let device = hal_device.raw_device();
+        let instance = hal_device.shared_instance().raw_instance();
 
-            let device = hal_device.raw_device();
-            let instance = hal_device.shared_instance().raw_instance();
-
-            let get_fd_info = vk::MemoryGetFdInfoKHR::default()
-                .memory(handle.memory)
-                .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
+        let get_fd_info = vk::MemoryGetFdInfoKHR::default()
+            .memory(handle.memory)
+            .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
 
-            let loader = khr::external_memory_fd::Device::new(instance, device);
+        let loader = khr::external_memory_fd::Device::new(instance, device);
 
-            return match loader.get_memory_fd(&get_fd_info) {
-                Err(..) => -1,
-                Ok(fd) => fd,
-            };
-        })
+        loader.get_memory_fd(&get_fd_info).unwrap_or(-1)
     }
 }
 
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub extern "C" fn wgpu_vkimage_get_dma_buf_info(handle: &VkImageHandle) -> DMABufInfo {
     let mut offsets: [u64; 3] = [0; 3];
     let mut strides: [u64; 3] = [0; 3];
@@ -1190,20 +1119,18 @@ pub struct MetalSharedEventHandle;
 #[allow(unused_variables)]
 pub extern "C" fn wgpu_server_get_device_fence_metal_shared_event(
     global: &Global,
     device_id: id::DeviceId,
 ) -> *mut MetalSharedEventHandle {
     #[cfg(target_os = "macos")]
     {
         let shared_event = unsafe {
-            global.device_fence_as_hal::<wgc::api::Metal, _, Option<metal::SharedEvent>>(
-                device_id,
-                |hal_fence| hal_fence.map(|fence| fence.raw_shared_event().unwrap().clone()),
-            )
+            global.device_fence_as_hal::<wgc::api::Metal>(device_id)
+                .map(|fence| fence.raw_shared_event().unwrap().clone())
         };
         let shared_event = match shared_event {
             Some(shared_event) => shared_event,
             None => {
                 return ptr::null_mut();
             }
         };
         return Box::into_raw(Box::new(MetalSharedEventHandle(shared_event)));
@@ -1473,36 +1400,26 @@ impl Global {
     fn create_texture_with_shared_texture_d3d11(
         &self,
         device_id: id::DeviceId,
         texture_id: id::TextureId,
         desc: &wgc::resource::TextureDescriptor,
         swap_chain_id: Option<SwapChainId>,
     ) -> bool {
         let dx12_device = unsafe {
-            self.device_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Device>>(
-                device_id,
-                |hal_device| {
-                    if hal_device.is_none() {
-                        return None;
-                    }
-                    hal_device.map(|hal_device| hal_device.raw_device().clone())
-                },
-            )
+            match self.device_as_hal::<wgc::api::Dx12>(device_id)
+                .map(|hal_device| hal_device.raw_device().clone()) {
+                None => {
+                    emit_critical_invalid_note("dx12 device");
+                    return false;
+                }
+                Some(dx12_device) => dx12_device,
+            }
         };
 
-        if dx12_device.is_none() {
-            let msg = c"dx12 device is none";
-            unsafe {
-                gfx_critical_note(msg.as_ptr());
-            }
-            return false;
-        }
-
-        let dx12_device = dx12_device.unwrap();
         let ret = unsafe {
             wgpu_server_ensure_shared_texture_for_swap_chain(
                 self.webgpu_parent,
                 swap_chain_id.unwrap(),
                 device_id,
                 texture_id,
                 desc.size.width,
                 desc.size.height,
@@ -1566,216 +1483,186 @@ impl Global {
     #[cfg(target_os = "linux")]
     fn create_texture_with_shared_texture_dmabuf(
         &self,
         device_id: id::DeviceId,
         texture_id: id::TextureId,
         desc: &wgc::resource::TextureDescriptor,
         swap_chain_id: Option<SwapChainId>,
     ) -> bool {
-        let ret = unsafe {
-            wgpu_server_ensure_shared_texture_for_swap_chain(
+        unsafe {
+            let ret = wgpu_server_ensure_shared_texture_for_swap_chain(
                 self.webgpu_parent,
                 swap_chain_id.unwrap(),
                 device_id,
                 texture_id,
                 desc.size.width,
                 desc.size.height,
                 desc.format,
                 desc.usage,
-            )
-        };
-        if ret != true {
-            let msg = c"Failed to create shared texture";
-            unsafe {
+            );
+            if ret != true {
+                let msg = c"Failed to create shared texture";
                 gfx_critical_note(msg.as_ptr());
-            }
-            return false;
-        }
-
-        let handle = unsafe { wgpu_server_get_vk_image_handle(self.webgpu_parent, texture_id) };
-        if handle.is_null() {
-            let msg = c"Failed to get VkImageHandle";
-            unsafe {
-                gfx_critical_note(msg.as_ptr());
-            }
-            return false;
-        }
-
-        let vk_image_wrapper = unsafe { &*handle };
-
-        let fd = unsafe { wgpu_server_get_dma_buf_fd(self.webgpu_parent, texture_id) };
-        if fd < 0 {
-            let msg = c"Failed to get DMABuf fd";
-            unsafe {
-                gfx_critical_note(msg.as_ptr());
+                return false;
             }
-            return false;
-        }
-
-        // Ensure to close file descriptor
-        let owned_fd = unsafe { OwnedFd::from_raw_fd(fd as RawFd) };
-
-        let image_holder = unsafe {
-            self.device_as_hal::<wgc::api::Vulkan, _, Option<VkImageHolder>>(
-                device_id,
-                |hal_device| {
-                    let hal_device = match hal_device {
-                        None => {
-                            let msg = c"Vulkan device is invalid";
-                            gfx_critical_note(msg.as_ptr());
-                            return None;
-                        }
-                        Some(hal_device) => hal_device,
-                    };
-
-                    let device = hal_device.raw_device();
-
-                    let extent = vk::Extent3D {
-                        width: desc.size.width,
-                        height: desc.size.height,
-                        depth: 1,
-                    };
-                    let mut usage_flags = vk::ImageUsageFlags::empty();
-                    usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
-
-                    let mut external_image_create_info =
-                        vk::ExternalMemoryImageCreateInfo::default()
-                            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
 
-                    let vk_info = vk::ImageCreateInfo::default()
-                        .flags(vk::ImageCreateFlags::ALIAS)
-                        .image_type(vk::ImageType::TYPE_2D)
-                        .format(vk::Format::R8G8B8A8_UNORM)
-                        .extent(extent)
-                        .mip_levels(1)
-                        .array_layers(1)
-                        .samples(vk::SampleCountFlags::TYPE_1)
-                        .tiling(vk::ImageTiling::OPTIMAL)
-                        .usage(usage_flags)
-                        .sharing_mode(vk::SharingMode::EXCLUSIVE)
-                        .initial_layout(vk::ImageLayout::UNDEFINED)
-                        .push_next(&mut external_image_create_info);
-
-                    let image = match device.create_image(&vk_info, None) {
-                        Err(err) => {
-                            let msg =
-                                CString::new(format!("create_image() failed: {:?}", err)).unwrap();
-                            gfx_critical_note(msg.as_ptr());
-                            return None;
-                        }
-                        Ok(image) => image,
-                    };
-
-                    let memory_req = device.get_image_memory_requirements(image);
-                    if memory_req.size > vk_image_wrapper.memory_size {
-                        let msg = c"Invalid memory size";
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-
-                    let mut dedicated_memory_info =
-                        vk::MemoryDedicatedAllocateInfo::default().image(image);
-
-                    let mut import_memory_fd_info = vk::ImportMemoryFdInfoKHR::default()
-                        .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
-                        .fd(owned_fd.into_raw_fd());
+            let handle = wgpu_server_get_vk_image_handle(self.webgpu_parent, texture_id);
+            if handle.is_null() {
+                let msg = c"Failed to get VkImageHandle";
+                gfx_critical_note(msg.as_ptr());
+                return false;
+            }
 
-                    let memory_allocate_info = vk::MemoryAllocateInfo::default()
-                        .allocation_size(vk_image_wrapper.memory_size)
-                        .memory_type_index(vk_image_wrapper.memory_type_index)
-                        .push_next(&mut dedicated_memory_info)
-                        .push_next(&mut import_memory_fd_info);
-
-                    let memory = match device.allocate_memory(&memory_allocate_info, None) {
-                        Err(err) => {
-                            let msg = CString::new(format!("allocate_memory() failed: {:?}", err))
-                                .unwrap();
-                            gfx_critical_note(msg.as_ptr());
-                            return None;
-                        }
-                        Ok(memory) => memory,
-                    };
+            let vk_image_wrapper = &*handle;
 
-                    let result = device.bind_image_memory(image, memory, /* offset */ 0);
-                    if result.is_err() {
-                        let msg = CString::new(format!("bind_image_memory() failed: {:?}", result))
-                            .unwrap();
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-
-                    Some(VkImageHolder {
-                        device: device.handle(),
-                        image,
-                        memory,
-                        fn_destroy_image: device.fp_v1_0().destroy_image,
-                        fn_free_memory: device.fp_v1_0().free_memory,
-                    })
-                },
-            )
-        };
-
-        let image_holder = match image_holder {
-            None => {
-                let msg = c"Failed to get vk::Image";
-                unsafe {
-                    gfx_critical_note(msg.as_ptr());
-                }
+            let fd = wgpu_server_get_dma_buf_fd(self.webgpu_parent, texture_id);
+            if fd < 0 {
+                let msg = c"Failed to get DMABuf fd";
+                gfx_critical_note(msg.as_ptr());
                 return false;
             }
-            Some(image_holder) => image_holder,
-        };
+
+            // Ensure to close file descriptor
+            let owned_fd = OwnedFd::from_raw_fd(fd as RawFd);
+
+            let Some(hal_device) = self.device_as_hal::<wgc::api::Vulkan>(device_id) else {
+                emit_critical_invalid_note("Vulkan device");
+                return false;
+            };
+
+            let device = hal_device.raw_device();
+
+            let extent = vk::Extent3D {
+                width: desc.size.width,
+                height: desc.size.height,
+                depth: 1,
+            };
+            let mut usage_flags = vk::ImageUsageFlags::empty();
+            usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
+
+            let mut external_image_create_info =
+                vk::ExternalMemoryImageCreateInfo::default()
+                    .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
+
+            let vk_info = vk::ImageCreateInfo::default()
+                .flags(vk::ImageCreateFlags::ALIAS)
+                .image_type(vk::ImageType::TYPE_2D)
+                .format(vk::Format::R8G8B8A8_UNORM)
+                .extent(extent)
+                .mip_levels(1)
+                .array_layers(1)
+                .samples(vk::SampleCountFlags::TYPE_1)
+                .tiling(vk::ImageTiling::OPTIMAL)
+                .usage(usage_flags)
+                .sharing_mode(vk::SharingMode::EXCLUSIVE)
+                .initial_layout(vk::ImageLayout::UNDEFINED)
+                .push_next(&mut external_image_create_info);
+
+            let image = match device.create_image(&vk_info, None) {
+                Err(err) => {
+                    let msg =
+                        CString::new(format!("Failed to get vk::Image: create_image() failed: {:?}", err)).unwrap();
+                    gfx_critical_note(msg.as_ptr());
+                    return false;
+                }
+                Ok(image) => image,
+            };
+
+            let memory_req = device.get_image_memory_requirements(image);
+            if memory_req.size > vk_image_wrapper.memory_size {
+                let msg = c"Invalid memory size";
+                gfx_critical_note(msg.as_ptr());
+                return false;
+            }
 
-        let hal_desc = wgh::TextureDescriptor {
-            label: None,
-            size: desc.size,
-            mip_level_count: desc.mip_level_count,
-            sample_count: desc.sample_count,
-            dimension: desc.dimension,
-            format: desc.format,
-            usage: wgt::TextureUses::COPY_DST | wgt::TextureUses::COLOR_TARGET,
-            memory_flags: wgh::MemoryFlags::empty(),
-            view_formats: vec![],
-        };
+            let mut dedicated_memory_info =
+                vk::MemoryDedicatedAllocateInfo::default().image(image);
+
+            let mut import_memory_fd_info = vk::ImportMemoryFdInfoKHR::default()
+                .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
+                .fd(owned_fd.into_raw_fd());
+
+            let memory_allocate_info = vk::MemoryAllocateInfo::default()
+                .allocation_size(vk_image_wrapper.memory_size)
+                .memory_type_index(vk_image_wrapper.memory_type_index)
+                .push_next(&mut dedicated_memory_info)
+                .push_next(&mut import_memory_fd_info);
+
+            let memory = match device.allocate_memory(&memory_allocate_info, None) {
+                Err(err) => {
+                    let msg = CString::new(format!("Failed to get vk::Image: allocate_memory() failed: {:?}", err))
+                        .unwrap();
+                    gfx_critical_note(msg.as_ptr());
+                    return false;
+                }
+                Ok(memory) => memory,
+            };
 
-        let image = image_holder.image;
+            match device.bind_image_memory(image, memory, /* offset */ 0) {
+                Ok(()) => {}
+                Err(err) => {
+                    let msg = CString::new(format!("Failed to get vk::Image: bind_image_memory() failed: {:?}", err))
+                        .unwrap();
+                    gfx_critical_note(msg.as_ptr());
+                    return false;
+                }
+            }
 
-        let hal_texture = unsafe {
-            <wgh::api::Vulkan as wgh::Api>::Device::texture_from_raw(
+            let image_holder = VkImageHolder {
+                device: device.handle(),
+                image,
+                memory,
+                fn_destroy_image: device.fp_v1_0().destroy_image,
+                fn_free_memory: device.fp_v1_0().free_memory,
+            };
+
+            let hal_desc = wgh::TextureDescriptor {
+                label: None,
+                size: desc.size,
+                mip_level_count: desc.mip_level_count,
+                sample_count: desc.sample_count,
+                dimension: desc.dimension,
+                format: desc.format,
+                usage: wgt::TextureUses::COPY_DST | wgt::TextureUses::COLOR_TARGET,
+                memory_flags: wgh::MemoryFlags::empty(),
+                view_formats: vec![],
+            };
+
+            let image = image_holder.image;
+
+            let hal_texture = <wgh::api::Vulkan as wgh::Api>::Device::texture_from_raw(
                 image,
                 &hal_desc,
                 Some(Box::new(move || {
                     image_holder.destroy();
                 })),
-            )
-        };
+            );
 
-        let (_, error) = unsafe {
-            self.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(texture_id))
-        };
-        if let Some(err) = error {
-            let msg = CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap();
-            unsafe {
+            let (_, error) = self.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(texture_id));
+            if let Some(err) = error {
+                let msg = CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap();
                 gfx_critical_note(msg.as_ptr());
+                return false;
             }
-            return false;
+
+            true
         }
-
-        true
     }
 
     #[cfg(target_os = "macos")]
     fn create_texture_with_shared_texture_iosurface(
         &self,
         device_id: id::DeviceId,
         texture_id: id::TextureId,
         desc: &wgc::resource::TextureDescriptor,
         swap_chain_id: Option<SwapChainId>,
     ) -> bool {
+        use metal::foreign_types::ForeignType as _;
+
         let ret = unsafe {
             wgpu_server_ensure_shared_texture_for_swap_chain(
                 self.webgpu_parent,
                 swap_chain_id.unwrap(),
                 device_id,
                 texture_id,
                 desc.size.width,
                 desc.size.height,
@@ -1800,70 +1687,58 @@ impl Global {
             }
             return false;
         }
 
         let io_surface = io_surface::lookup(io_surface_id);
 
         let desc_ref = &desc;
 
-        let raw = unsafe {
-            self.device_as_hal::<wgc::api::Metal, _, Option<metal::Texture>>(
-                device_id,
-                |hal_device| {
-                    let hal_device = match hal_device {
-                        None => {
-                            let msg = c"metal device is invalid";
-                            gfx_critical_note(msg.as_ptr());
-                            return None;
-                        }
-                        Some(hal_device) => hal_device,
-                    };
+        let raw_texture: metal::Texture = unsafe {
+            let Some(hal_device) = self.device_as_hal::<wgc::api::Metal>(device_id) else {
+                emit_critical_invalid_note("metal device");
+                return false;
+            };
 
-                    use metal::foreign_types::ForeignType as _;
-                    let device = hal_device.raw_device();
+            let device = hal_device.raw_device();
 
-                    objc::rc::autoreleasepool(|| {
-                        let descriptor = metal::TextureDescriptor::new();
-                        let usage = metal::MTLTextureUsage::RenderTarget
-                            | metal::MTLTextureUsage::ShaderRead
-                            | metal::MTLTextureUsage::PixelFormatView;
+            objc::rc::autoreleasepool(|| {
+                let descriptor = metal::TextureDescriptor::new();
+                let usage = metal::MTLTextureUsage::RenderTarget
+                    | metal::MTLTextureUsage::ShaderRead
+                    | metal::MTLTextureUsage::PixelFormatView;
 
-                        descriptor.set_texture_type(metal::MTLTextureType::D2);
-                        descriptor.set_width(desc_ref.size.width as u64);
-                        descriptor.set_height(desc_ref.size.height as u64);
-                        descriptor.set_mipmap_level_count(desc_ref.mip_level_count as u64);
-                        descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm);
-                        descriptor.set_usage(usage);
-                        descriptor.set_storage_mode(metal::MTLStorageMode::Private);
-
-                        let raw_device = device.lock();
-                        let raw_texture: metal::Texture = msg_send![*raw_device, newTextureWithDescriptor: descriptor
-                        iosurface:io_surface.obj
-                        plane:0];
+                descriptor.set_texture_type(metal::MTLTextureType::D2);
+                descriptor.set_width(desc_ref.size.width as u64);
+                descriptor.set_height(desc_ref.size.height as u64);
+                descriptor.set_mipmap_level_count(desc_ref.mip_level_count as u64);
+                descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm);
+                descriptor.set_usage(usage);
+                descriptor.set_storage_mode(metal::MTLStorageMode::Private);
 
-                        if raw_texture.as_ptr().is_null() {
-                            let msg = c"Failed to create metal::Texture for swap chain";
-                            gfx_critical_note(msg.as_ptr());
-                            return None;
-                        }
+                let raw_device = device.lock();
+                msg_send![*raw_device, newTextureWithDescriptor: descriptor iosurface:io_surface.obj plane:0]
+            })
+        };
 
-                        if let Some(label) = &desc_ref.label {
-                            raw_texture.set_label(&label);
-                        }
+        if raw_texture.as_ptr().is_null() {
+            let msg = c"Failed to create metal::Texture for swap chain";
+            unsafe {
+                gfx_critical_note(msg.as_ptr());
+            }
+            return false;
+        }
 
-                        Some(raw_texture)
-                    })
-                },
-            )
-        };
+        if let Some(label) = &desc_ref.label {
+            raw_texture.set_label(&label);
+        }
 
         let hal_texture = unsafe {
             <wgh::api::Metal as wgh::Api>::Device::texture_from_raw(
-                raw.unwrap(),
+                raw_texture,
                 wgt::TextureFormat::Bgra8Unorm,
                 metal::MTLTextureType::D2,
                 1,
                 1,
                 wgh::CopyExtent {
                     width: desc.size.width,
                     height: desc.size.height,
                     depth: 1,
@@ -2958,86 +2833,76 @@ pub struct SubmittedWorkDoneClosure {
 unsafe impl Send for SubmittedWorkDoneClosure {}
 
 #[derive(Debug)]
 #[cfg(target_os = "linux")]
 pub struct VkSemaphoreHandle {
     pub semaphore: vk::Semaphore,
 }
 
-#[allow(dead_code)]
-fn emit_critical_invalid_note_if_none<T>(what: &'static str, t: Option<T>) -> Option<T> {
-    if t.is_none() {
-        // SAFETY: We ensure that the pointer provided is not null.
-        let msg = CString::new(format!("{what} is invalid")).unwrap();
-        unsafe { gfx_critical_note(msg.as_ptr()) }
-    }
-    t
-}
-
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub extern "C" fn wgpu_vksemaphore_create_signal_semaphore(
     global: &Global,
     queue_id: id::QueueId,
 ) -> *mut VkSemaphoreHandle {
     let semaphore_handle = unsafe {
-        global.queue_as_hal::<wgc::api::Vulkan, _, Option<VkSemaphoreHandle>>(
-            queue_id,
-            |hal_queue| {
-                let hal_queue = emit_critical_invalid_note_if_none("Vulkan queue", hal_queue)?;
-                let device = hal_queue.raw_device();
+        let Some(hal_queue) = global.queue_as_hal::<wgc::api::Vulkan>(queue_id) else {
+            emit_critical_invalid_note("Vulkan queue");
+            return ptr::null_mut();
+        };
+        let device = hal_queue.raw_device();
 
-                let mut export_semaphore_create_info = vk::ExportSemaphoreCreateInfo::default()
-                    .handle_types(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
-                let create_info =
-                    vk::SemaphoreCreateInfo::default().push_next(&mut export_semaphore_create_info);
-                let semaphore = match device.create_semaphore(&create_info, None) {
-                    Err(err) => {
-                        let msg =
-                            CString::new(format!("create_semaphore() failed: {:?}", err)).unwrap();
-                        gfx_critical_note(msg.as_ptr());
-                        return None;
-                    }
-                    Ok(semaphore) => semaphore,
-                };
+        let mut export_semaphore_create_info = vk::ExportSemaphoreCreateInfo::default()
+            .handle_types(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
+        let create_info =
+            vk::SemaphoreCreateInfo::default().push_next(&mut export_semaphore_create_info);
+        let semaphore = match device.create_semaphore(&create_info, None) {
+            Err(err) => {
+                let msg =
+                    CString::new(format!("create_semaphore() failed: {:?}", err)).unwrap();
+                gfx_critical_note(msg.as_ptr());
+                return ptr::null_mut();
+            }
+            Ok(semaphore) => semaphore,
+        };
 
-                hal_queue.add_signal_semaphore(semaphore, None);
+        hal_queue.add_signal_semaphore(semaphore, None);
 
-                Some(VkSemaphoreHandle { semaphore })
-            },
-        )
+        VkSemaphoreHandle { semaphore }
     };
 
-    match semaphore_handle {
-        None => ptr::null_mut(),
-        Some(semaphore_handle) => Box::into_raw(Box::new(semaphore_handle)),
-    }
+    Box::into_raw(Box::new(semaphore_handle))
 }
 
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub unsafe extern "C" fn wgpu_vksemaphore_get_file_descriptor(
     global: &Global,
     device_id: id::DeviceId,
     handle: &VkSemaphoreHandle,
 ) -> i32 {
     let file_descriptor = unsafe {
-        global.device_as_hal::<wgc::api::Vulkan, _, Option<i32>>(device_id, |hal_device| {
-            let hal_device = emit_critical_invalid_note_if_none("Vulkan device", hal_device)?;
-            let device = hal_device.raw_device();
-            let instance = hal_device.shared_instance().raw_instance();
+        match global.device_as_hal::<wgc::api::Vulkan>(device_id) {
+            None => {
+                emit_critical_invalid_note("Vulkan device");
+                None
+            }
+            Some(hal_device) => {
+                let device = hal_device.raw_device();
+                let instance = hal_device.shared_instance().raw_instance();
 
-            let external_semaphore_fd = khr::external_semaphore_fd::Device::new(instance, device);
-            let get_fd_info = vk::SemaphoreGetFdInfoKHR::default()
-                .semaphore(handle.semaphore)
-                .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
+                let external_semaphore_fd = khr::external_semaphore_fd::Device::new(instance, device);
+                let get_fd_info = vk::SemaphoreGetFdInfoKHR::default()
+                    .semaphore(handle.semaphore)
+                    .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
 
-            external_semaphore_fd.get_semaphore_fd(&get_fd_info).ok()
-        })
+                external_semaphore_fd.get_semaphore_fd(&get_fd_info).ok()
+            }
+        }
     };
 
     // From [Wikipedia](https://en.wikipedia.org/wiki/File_descriptor):
     //
     // > File descriptors typically have non-negative integer values, with negative values
     // > being reserved to indicate "no value" or error conditions.
     file_descriptor.unwrap_or(-1)
 }
@@ -3045,27 +2910,22 @@ pub unsafe extern "C" fn wgpu_vksemaphor
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub unsafe extern "C" fn wgpu_vksemaphore_destroy(
     global: &Global,
     device_id: id::DeviceId,
     handle: &VkSemaphoreHandle,
 ) {
     unsafe {
-        global.device_as_hal::<wgc::api::Vulkan, _, ()>(device_id, |hal_device| {
-            let hal_device = emit_critical_invalid_note_if_none("Vulkan device", hal_device);
-            let hal_device = match hal_device {
-                None => {
-                    return;
-                }
-                Some(hal_device) => hal_device,
-            };
-            let device = hal_device.raw_device();
-            device.destroy_semaphore(handle.semaphore, None);
-        })
+        let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else {
+            emit_critical_invalid_note("Vulkan device");
+            return;
+        };
+        let device = hal_device.raw_device();
+        device.destroy_semaphore(handle.semaphore, None);
     };
 }
 
 #[no_mangle]
 #[cfg(target_os = "linux")]
 pub unsafe extern "C" fn wgpu_vksemaphore_delete(handle: *mut VkSemaphoreHandle) {
     let _ = Box::from_raw(handle);
 }
--- a/supply-chain/audits.toml
+++ b/supply-chain/audits.toml
@@ -4029,16 +4029,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.naga]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.naga]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.net2]]
 who = "Mike Hommey <mh+mozilla@glandium.org>"
 criteria = "safe-to-run"
 delta = "0.2.37 -> 0.2.38"
 
 [[audits.new_debug_unreachable]]
 who = "Bobby Holley <bobbyholley@gmail.com>"
 criteria = "safe-to-deploy"
@@ -6425,16 +6431,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.wgpu-core]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.wgpu-core]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.wgpu-core-deps-apple]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 version = "25.0.0"
 
 [[audits.wgpu-core-deps-apple]]
 who = [
     "Teodor Tanasoaia <ttanasoaia@mozilla.com>",
@@ -6446,16 +6458,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.wgpu-core-deps-apple]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.wgpu-core-deps-apple]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.wgpu-core-deps-windows-linux-android]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 version = "25.0.0"
 
 [[audits.wgpu-core-deps-windows-linux-android]]
 who = [
     "Teodor Tanasoaia <ttanasoaia@mozilla.com>",
@@ -6467,16 +6485,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.wgpu-core-deps-windows-linux-android]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.wgpu-core-deps-windows-linux-android]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.wgpu-hal]]
 who = "Dzmitry Malyshau <kvark@fastmail.com>"
 criteria = "safe-to-deploy"
 version = "0.12.0"
 notes = """
 This crate, up through the indicated version, was written or reviewed
 by Dzmitry Malyshau while he was a Mozilla employee. Dzmitry left
 Mozilla at the beginning of February 2022. This audit statement was
@@ -6566,16 +6590,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.wgpu-hal]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.wgpu-hal]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.wgpu-types]]
 who = "Dzmitry Malyshau <kvark@fastmail.com>"
 criteria = "safe-to-deploy"
 version = "0.12.0"
 notes = """
 This crate, up through the indicated version, was written or reviewed
 by Dzmitry Malyshau while he was a Mozilla employee. Dzmitry left
 Mozilla at the beginning of February 2022. This audit statement was
@@ -6660,16 +6690,22 @@ criteria = "safe-to-deploy"
 delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847"
 importable = false
 
 [[audits.wgpu-types]]
 who = "Erich Gubler <erichdongubler@gmail.com>"
 criteria = "safe-to-deploy"
 delta = "25.0.0 -> 26.0.0"
 
+[[audits.wgpu-types]]
+who = "Andy Leiserson <aleiserson@mozilla.com>"
+criteria = "safe-to-deploy"
+delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a"
+importable = false
+
 [[audits.whatsys]]
 who = "Bobby Holley <bobbyholley@gmail.com>"
 criteria = "safe-to-deploy"
 version = "0.1.2"
 notes = """
 Contains platform-specific FFI code for apple, mac, and windows. The windows code
 also contains a small C file compiled at build-time. I audited all of it and it
 looks correct.
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setIndexBuffer/cts.https.html.ini
+++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setIndexBuffer/cts.https.html.ini
@@ -12,17 +12,9 @@
 
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_alignment:*]
   implementation-status: backlog
   [:]
     expected: FAIL
 
 
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_and_size_oob:*]
-  implementation-status: backlog
-  expected:
-    if os == "linux" and debug: CRASH
-    if os == "mac" and debug: CRASH
   [:]
-    expected:
-      if os == "win": FAIL
-      if os == "linux" and not debug: FAIL
-      if os == "mac" and not debug: FAIL
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setVertexBuffer/cts.https.html.ini
+++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setVertexBuffer/cts.https.html.ini
@@ -1,24 +1,16 @@
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_alignment:*]
   implementation-status: backlog
   [:]
     expected: FAIL
 
 
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_and_size_oob:*]
-  implementation-status: backlog
-  expected:
-    if os == "linux" and debug: CRASH
-    if os == "mac" and debug: CRASH
   [:]
-    expected:
-      if os == "win": FAIL
-      if os == "linux" and not debug: FAIL
-      if os == "mac" and not debug: FAIL
 
 
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:slot:*]
   [:]
 
 
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer,device_mismatch:*]
   [:]
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/setBindGroup/cts.https.html.ini
+++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/setBindGroup/cts.https.html.ini
@@ -171,18 +171,17 @@
 [cts.https.html?q=webgpu:api,validation,encoding,cmds,setBindGroup:state_and_binding_index:*]
   implementation-status: backlog
   expected:
     if os == "linux": [OK, CRASH]
   [:encoderType="compute%20pass";state="destroyed";resourceType="buffer"]
     expected: FAIL
 
   [:encoderType="compute%20pass";state="destroyed";resourceType="texture"]
-    expected:
-      if os == "win" and debug: [PASS, FAIL]
+    expected: FAIL
 
   [:encoderType="compute%20pass";state="invalid";resourceType="buffer"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
 
   [:encoderType="compute%20pass";state="invalid";resourceType="texture"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
@@ -194,18 +193,17 @@
   [:encoderType="compute%20pass";state="valid";resourceType="texture"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
 
   [:encoderType="render%20bundle";state="destroyed";resourceType="buffer"]
     expected: FAIL
 
   [:encoderType="render%20bundle";state="destroyed";resourceType="texture"]
-    expected:
-      if os == "win" and debug: [PASS, FAIL]
+    expected: FAIL
 
   [:encoderType="render%20bundle";state="invalid";resourceType="buffer"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
 
   [:encoderType="render%20bundle";state="invalid";resourceType="texture"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
@@ -217,18 +215,17 @@
   [:encoderType="render%20bundle";state="valid";resourceType="texture"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
 
   [:encoderType="render%20pass";state="destroyed";resourceType="buffer"]
     expected: FAIL
 
   [:encoderType="render%20pass";state="destroyed";resourceType="texture"]
-    expected:
-      if os == "win" and debug: [PASS, FAIL]
+    expected: FAIL
 
   [:encoderType="render%20pass";state="invalid";resourceType="buffer"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
 
   [:encoderType="render%20pass";state="invalid";resourceType="texture"]
     expected:
       if os == "win" and debug: [PASS, FAIL]
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/image_copy/layout_related/cts.https.html.ini
+++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/image_copy/layout_related/cts.https.html.ini
@@ -1685,32 +1685,21 @@
   [:method="WriteTexture";dimension="2d";size=[4,4,3\]]
     expected: FAIL
 
   [:method="WriteTexture";dimension="3d";size=[4,4,3\]]
     expected: FAIL
 
 
 [cts.https.html?q=webgpu:api,validation,image_copy,layout_related:copy_end_overflows_u64:*]
-  implementation-status:
-    if debug: backlog
-  expected:
-    if os == "linux" and debug: CRASH
-    if os == "mac" and debug: CRASH
   [:method="CopyB2T"]
-    expected:
-      if os == "win" and debug: FAIL
 
   [:method="CopyT2B"]
-    expected:
-      if os == "win" and debug: FAIL
 
   [:method="WriteTexture"]
-    expected:
-      if os == "win" and debug: FAIL
 
 
 [cts.https.html?q=webgpu:api,validation,image_copy,layout_related:offset_alignment:*]
   [:method="CopyB2T";format="astc-10x10-unorm";dimension="2d"]
 
   [:method="CopyB2T";format="astc-10x10-unorm";dimension="3d"]
 
   [:method="CopyB2T";format="astc-10x10-unorm-srgb";dimension="2d"]
--- a/third_party/rust/naga/.cargo-checksum.json
+++ b/third_party/rust/naga/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"3eed95bdea8c5d544ed14d6cea7d1997a66f4f0f3d8a085162b3dc591258e564","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"999de9d55d01213789072a63ad4ae9b4635e6653984d38db8b308d42bb1e7be3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"ddd6c404c9b7d7d1aa041af1a8c3d451ef6e71339d408eac22f10d25d33d5b18","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"214622a55414393f205a7e71a5aa2bd535e76fde71b612845f251ca57bd32539","src/back/glsl/features.rs":"5975ad4ae9c2e78f795f9d2532d03fe425ce910a146f6fe8863f95a4f029b280","src/back/glsl/keywords.rs":"4cfbcf931f8b234f10b7cd807839764945cd6ece71910735d9bae362690aceed","src/back/glsl/mod.rs":"19c02133c489e35f8e7a93eceb8a2b28a31a008dfc284102bfc7a9ff66e7e90d","src/back/hlsl/conv.rs":"3e1a78203e8c4efb75986db962cec150c7b2d99f7e48b400e702233de70e8aab","src/back/hlsl/help.rs":"67786bb73f4809769d8e5f97a401f576a89803f7c95a92e59088271ccb84d9d6","src/back/hlsl/keywords.rs":"af1c16b81f14f3ae04e3911701cf0782fcaf54ad9427a13e5fdc4dd0ca441e5f","src/back/hlsl/mod.rs":"e644011ea83a6dd194e417a640deb395160d7af4460d30c1359145b3d6dacc5e","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"7443cea2abb6ce8d0c0c9bfe805b37b5600bd28618de44ba1ebd8e4e38eac92f","src/back/hlsl/writer.rs":"4fdaa36c745269e5759737dbb6907e5bb304b0baec8e72bd6770d979afd4a9ef","src/back/mod.rs":"1489e44272b0fbe58e6e5042fcb6299525c00ce42a811944c6f94935379e52d7","src/back/msl/keywords.rs":"f1f080b02d98a36ccde81a3b77ae12651272dffc4043ddaebd6937673154ba2b","src/back/msl/mod.rs":"f980ddf9cfaf0f7e0249a9580216cafe76405047cd949210bfbfb29ee64e1cfb","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"1c6c3662d20c60261b4bc0550adca55f6e14c7164eb9456252e1ea54e40dd949","src/back/pipeline_constants.rs":"c2244d7e47a52c01ead61b4b6c7b3d0f29263ca308aca70f213137a0938c9aa4","src/back/spv/block.rs":"d005284f0fb17b4bf3e3b7323183e903bfae7e86956419b9602891ed950eaa45","src/back/spv/helpers.rs":"37ef7388b1e97edb2682b93f1f0eceb71039ecd54923d91346d974b29322077c","src/back/spv/image.rs":"e22cb4c56e29d049a512a7fe43d6ad2c059a17e06531ae84b3c9446ac27c35f6","src/back/spv/index.rs":"5f0561a83011bcf482575d209c549ce08fce85b9dd95f179f6e8c2b112e0c8e5","src/back/spv/instructions.rs":"556f1f30ae11c3e01910c354a36ba314280932e3a2928584b06eb0812a2cb81a","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"ba6228b2addde92d6671410df87970cb31baa06818f507930f278a6307d58140","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":"3e2fa86bdc1a8117512ac20eaf208124cefd77b6ef451c2d4e2da74ffa684fb9","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":"36aa1d68def860e9befd9c694d841fc5c0680f98cba61c33989cfea6eb705771","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":"c506579e7f124643a35373705a870318500e000a6a752be58666bcbb3c08fc1f","src/common/wgsl/types.rs":"9ccdd6676437ac7e282a508403eb24742dea654b380d6419ffe5aac9cd699996","src/compact/expressions.rs":"1bd4426d06afda9ba226a495406e8239a8d87bbbf8a89b6fab4a78c9bd6880cf","src/compact/functions.rs":"f9598be11b9bbdd63a2c42348b8a25422f477287b92b331ac7ebd7ba4d44d879","src/compact/handle_set_map.rs":"f282349ba0d1e35a873f6ee9ff9086ae061d3dd8e31f2a291c443bd0e7e1ebfd","src/compact/mod.rs":"03ceafe4140713c279168bcd20b17c9bb9f880d406806fd63ca2065de9950f0f","src/compact/statements.rs":"85b2faf6a4caaebc0372e773ca3be2904db5bb0e691ac7ea845720ef0864a22b","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"b7f570cc9e334e2b5a1aec499b4742457eba6f2f6673de4e80c8f5499eb16793","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"5514238a48529d2bb953a032d13014c00adfe6c497e13ac33d27a5f17ae1fc63","src/front/glsl/context.rs":"14fd933c79f49f4fb4ccabdc24ad31745777806f7464f111a4f7782662612a4b","src/front/glsl/error.rs":"4f0836fbab8dcdad0603d4e3164d17b48f5d7498b829665ed0c9c48c3fb0b410","src/front/glsl/functions.rs":"28aa0fa2e048a296df0f342d482ee5e02510ae39bfa96fb400a5892cfff71cf9","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":"74762e4375fd5c1d2b425a80d40bf5771fa06ad9eb6838ffed7cdfcc1b909a06","src/front/spv/convert.rs":"16b8281fc1ae75dc62a02893db2c5b6d8994166e78b3b6b8cac7a01e0da4eae2","src/front/spv/error.rs":"ac484fca63ed6aa83a9e2527de049f0afaa6d92aa132e4e9aee4cf60f0bdd471","src/front/spv/function.rs":"c929cdc1a4b83fff75d9dcd1404c243142d288efbbe0ec5afef20e9602635142","src/front/spv/image.rs":"368ec748dd0e35ea855f5d69ebb8b6df5e9445d986cd7ad858a7c85d2af520d7","src/front/spv/mod.rs":"46301fb6946e0740ae4ea36888c09846e53ac067f52f8c58eaaf43d9b61d6bc0","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"d7abef5dfc9e18ae549ebb87bd61f5c9cd1007bde3cf280745dbadb48667a248","src/front/wgsl/error.rs":"ded41f78cd926b50eb31113da82cbeae15c47e390b17692f39404ab346ae1d21","src/front/wgsl/index.rs":"1db1bee7074a3fe9668d2c2ba0bd5053d6443f4ea19a56e4cccf2aa2bc8a33c9","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"0c941c094880f1df02d7f552583692dfd2214fece0244ab97f0e2f7cb4ef1736","src/front/wgsl/mod.rs":"b7b407ad94e91d32135643350b4549b3320a3ebdbfd22292218ae35aec95c5bc","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"a03db6fc5c7c04eb84ea3b9338c96ee0574ad5b59defd80b9ea6bdc1df279643","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"21de0a5b3146764de193b78e823cc5a925fdff3301eb277dafd0c31b55d86aeb","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"dcb58fb3746ceff5fc74637b77b57ef7d4883405c12ef43e032970475f3eeec9","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"a50bd5d6d218fc0be8876d1f9db7936ff593d93805c5e85754ae6bf277beae32","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"a94b9fcd19ea4cab1dba48b420c1851d872802646101e56aa3e1621c0d4ec473","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"291811eef2a56f625c460b33a5a459d685e4eca2d9f30e24816bcc72a5e4705f","src/lib.rs":"81a21310e6db0d30efa8f679e65167706deef9cbb03c2006dfac1989f1ed140b","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/path_like.rs":"2740c65fc61e490b24066cdefc8ae2822650bd0c9323f83054e18005a28dfc48","src/proc/constant_evaluator.rs":"abc75112f5ffde7893ab71c8c0082198f24df98780d3ccbc34d6c5deb87fb0e4","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"f1defc37588bb9ef8c097db8f7ebe4898a9aa182d8009d3c2e76b38b4144fb91","src/proc/layouter.rs":"bf50fed8cf4b15400218fa1cf897f04925795939b09c9ce658eb8bc7559a5705","src/proc/mod.rs":"8b79b860f32f27568b9e2a45845424deb89960bbcd32ef46e168bc4ab995457c","src/proc/namer.rs":"d706e30b34f3d2b3e292174acfce229a2579dbffc986ee81e5bb6219bf8bb76f","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":"e272f1973c881f17ef23a0509edc0a1184b20778b1f03bdb33a4d6b15c4a25e1","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":"f1b73b2507377d04ee873ace7971e1b4bc90ff520d3534df1cd29de56035366a","src/proc/typifier.rs":"3bea9c55fb9d6141072c6a17b6fc9d990de4bd5209bf5ea3eb3a5d72466aa2c4","src/racy_lock.rs":"b5b6e081c9519648a61225710b656b53dd695ae65a1cd9ca927946340b2a6e70","src/span.rs":"666a413531c2eb44ab5a42a84349d25f5747f52337268afeb1714c7740d94961","src/valid/analyzer.rs":"9e0479bee5d2ac15704f69d8852400cd1bcd35bc01c056cb9a510db6dec63a39","src/valid/compose.rs":"44f01ed290d49b9ffc5651c2edaf9a7aa3b969828790a732da39a908b54aee24","src/valid/expression.rs":"469df8f97ead6e7b21f14a68c95bcc008f178661f095eccb8f6123461ee5fd6a","src/valid/function.rs":"8e2891789df255e0b8472e9b5e092ded0171f17d1e953b18c8f7c6eea135237c","src/valid/handles.rs":"59f96f672f57e253006f330a3b9a540564dfb462a543e5cad6d20231de29538f","src/valid/interface.rs":"0bb4025647600237b78d4e7188f88af44bb66fcd77db987ae88baf73161ea8fe","src/valid/mod.rs":"b262c3c31affe6a645ad87aa4c396c987c5ed173a1f038247d6607572b1c8b82","src/valid/type.rs":"0947af787fcbd40ac74dc6fb35c1973879cbd548d1cb815eb0907c0a7bf7c362"},"package":null}
\ No newline at end of file
+{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"29cc03bac7a55b4e0bb3ae20ed22e44c3711deaba835b025177086247aca668c","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"999de9d55d01213789072a63ad4ae9b4635e6653984d38db8b308d42bb1e7be3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"ddd6c404c9b7d7d1aa041af1a8c3d451ef6e71339d408eac22f10d25d33d5b18","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"214622a55414393f205a7e71a5aa2bd535e76fde71b612845f251ca57bd32539","src/back/glsl/features.rs":"5975ad4ae9c2e78f795f9d2532d03fe425ce910a146f6fe8863f95a4f029b280","src/back/glsl/keywords.rs":"4cfbcf931f8b234f10b7cd807839764945cd6ece71910735d9bae362690aceed","src/back/glsl/mod.rs":"19c02133c489e35f8e7a93eceb8a2b28a31a008dfc284102bfc7a9ff66e7e90d","src/back/hlsl/conv.rs":"3e1a78203e8c4efb75986db962cec150c7b2d99f7e48b400e702233de70e8aab","src/back/hlsl/help.rs":"67786bb73f4809769d8e5f97a401f576a89803f7c95a92e59088271ccb84d9d6","src/back/hlsl/keywords.rs":"af1c16b81f14f3ae04e3911701cf0782fcaf54ad9427a13e5fdc4dd0ca441e5f","src/back/hlsl/mod.rs":"e644011ea83a6dd194e417a640deb395160d7af4460d30c1359145b3d6dacc5e","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"7443cea2abb6ce8d0c0c9bfe805b37b5600bd28618de44ba1ebd8e4e38eac92f","src/back/hlsl/writer.rs":"4fdaa36c745269e5759737dbb6907e5bb304b0baec8e72bd6770d979afd4a9ef","src/back/mod.rs":"1489e44272b0fbe58e6e5042fcb6299525c00ce42a811944c6f94935379e52d7","src/back/msl/keywords.rs":"f1f080b02d98a36ccde81a3b77ae12651272dffc4043ddaebd6937673154ba2b","src/back/msl/mod.rs":"f980ddf9cfaf0f7e0249a9580216cafe76405047cd949210bfbfb29ee64e1cfb","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"1c6c3662d20c60261b4bc0550adca55f6e14c7164eb9456252e1ea54e40dd949","src/back/pipeline_constants.rs":"c2244d7e47a52c01ead61b4b6c7b3d0f29263ca308aca70f213137a0938c9aa4","src/back/spv/block.rs":"d005284f0fb17b4bf3e3b7323183e903bfae7e86956419b9602891ed950eaa45","src/back/spv/helpers.rs":"37ef7388b1e97edb2682b93f1f0eceb71039ecd54923d91346d974b29322077c","src/back/spv/image.rs":"e22cb4c56e29d049a512a7fe43d6ad2c059a17e06531ae84b3c9446ac27c35f6","src/back/spv/index.rs":"5f0561a83011bcf482575d209c549ce08fce85b9dd95f179f6e8c2b112e0c8e5","src/back/spv/instructions.rs":"556f1f30ae11c3e01910c354a36ba314280932e3a2928584b06eb0812a2cb81a","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"ba6228b2addde92d6671410df87970cb31baa06818f507930f278a6307d58140","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":"3e2fa86bdc1a8117512ac20eaf208124cefd77b6ef451c2d4e2da74ffa684fb9","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":"36aa1d68def860e9befd9c694d841fc5c0680f98cba61c33989cfea6eb705771","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":"c506579e7f124643a35373705a870318500e000a6a752be58666bcbb3c08fc1f","src/common/wgsl/types.rs":"9ccdd6676437ac7e282a508403eb24742dea654b380d6419ffe5aac9cd699996","src/compact/expressions.rs":"1bd4426d06afda9ba226a495406e8239a8d87bbbf8a89b6fab4a78c9bd6880cf","src/compact/functions.rs":"f9598be11b9bbdd63a2c42348b8a25422f477287b92b331ac7ebd7ba4d44d879","src/compact/handle_set_map.rs":"f282349ba0d1e35a873f6ee9ff9086ae061d3dd8e31f2a291c443bd0e7e1ebfd","src/compact/mod.rs":"03ceafe4140713c279168bcd20b17c9bb9f880d406806fd63ca2065de9950f0f","src/compact/statements.rs":"85b2faf6a4caaebc0372e773ca3be2904db5bb0e691ac7ea845720ef0864a22b","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"b7f570cc9e334e2b5a1aec499b4742457eba6f2f6673de4e80c8f5499eb16793","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"5514238a48529d2bb953a032d13014c00adfe6c497e13ac33d27a5f17ae1fc63","src/front/glsl/context.rs":"14fd933c79f49f4fb4ccabdc24ad31745777806f7464f111a4f7782662612a4b","src/front/glsl/error.rs":"4f0836fbab8dcdad0603d4e3164d17b48f5d7498b829665ed0c9c48c3fb0b410","src/front/glsl/functions.rs":"28aa0fa2e048a296df0f342d482ee5e02510ae39bfa96fb400a5892cfff71cf9","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":"74762e4375fd5c1d2b425a80d40bf5771fa06ad9eb6838ffed7cdfcc1b909a06","src/front/spv/convert.rs":"16b8281fc1ae75dc62a02893db2c5b6d8994166e78b3b6b8cac7a01e0da4eae2","src/front/spv/error.rs":"ac484fca63ed6aa83a9e2527de049f0afaa6d92aa132e4e9aee4cf60f0bdd471","src/front/spv/function.rs":"c929cdc1a4b83fff75d9dcd1404c243142d288efbbe0ec5afef20e9602635142","src/front/spv/image.rs":"368ec748dd0e35ea855f5d69ebb8b6df5e9445d986cd7ad858a7c85d2af520d7","src/front/spv/mod.rs":"46301fb6946e0740ae4ea36888c09846e53ac067f52f8c58eaaf43d9b61d6bc0","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"d7abef5dfc9e18ae549ebb87bd61f5c9cd1007bde3cf280745dbadb48667a248","src/front/wgsl/error.rs":"ded41f78cd926b50eb31113da82cbeae15c47e390b17692f39404ab346ae1d21","src/front/wgsl/index.rs":"1db1bee7074a3fe9668d2c2ba0bd5053d6443f4ea19a56e4cccf2aa2bc8a33c9","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"0c941c094880f1df02d7f552583692dfd2214fece0244ab97f0e2f7cb4ef1736","src/front/wgsl/mod.rs":"b7b407ad94e91d32135643350b4549b3320a3ebdbfd22292218ae35aec95c5bc","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"a03db6fc5c7c04eb84ea3b9338c96ee0574ad5b59defd80b9ea6bdc1df279643","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"21de0a5b3146764de193b78e823cc5a925fdff3301eb277dafd0c31b55d86aeb","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"dcb58fb3746ceff5fc74637b77b57ef7d4883405c12ef43e032970475f3eeec9","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"a50bd5d6d218fc0be8876d1f9db7936ff593d93805c5e85754ae6bf277beae32","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"a94b9fcd19ea4cab1dba48b420c1851d872802646101e56aa3e1621c0d4ec473","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"291811eef2a56f625c460b33a5a459d685e4eca2d9f30e24816bcc72a5e4705f","src/lib.rs":"81a21310e6db0d30efa8f679e65167706deef9cbb03c2006dfac1989f1ed140b","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/path_like.rs":"2740c65fc61e490b24066cdefc8ae2822650bd0c9323f83054e18005a28dfc48","src/proc/constant_evaluator.rs":"abc75112f5ffde7893ab71c8c0082198f24df98780d3ccbc34d6c5deb87fb0e4","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"f1defc37588bb9ef8c097db8f7ebe4898a9aa182d8009d3c2e76b38b4144fb91","src/proc/layouter.rs":"bf50fed8cf4b15400218fa1cf897f04925795939b09c9ce658eb8bc7559a5705","src/proc/mod.rs":"8b79b860f32f27568b9e2a45845424deb89960bbcd32ef46e168bc4ab995457c","src/proc/namer.rs":"d706e30b34f3d2b3e292174acfce229a2579dbffc986ee81e5bb6219bf8bb76f","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":"e272f1973c881f17ef23a0509edc0a1184b20778b1f03bdb33a4d6b15c4a25e1","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":"f1b73b2507377d04ee873ace7971e1b4bc90ff520d3534df1cd29de56035366a","src/proc/typifier.rs":"3bea9c55fb9d6141072c6a17b6fc9d990de4bd5209bf5ea3eb3a5d72466aa2c4","src/racy_lock.rs":"b5b6e081c9519648a61225710b656b53dd695ae65a1cd9ca927946340b2a6e70","src/span.rs":"666a413531c2eb44ab5a42a84349d25f5747f52337268afeb1714c7740d94961","src/valid/analyzer.rs":"9e0479bee5d2ac15704f69d8852400cd1bcd35bc01c056cb9a510db6dec63a39","src/valid/compose.rs":"44f01ed290d49b9ffc5651c2edaf9a7aa3b969828790a732da39a908b54aee24","src/valid/expression.rs":"469df8f97ead6e7b21f14a68c95bcc008f178661f095eccb8f6123461ee5fd6a","src/valid/function.rs":"8e2891789df255e0b8472e9b5e092ded0171f17d1e953b18c8f7c6eea135237c","src/valid/handles.rs":"59f96f672f57e253006f330a3b9a540564dfb462a543e5cad6d20231de29538f","src/valid/interface.rs":"0bb4025647600237b78d4e7188f88af44bb66fcd77db987ae88baf73161ea8fe","src/valid/mod.rs":"b262c3c31affe6a645ad87aa4c396c987c5ed173a1f038247d6607572b1c8b82","src/valid/type.rs":"0947af787fcbd40ac74dc6fb35c1973879cbd548d1cb815eb0907c0a7bf7c362"},"package":null}
\ No newline at end of file
--- a/third_party/rust/naga/Cargo.toml
+++ b/third_party/rust/naga/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.82.0"
 name = "naga"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = "build.rs"
 exclude = [
     "bin/**/*",
     "tests/**/*",
     "Cargo.lock",
     "target/**/*",
 ]
--- a/third_party/rust/wgpu-core-deps-apple/.cargo-checksum.json
+++ b/third_party/rust/wgpu-core-deps-apple/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6731a9da7b46084fa1c5cb6d8d55026c10a84b11a9d61dfed9275b5528fab0ad","README.md":"729fdd16cb87ad318ed2bfc70593363aa324c804c825ffea7c42670dff681255","src/lib.rs":"54ef7b7d746c6b26b0ee65552cc969d69c6204d0d38b3678c40bffbfbc5a146c"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"7a8c769f2eb7ea6b5a24f430264b36c878413198a87a8b9faa65002d7be95f96","README.md":"729fdd16cb87ad318ed2bfc70593363aa324c804c825ffea7c42670dff681255","src/lib.rs":"54ef7b7d746c6b26b0ee65552cc969d69c6204d0d38b3678c40bffbfbc5a146c"},"package":null}
\ No newline at end of file
--- a/third_party/rust/wgpu-core-deps-apple/Cargo.toml
+++ b/third_party/rust/wgpu-core-deps-apple/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.76"
 name = "wgpu-core-deps-apple"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = false
 autolib = false
 autobins = false
 autoexamples = false
 autotests = false
 autobenches = false
 description = "Feature unification helper crate for Apple platforms"
@@ -39,10 +39,10 @@ vulkan-portability = [
     "wgpu-hal/renderdoc",
 ]
 
 [lib]
 name = "wgpu_core_deps_apple"
 path = "src/lib.rs"
 
 [target.'cfg(target_vendor = "apple")'.dependencies.wgpu-hal]
-version = "25.0.0"
+version = "26.0.0"
 path = "../../../wgpu-hal"
--- a/third_party/rust/wgpu-core-deps-windows-linux-android/.cargo-checksum.json
+++ b/third_party/rust/wgpu-core-deps-windows-linux-android/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"0b0dd61a2bcfaf314f95e1ccc01b1c27bb2d984fbf02f87429e2fd7125aa6b32","README.md":"38086a02e134ac959bd061f1161c141a848a1b05a6bf31874035908217ad3eed","src/lib.rs":"a99034037e9c9ddf912f44c05b98af2c11e0ed0d09bb7cb69577826f46062ab9"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"41aec5999e044b23c0f31729cfb447099f4be9d943d52d659b25fdd7609448db","README.md":"38086a02e134ac959bd061f1161c141a848a1b05a6bf31874035908217ad3eed","src/lib.rs":"a99034037e9c9ddf912f44c05b98af2c11e0ed0d09bb7cb69577826f46062ab9"},"package":null}
\ No newline at end of file
--- a/third_party/rust/wgpu-core-deps-windows-linux-android/Cargo.toml
+++ b/third_party/rust/wgpu-core-deps-windows-linux-android/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.76"
 name = "wgpu-core-deps-windows-linux-android"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = false
 autolib = false
 autobins = false
 autoexamples = false
 autotests = false
 autobenches = false
 description = "Feature unification helper crate for the Windows/Linux/Android platforms"
@@ -34,10 +34,10 @@ gles = ["wgpu-hal/gles"]
 renderdoc = ["wgpu-hal/renderdoc"]
 vulkan = ["wgpu-hal/vulkan"]
 
 [lib]
 name = "wgpu_core_deps_windows_linux_android"
 path = "src/lib.rs"
 
 [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies.wgpu-hal]
-version = "25.0.0"
+version = "26.0.0"
 path = "../../../wgpu-hal"
--- a/third_party/rust/wgpu-core/.cargo-checksum.json
+++ b/third_party/rust/wgpu-core/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"76e5f69ff2a959493c3621810bea2db96e67cc6894d99acfd76d85108eb2f360","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"c67295643e006849b11d2d4bf64142e6485280e19887523785c3c03cb5fe1f32","src/binding_model.rs":"1e6a73574e602ec8b4ff57ba11fa6c62b8431ceceda4f5508c2048240236e12e","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"c88aa87bf3052fe0993b79ff047339fac4557ead85973f4a37bf236fba401222","src/command/bundle.rs":"59dd5714d3b553339864f9c9f5fcfc8a6a7816a4ba9b59aa459b5ea7f3edfcd3","src/command/clear.rs":"7e03fa2b2516e4f930599b5fa72f326805c18ee004bed04ad74e317c007c4c42","src/command/compute.rs":"43796e32cc5cb3b2cbd6f310fa6eccb1c6291a3c65b67007cfd690f06fb686b3","src/command/compute_command.rs":"18aa0b8e389a5d345243b876b1abbacfc998a19d23069e092183fa7be10fa0ab","src/command/draw.rs":"304a308ac77cab1f6904d77516047497ede7f18562e0800a8cc918ae1d314d05","src/command/memory_init.rs":"f25554cff06f96e37afd81153a351e9d8482c855318b86b4db29231926d265b5","src/command/mod.rs":"a750bb0a17c60407df4f3604995db40d20353564e077984ea865284a560c4ec3","src/command/pass.rs":"23f17526798dff6e352359e166c6734e34c16c0087f60a9c1c9951d2442fb4cc","src/command/query.rs":"189d9949f0431ad0c3826936651959b7c4219fb3fe4eacb2122ffb2f7a9ce124","src/command/ray_tracing.rs":"ebc6fe1bd6b8fc86b9cc0bb74666b638416d3709b220d3a8b5cc00d1c791a3a7","src/command/render.rs":"34378658b994cf1d727d9078d7e5b4b35a2621153faf8c44db7ec8b7cdbbdad6","src/command/render_command.rs":"209242e9ab30e23044840f89efed62e4d0dbadf832fcaf5a861d2487af4358ad","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"5917c1c1371acb6045517ad0b828e1810762ea60cf8df2569d1faf8fecf36c6b","src/command/transition_resources.rs":"b591797bb75f937bce6d5bffc60b54bbcdb78111ea8d140f4a8c17d80958f226","src/conv.rs":"02722149d21bcdba6ee5101b3c0625a9de8ef607523a0eebb1f4088e82b3608b","src/device/bgl.rs":"fcb1d53b692970912781748379df675268981c97352872abf2e7bb0b1ebdd533","src/device/global.rs":"298d32daa32f67b5c6c47739d4173033c4930eb4b51281e595eefe70f9816dfc","src/device/life.rs":"c14c34512f24a511febbe4f3ef092e2c8ad43e5bdd5c29b7e965b19827b80b52","src/device/mod.rs":"b1949bf0f98ebe0604f7c342acb88022a6749ea94e92731e18f832b824f915ec","src/device/queue.rs":"202acc9a5192e78e4c28dac46d3ba879c60f9ad56917708370d28478d153b3e8","src/device/ray_tracing.rs":"237fc05b6258c102037a0ec13942727375f088bfdbde078e7360bfa49e44a041","src/device/resource.rs":"269ad0cab4ae709e8abc6d05426ba1865b57ea48d3b1b221cb179f3a6cec1bf2","src/device/trace.rs":"48316a9360ba795ce024f4e93fb1751ca0fa4210a93c6255ebc9a6d9a0f15e72","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"7bb7dc795d01607fd5d6f4477b55255c71fe4b1f8621a004b0a4305d6641fc20","src/hal_api.rs":"7962c119456602e9c2ba958712660532290cabe0b8c4c67ef7595de73cdf8b57","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"ce0a14d5a3314df318bbc7c4d8c40ea2b3197dbddb2227e828ceb5127db7d37d","src/id.rs":"207f262558388147b484c51cf07d2554c26a3e19243058939e63a7f8e5c7ea75","src/identity.rs":"0a92302fc5b483ea1a8750b1672971af1cf2abfd4c0325bb02488b43e85073e2","src/indirect_validation/dispatch.rs":"1d732bb0e0716c6e5505871ea0dcc9de128fb9c9e2813769f359088d8f1573f9","src/indirect_validation/draw.rs":"a2f6d25318e0a679ce12f9ef439e96867ffb1ef57119810f78dd59e5a4804150","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":"3895c4a2284631b6d6247c0d96c5fc9cfd024d358e09cad8752b2505700138a3","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"80d8ab62ebad5c7093c1afa3345b09e480fa0e2d7ad0170a8f3b782d359f8e90","src/lib.rs":"5686a1fd2149f1ef352e5f5bacd3322d7721040cc5fed5b67f45163cf5730736","src/lock/mod.rs":"7343aa3ee73a0e6d41f0c28c658f22a2af0ff3e558a2c3437764ebc038816c0f","src/lock/observing.rs":"21c4749dad50cdbed159d8cc44ffd87e83620bb9fabc715773ac7f88afe1b276","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"7f44776bc7d71a25e23c97ab80e2fdab3576bb3f912bc8a0b4fcc28a64ef5c6e","src/lock/vanilla.rs":"3a772dfc1f8d8d4047669962beaa15542f771d2dcbe4e1755cd2cfed5cbacca0","src/pipeline.rs":"3f81da8f824feb62a8c7e22811d409e14507945c3bab795878d41b9989f7c0e6","src/pipeline_cache.rs":"256bf8df58d8ab904afddc132349d03e4f659b6bd6882bc8df582dcfd05ae3d5","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"d0ab0b3ab29f3e49828a595ed432f0281bf569b5eafb0bb996f49bcfab86d2c0","src/ray_tracing.rs":"6e33799815e98d0dc7e98902e6b9c9c928bc50aaab27f343379989a13cc728f9","src/registry.rs":"779d8c277193537edd2b883b72cdcc07161b7231c8d2c80be726bd800cd327b6","src/resource.rs":"6410c784d2b4f292f296d1cdf6ad4a58541bdf3702489f8071cfc50f59537636","src/scratch.rs":"05f2032fa6d6f589c2507f4028755769b9524029e5ad59cc500cab7940e40d42","src/snatch.rs":"d75583fa0504b60554b14a865e1b1062b6b1dea7d99903cf09d03608f3a78a4c","src/storage.rs":"8a4d20e85c3ac135316dcb0dab41ec4d335d86d34959d4392ec07f592125f0d3","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"a1aab50a03ae283e86db0885ad00239278da8b3a40647f2d93fa15b2f23e51dc","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"1ab5310367606fc74f0791733ea5ba2e09acc92ff7f4f4773f66bcfb3138c52f","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"93348b15d04f2680507e9dde66df2c70d82ebcaae170b0dfb203a72482ff4bda","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"fbd5f3cde5161404048131dbea014806cfc210ab1497bfd638f0064969c004f9","src/validation.rs":"256f8ff5e579af4f1319997a2ca9e110f806ecf0d9b5534a2c5b4bd4f0c10776","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"2612ad61671a56b139c5c92fd152e633e47550b945ba1a727af71af65e7ad87f","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"c67295643e006849b11d2d4bf64142e6485280e19887523785c3c03cb5fe1f32","src/as_hal.rs":"c3fa229dc0c65b1480951c53994afba580a595d13ecdad04095a83081ff4fe57","src/binding_model.rs":"f5f669f6ba53ce0940bacbbaa6100661a43e3d957d8ebc1906aad20608676abf","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"c88aa87bf3052fe0993b79ff047339fac4557ead85973f4a37bf236fba401222","src/command/bundle.rs":"27eb1565c32f5486dd9dc87e0ba63e3fd9f3211e6e4a66a998071e0171a28fdf","src/command/clear.rs":"388a5dd1c7dfcf82053e61c74c52228346261191c9061c17f52285ec2fa51443","src/command/compute.rs":"5680142897313eacb4becc6f0c3cddc29dfc3ef7f6e3d5084c8ef6d5adf78230","src/command/compute_command.rs":"18aa0b8e389a5d345243b876b1abbacfc998a19d23069e092183fa7be10fa0ab","src/command/draw.rs":"97e61b057fdea79d68490604aadf7ccfa24381712405f21aba09d6ddc0f03f24","src/command/memory_init.rs":"2a7a8c27c48c2e4f4d40d09784d06d1cd22ea8793e71dbafb369efa430a05417","src/command/mod.rs":"01e1998b74e9a590235ea57f8249f96aa9b6cd7226069e46ed79e1db132b165e","src/command/pass.rs":"23f17526798dff6e352359e166c6734e34c16c0087f60a9c1c9951d2442fb4cc","src/command/query.rs":"8e88b65266169430c8a8e0b9ea39c5b36b161c8c6dccb6b574e4056a2e6d004e","src/command/ray_tracing.rs":"ad2581fbb13ab487b8a82bf875c31a1af7b3ef000e3b3b4b9f8dd528d5b29caa","src/command/render.rs":"7e439909996382b3539a8653c726ac405ea503b3436114b893139cb21c53c130","src/command/render_command.rs":"e6eaabb59d04c2c0c46e2f008d20eb01ff1a59e0d25abd6240ac49a23f8ce30a","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"775941b4ddc25834fa8f27b41b3974d9e8a647bb099078812128153a90ef1a02","src/command/transition_resources.rs":"b591797bb75f937bce6d5bffc60b54bbcdb78111ea8d140f4a8c17d80958f226","src/conv.rs":"02722149d21bcdba6ee5101b3c0625a9de8ef607523a0eebb1f4088e82b3608b","src/device/bgl.rs":"fcb1d53b692970912781748379df675268981c97352872abf2e7bb0b1ebdd533","src/device/global.rs":"373d802bc24f28807dc171454c1729fa1fd0dbfb1f09044469e70bf9c7aac80b","src/device/life.rs":"c14c34512f24a511febbe4f3ef092e2c8ad43e5bdd5c29b7e965b19827b80b52","src/device/mod.rs":"3007e78178ba5b5b9b40ec75799c1576347789235b7ce68943b1ea869395e77d","src/device/queue.rs":"2caec9f5fe7db12bd9ab9047ebfd216a7c57ab83833e21071c8914c7bb385583","src/device/ray_tracing.rs":"237fc05b6258c102037a0ec13942727375f088bfdbde078e7360bfa49e44a041","src/device/resource.rs":"ad8f58dacfd22aeeb33604800a431bce7c2d1f0666f582ca487c62c01c7e67ad","src/device/trace.rs":"48316a9360ba795ce024f4e93fb1751ca0fa4210a93c6255ebc9a6d9a0f15e72","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"7bb7dc795d01607fd5d6f4477b55255c71fe4b1f8621a004b0a4305d6641fc20","src/hal_api.rs":"7962c119456602e9c2ba958712660532290cabe0b8c4c67ef7595de73cdf8b57","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"ce0a14d5a3314df318bbc7c4d8c40ea2b3197dbddb2227e828ceb5127db7d37d","src/id.rs":"207f262558388147b484c51cf07d2554c26a3e19243058939e63a7f8e5c7ea75","src/identity.rs":"0a92302fc5b483ea1a8750b1672971af1cf2abfd4c0325bb02488b43e85073e2","src/indirect_validation/dispatch.rs":"8530817d6a062158c6426b51a1a6fb7da945b41c71c41e9a72ad832fad70c2ae","src/indirect_validation/draw.rs":"83a89798f7511e1ecfa3d489c2ba9ec558da9d2ac96bbf2717ebc5c4084f14d6","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":"3895c4a2284631b6d6247c0d96c5fc9cfd024d358e09cad8752b2505700138a3","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"80d8ab62ebad5c7093c1afa3345b09e480fa0e2d7ad0170a8f3b782d359f8e90","src/lib.rs":"578fce1910bf5a305baac6df171c94119ee71bf0b311d09478411fc27bfd0010","src/lock/mod.rs":"8d3ae3f8d004d7f7d8a3aefe9f30b35669cb8e2409f5fba27b1fcb116b2429c4","src/lock/observing.rs":"154134e93283a39327155b83fe7bf63df3c0f5cd9bbc0641081a4a5cf27851b5","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"82809ea117b802bbb6f9ce2afebb5b0ab193c5a96491e881c55d4082f2681c61","src/lock/vanilla.rs":"a2907c56c847cb37cc0d38a7790c3849f4d81034d0f85162195805be60398eae","src/pipeline.rs":"2abb5aacdb603a1fdba247db47c55c55d57c174d22b5f8b82a0bc29e17ad1ad6","src/pipeline_cache.rs":"256bf8df58d8ab904afddc132349d03e4f659b6bd6882bc8df582dcfd05ae3d5","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"d0ab0b3ab29f3e49828a595ed432f0281bf569b5eafb0bb996f49bcfab86d2c0","src/ray_tracing.rs":"6e33799815e98d0dc7e98902e6b9c9c928bc50aaab27f343379989a13cc728f9","src/registry.rs":"779d8c277193537edd2b883b72cdcc07161b7231c8d2c80be726bd800cd327b6","src/resource.rs":"800112a9a711eb6b57b29f5a54bfa41769561a1e69f103b3541200a852421317","src/scratch.rs":"05f2032fa6d6f589c2507f4028755769b9524029e5ad59cc500cab7940e40d42","src/snatch.rs":"a0de237e327c9b30e4729440784c9e44b0725715d881b9762594dc3f8e61e32d","src/storage.rs":"8a4d20e85c3ac135316dcb0dab41ec4d335d86d34959d4392ec07f592125f0d3","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"037b0ea1573065cef19d290a692d0cc7546e16c84b3a7cf4b510a4a7e02b2db4","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"1ab5310367606fc74f0791733ea5ba2e09acc92ff7f4f4773f66bcfb3138c52f","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"57a2aeda7ed8dc25f3fa13d70f1fb66b123f0e59c29a89c7529d573e3501f5b5","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"754c54f3051c8c780f3904c8c9213fc91ea1838ee14301731dd069a98c8c6695","src/validation.rs":"256f8ff5e579af4f1319997a2ca9e110f806ecf0d9b5534a2c5b4bd4f0c10776","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null}
\ No newline at end of file
--- a/third_party/rust/wgpu-core/Cargo.toml
+++ b/third_party/rust/wgpu-core/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.82.0"
 name = "wgpu-core"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = "build.rs"
 autolib = false
 autobins = false
 autoexamples = false
 autotests = false
 autobenches = false
 description = "Core implementation logic of wgpu, the cross-platform, safe, pure-rust graphics API"
@@ -144,29 +144,29 @@ default-features = false
 [dependencies.indexmap]
 version = "2.7"
 default-features = false
 
 [dependencies.log]
 version = "0.4.21"
 
 [dependencies.naga]
-version = "25.0.0"
+version = "26.0.0"
 path = "../naga"
 
 [dependencies.once_cell]
 version = "1.21"
 features = ["std"]
 default-features = false
 
 [dependencies.parking_lot]
 version = "0.12.3"
 
 [dependencies.profiling]
-version = "1"
+version = "1.0.1"
 default-features = false
 
 [dependencies.raw-window-handle]
 version = "0.6.2"
 optional = true
 default-features = false
 
 [dependencies.ron]
@@ -189,47 +189,47 @@ default-features = false
 [dependencies.smallvec]
 version = "1.9"
 
 [dependencies.thiserror]
 version = "2.0.3"
 default-features = false
 
 [dependencies.wgpu-hal]
-version = "25.0.0"
+version = "26.0.0"
 path = "../wgpu-hal"
 
 [dependencies.wgpu-types]
-version = "25.0.0"
+version = "26.0.0"
 path = "../wgpu-types"
 default-features = false
 
 [build-dependencies.cfg_aliases]
 version = "0.2.1"
 
 [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies.wgpu-core-deps-wasm]
-version = "25.0.0"
+version = "26.0.0"
 path = "platform-deps/wasm"
 optional = true
 
 [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies.wgpu-core-deps-windows-linux-android]
-version = "25.0.0"
+version = "26.0.0"
 path = "platform-deps/windows-linux-android"
 optional = true
 
 [target.'cfg(not(target_has_atomic = "64"))'.dependencies.portable-atomic]
 version = "1.8"
 optional = true
 
 [target.'cfg(target_os = "emscripten")'.dependencies.wgpu-core-deps-emscripten]
-version = "25.0.0"
+version = "26.0.0"
 path = "platform-deps/emscripten"
 optional = true
 
 [target.'cfg(target_vendor = "apple")'.dependencies.wgpu-core-deps-apple]
-version = "25.0.0"
+version = "26.0.0"
 path = "platform-deps/apple"
 optional = true
 
 [lints.rust.unexpected_cfgs]
 level = "warn"
 priority = 0
 check-cfg = ["cfg(wgpu_validate_locks)"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/wgpu-core/src/as_hal.rs
@@ -0,0 +1,408 @@
+use core::{mem::ManuallyDrop, ops::Deref};
+
+use alloc::sync::Arc;
+use hal::DynResource;
+
+use crate::{
+    device::Device,
+    global::Global,
+    hal_api::HalApi,
+    id::{
+        AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
+        TextureViewId, TlasId,
+    },
+    lock::{RankData, RwLockReadGuard},
+    resource::RawResourceAccess,
+    snatch::SnatchGuard,
+};
+
+/// A guard which holds alive a wgpu-core resource and dereferences to the Hal type.
+struct SimpleResourceGuard<Resource, HalType> {
+    _guard: Resource,
+    ptr: *const HalType,
+}
+
+impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> {
+    /// Creates a new guard from a resource, using a callback to derive the Hal type.
+    pub fn new<C>(guard: Resource, callback: C) -> Option<Self>
+    where
+        C: Fn(&Resource) -> Option<&HalType>,
+    {
+        // Derive the hal type from the resource and coerce it to a pointer.
+        let ptr: *const HalType = callback(&guard)?;
+
+        Some(Self { _guard: guard, ptr })
+    }
+}
+
+impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> {
+    type Target = HalType;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The pointer is guaranteed to be valid as the original resource is
+        // still alive and this guard cannot be used with snatchable resources.
+        unsafe { &*self.ptr }
+    }
+}
+
+unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType>
+where
+    Resource: Send,
+    HalType: Send,
+{
+}
+unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType>
+where
+    Resource: Sync,
+    HalType: Sync,
+{
+}
+
+/// A guard which holds alive a snatchable wgpu-core resource and dereferences to the Hal type.
+struct SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess,
+{
+    resource: Arc<Resource>,
+    snatch_lock_rank_data: ManuallyDrop<RankData>,
+    ptr: *const HalType,
+}
+
+impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess,
+    HalType: 'static,
+{
+    /// Creates a new guard from a snatchable resource.
+    ///
+    /// Returns `None` if:
+    /// - The resource is not of the expected Hal type.
+    /// - The resource has been destroyed.
+    pub fn new(resource: Arc<Resource>) -> Option<Self> {
+        // Grab the snatchable lock.
+        let snatch_guard = resource.device().snatchable_lock.read();
+
+        // Get the raw resource and downcast it to the expected Hal type.
+        let underlying = resource
+            .raw(&snatch_guard)?
+            .as_any()
+            .downcast_ref::<HalType>()?;
+
+        // Cast the raw resource to a pointer to get rid of the lifetime
+        // connecting us to the snatch guard.
+        let ptr: *const HalType = underlying;
+
+        // SAFETY: At this point all panicking or divergance has already happened,
+        // so we can safely forget the snatch guard without causing the lock to be left open.
+        let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard);
+
+        // SAFETY: We only construct this guard while the snatchable lock is held,
+        // as the `drop` implementation of this guard will unsafely release the lock.
+        Some(Self {
+            resource,
+            snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data),
+            ptr,
+        })
+    }
+}
+
+impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess,
+{
+    type Target = HalType;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The pointer is guaranteed to be valid as the original resource is
+        // still alive and the snatchable lock is still being held due to the forgotten
+        // snatch guard.
+        unsafe { &*self.ptr }
+    }
+}
+
+impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess,
+{
+    fn drop(&mut self) {
+        // SAFETY:
+        // - We are not going to access the rank data anymore.
+        let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) };
+
+        // SAFETY:
+        // - The pointer is no longer going to be accessed.
+        // - The snatchable lock is being held because this type was not created
+        //   until after the snatchable lock was forgotten.
+        unsafe {
+            self.resource
+                .device()
+                .snatchable_lock
+                .force_unlock_read(data)
+        };
+    }
+}
+
+unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess + Send,
+    HalType: Send,
+{
+}
+unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType>
+where
+    Resource: RawResourceAccess + Sync,
+    HalType: Sync,
+{
+}
+
+/// A guard which holds alive a device and the device's fence lock, dereferencing to the Hal type.
+struct FenceGuard<Fence> {
+    device: Arc<Device>,
+    fence_lock_rank_data: ManuallyDrop<RankData>,
+    ptr: *const Fence,
+}
+
+impl<Fence> FenceGuard<Fence>
+where
+    Fence: 'static,
+{
+    /// Creates a new guard over a device's fence.
+    ///
+    /// Returns `None` if:
+    /// - The device's fence is not of the expected Hal type.
+    pub fn new(device: Arc<Device>) -> Option<Self> {
+        // Grab the fence lock.
+        let fence_guard = device.fence.read();
+
+        // Get the raw fence and downcast it to the expected Hal type, coercing it to a pointer
+        // to get rid of the lifetime connecting us to the fence guard.
+        let ptr: *const Fence = fence_guard.as_any().downcast_ref::<Fence>()?;
+
+        // SAFETY: At this point all panicking or divergance has already happened,
+        // so we can safely forget the fence guard without causing the lock to be left open.
+        let fence_lock_rank_data = RwLockReadGuard::forget(fence_guard);
+
+        // SAFETY: We only construct this guard while the fence lock is held,
+        // as the `drop` implementation of this guard will unsafely release the lock.
+        Some(Self {
+            device,
+            fence_lock_rank_data: ManuallyDrop::new(fence_lock_rank_data),
+            ptr,
+        })
+    }
+}
+
+impl<Fence> Deref for FenceGuard<Fence> {
+    type Target = Fence;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The pointer is guaranteed to be valid as the original device's fence
+        // is still alive and the fence lock is still being held due to the forgotten
+        // fence guard.
+        unsafe { &*self.ptr }
+    }
+}
+
+impl<Fence> Drop for FenceGuard<Fence> {
+    fn drop(&mut self) {
+        // SAFETY:
+        // - We are not going to access the rank data anymore.
+        let data = unsafe { ManuallyDrop::take(&mut self.fence_lock_rank_data) };
+
+        // SAFETY:
+        // - The pointer is no longer going to be accessed.
+        // - The fence lock is being held because this type was not created
+        //   until after the fence lock was forgotten.
+        unsafe {
+            self.device.fence.force_unlock_read(data);
+        };
+    }
+}
+
+unsafe impl<Fence> Send for FenceGuard<Fence> where Fence: Send {}
+unsafe impl<Fence> Sync for FenceGuard<Fence> where Fence: Sync {}
+
+impl Global {
+    /// # Safety
+    ///
+    /// - The raw buffer handle must not be manually destroyed
+    pub unsafe fn buffer_as_hal<A: HalApi>(
+        &self,
+        id: BufferId,
+    ) -> Option<impl Deref<Target = A::Buffer>> {
+        profiling::scope!("Buffer::as_hal");
+
+        let hub = &self.hub;
+
+        let buffer = hub.buffers.get(id).get().ok()?;
+
+        SnatchableResourceGuard::new(buffer)
+    }
+
+    /// # Safety
+    ///
+    /// - The raw texture handle must not be manually destroyed
+    pub unsafe fn texture_as_hal<A: HalApi>(
+        &self,
+        id: TextureId,
+    ) -> Option<impl Deref<Target = A::Texture>> {
+        profiling::scope!("Texture::as_hal");
+
+        let hub = &self.hub;
+
+        let texture = hub.textures.get(id).get().ok()?;
+
+        SnatchableResourceGuard::new(texture)
+    }
+
+    /// # Safety
+    ///
+    /// - The raw texture view handle must not be manually destroyed
+    pub unsafe fn texture_view_as_hal<A: HalApi>(
+        &self,
+        id: TextureViewId,
+    ) -> Option<impl Deref<Target = A::TextureView>> {
+        profiling::scope!("TextureView::as_hal");
+
+        let hub = &self.hub;
+
+        let view = hub.texture_views.get(id).get().ok()?;
+
+        SnatchableResourceGuard::new(view)
+    }
+
+    /// # Safety
+    ///
+    /// - The raw adapter handle must not be manually destroyed
+    pub unsafe fn adapter_as_hal<A: HalApi>(
+        &self,
+        id: AdapterId,
+    ) -> Option<impl Deref<Target = A::Adapter>> {
+        profiling::scope!("Adapter::as_hal");
+
+        let hub = &self.hub;
+        let adapter = hub.adapters.get(id);
+
+        SimpleResourceGuard::new(adapter, move |adapter| {
+            adapter.raw.adapter.as_any().downcast_ref()
+        })
+    }
+
+    /// # Safety
+    ///
+    /// - The raw device handle must not be manually destroyed
+    pub unsafe fn device_as_hal<A: HalApi>(
+        &self,
+        id: DeviceId,
+    ) -> Option<impl Deref<Target = A::Device>> {
+        profiling::scope!("Device::as_hal");
+
+        let device = self.hub.devices.get(id);
+
+        SimpleResourceGuard::new(device, move |device| device.raw().as_any().downcast_ref())
+    }
+
+    /// # Safety
+    ///
+    /// - The raw fence handle must not be manually destroyed
+    pub unsafe fn device_fence_as_hal<A: HalApi>(
+        &self,
+        id: DeviceId,
+    ) -> Option<impl Deref<Target = A::Fence>> {
+        profiling::scope!("Device::fence_as_hal");
+
+        let device = self.hub.devices.get(id);
+
+        FenceGuard::new(device)
+    }
+
+    /// # Safety
+    /// - The raw surface handle must not be manually destroyed
+    pub unsafe fn surface_as_hal<A: HalApi>(
+        &self,
+        id: SurfaceId,
+    ) -> Option<impl Deref<Target = A::Surface>> {
+        profiling::scope!("Surface::as_hal");
+
+        let surface = self.surfaces.get(id);
+
+        SimpleResourceGuard::new(surface, move |surface| {
+            surface.raw(A::VARIANT)?.as_any().downcast_ref()
+        })
+    }
+
+    /// # Safety
+    ///
+    /// - The raw command encoder handle must not be manually destroyed
+    pub unsafe fn command_encoder_as_hal_mut<
+        A: HalApi,
+        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
+        R,
+    >(
+        &self,
+        id: CommandEncoderId,
+        hal_command_encoder_callback: F,
+    ) -> R {
+        profiling::scope!("CommandEncoder::as_hal");
+
+        let hub = &self.hub;
+
+        let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
+        let mut cmd_buf_data = cmd_buf.data.lock();
+        cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
+            hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
+                cmd_buf
+                    .encoder
+                    .open()
+                    .ok()
+                    .and_then(|encoder| encoder.as_any_mut().downcast_mut())
+            }))
+        })
+    }
+
+    /// # Safety
+    ///
+    /// - The raw queue handle must not be manually destroyed
+    pub unsafe fn queue_as_hal<A: HalApi>(
+        &self,
+        id: QueueId,
+    ) -> Option<impl Deref<Target = A::Queue>> {
+        profiling::scope!("Queue::as_hal");
+
+        let queue = self.hub.queues.get(id);
+
+        SimpleResourceGuard::new(queue, move |queue| queue.raw().as_any().downcast_ref())
+    }
+
+    /// # Safety
+    ///
+    /// - The raw blas handle must not be manually destroyed
+    pub unsafe fn blas_as_hal<A: HalApi>(
+        &self,
+        id: BlasId,
+    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
+        profiling::scope!("Blas::as_hal");
+
+        let hub = &self.hub;
+
+        let blas = hub.blas_s.get(id).get().ok()?;
+
+        SnatchableResourceGuard::new(blas)
+    }
+
+    /// # Safety
+    ///
+    /// - The raw tlas handle must not be manually destroyed
+    pub unsafe fn tlas_as_hal<A: HalApi>(
+        &self,
+        id: TlasId,
+    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
+        profiling::scope!("Tlas::as_hal");
+
+        let hub = &self.hub;
+
+        let tlas = hub.tlas_s.get(id).get().ok()?;
+
+        SnatchableResourceGuard::new(tlas)
+    }
+}
--- a/third_party/rust/wgpu-core/src/binding_model.rs
+++ b/third_party/rust/wgpu-core/src/binding_model.rs
@@ -21,17 +21,18 @@ use crate::{
     device::{
         bgl, Device, DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT,
     },
     id::{BindGroupLayoutId, BufferId, SamplerId, TextureViewId, TlasId},
     init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction},
     pipeline::{ComputePipeline, RenderPipeline},
     resource::{
         Buffer, DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError,
-        MissingTextureUsageError, ResourceErrorIdent, Sampler, TextureView, Tlas, TrackingData,
+        MissingTextureUsageError, RawResourceAccess, ResourceErrorIdent, Sampler, TextureView,
+        Tlas, TrackingData,
     },
     resource_log,
     snatch::{SnatchGuard, Snatchable},
     track::{BindGroupStates, ResourceUsageCompatibilityError},
     Label,
 };
 
 #[derive(Clone, Debug, Error)]
@@ -89,41 +90,68 @@ impl WebGpuError for CreateBindGroupLayo
             | Self::InvalidBindingIndex { .. }
             | Self::InvalidVisibility(_)
             | Self::ContainsBothBindingArrayAndDynamicOffsetArray
             | Self::ContainsBothBindingArrayAndUniformBuffer => ErrorType::Validation,
         }
     }
 }
 
-//TODO: refactor this to move out `enum BindingError`.
+#[derive(Clone, Debug, Error)]
+#[non_exhaustive]
+pub enum BindingError {
+    #[error(transparent)]
+    DestroyedResource(#[from] DestroyedResourceError),
+    #[error("Buffer {buffer}: Binding with size {binding_size} at offset {offset} would overflow buffer size of {buffer_size}")]
+    BindingRangeTooLarge {
+        buffer: ResourceErrorIdent,
+        offset: wgt::BufferAddress,
+        binding_size: u64,
+        buffer_size: u64,
+    },
+    #[error("Buffer {buffer}: Binding offset {offset} is greater than buffer size {buffer_size}")]
+    BindingOffsetTooLarge {
+        buffer: ResourceErrorIdent,
+        offset: wgt::BufferAddress,
+        buffer_size: u64,
+    },
+}
 
+impl WebGpuError for BindingError {
+    fn webgpu_error_type(&self) -> ErrorType {
+        match self {
+            Self::DestroyedResource(e) => e.webgpu_error_type(),
+            Self::BindingRangeTooLarge { .. } | Self::BindingOffsetTooLarge { .. } => {
+                ErrorType::Validation
+            }
+        }
+    }
+}
+
+// TODO: there may be additional variants here that can be extracted into
+// `BindingError`.
 #[derive(Clone, Debug, Error)]
 #[non_exhaustive]
 pub enum CreateBindGroupError {
     #[error(transparent)]
     Device(#[from] DeviceError),
     #[error(transparent)]
     DestroyedResource(#[from] DestroyedResourceError),
+    #[error(transparent)]
+    BindingError(#[from] BindingError),
     #[error(
         "Binding count declared with at most {expected} items, but {actual} items were provided"
     )]
     BindingArrayPartialLengthMismatch { actual: usize, expected: usize },
     #[error(
         "Binding count declared with exactly {expected} items, but {actual} items were provided"
     )]
     BindingArrayLengthMismatch { actual: usize, expected: usize },
     #[error("Array binding provided zero elements")]
     BindingArrayZeroLength,
-    #[error("The bound range {range:?} of {buffer} overflows its size ({size})")]
-    BindingRangeTooLarge {
-        buffer: ResourceErrorIdent,
-        range: Range<wgt::BufferAddress>,
-        size: u64,
-    },
     #[error("Binding size {actual} of {buffer} is less than minimum {min}")]
     BindingSizeTooSmall {
         buffer: ResourceErrorIdent,
         actual: u64,
         min: u64,
     },
     #[error("{0} binding size is zero")]
     BindingZeroSize(ResourceErrorIdent),
@@ -228,24 +256,24 @@ pub enum CreateBindGroupError {
     InvalidResource(#[from] InvalidResourceError),
 }
 
 impl WebGpuError for CreateBindGroupError {
     fn webgpu_error_type(&self) -> ErrorType {
         let e: &dyn WebGpuError = match self {
             Self::Device(e) => e,
             Self::DestroyedResource(e) => e,
+            Self::BindingError(e) => e,
             Self::MissingBufferUsage(e) => e,
             Self::MissingTextureUsage(e) => e,
             Self::ResourceUsageCompatibility(e) => e,
             Self::InvalidResource(e) => e,
             Self::BindingArrayPartialLengthMismatch { .. }
             | Self::BindingArrayLengthMismatch { .. }
             | Self::BindingArrayZeroLength
-            | Self::BindingRangeTooLarge { .. }
             | Self::BindingSizeTooSmall { .. }
             | Self::BindingsNumMismatch { .. }
             | Self::BindingZeroSize(_)
             | Self::DuplicateBinding(_)
             | Self::MissingBindingDeclaration(_)
             | Self::SingleBindingExpected
             | Self::UnalignedBufferOffset(_, _, _)
             | Self::BufferRangeTooLarge { .. }
--- a/third_party/rust/wgpu-core/src/command/bundle.rs
+++ b/third_party/rust/wgpu-core/src/command/bundle.rs
@@ -88,16 +88,17 @@ use core::{
     convert::Infallible,
     num::{NonZeroU32, NonZeroU64},
     ops::Range,
 };
 
 use arrayvec::ArrayVec;
 use thiserror::Error;
 
+use wgpu_hal::ShouldBeNonZeroExt;
 use wgt::error::{ErrorType, WebGpuError};
 
 use crate::{
     binding_model::{BindError, BindGroup, PipelineLayout},
     command::{
         BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr,
         PassErrorScope, RenderCommandError, StateChange,
     },
@@ -106,17 +107,17 @@ use crate::{
         SHADER_STAGE_COUNT,
     },
     hub::Hub,
     id,
     init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction},
     pipeline::{PipelineFlags, RenderPipeline, VertexStep},
     resource::{
         Buffer, DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice,
-        TrackingData,
+        RawResourceAccess, TrackingData,
     },
     resource_log,
     snatch::SnatchGuard,
     track::RenderBundleScope,
     Label, LabelHelpers,
 };
 
 use super::{
@@ -597,16 +598,17 @@ fn set_pipeline(
 
     state.invalidate_bind_groups(&pipeline_state, &pipeline.layout);
     state.pipeline = Some(pipeline_state);
 
     state.trackers.render_pipelines.insert_single(pipeline);
     Ok(())
 }
 
+// This function is duplicative of `render::set_index_buffer`.
 fn set_index_buffer(
     state: &mut State,
     buffer_guard: &crate::storage::Storage<Fallible<Buffer>>,
     buffer_id: id::Id<id::markers::Buffer>,
     index_format: wgt::IndexFormat,
     offset: u64,
     size: Option<NonZeroU64>,
 ) -> Result<(), RenderBundleErrorInner> {
@@ -615,31 +617,30 @@ fn set_index_buffer(
     state
         .trackers
         .buffers
         .merge_single(&buffer, wgt::BufferUses::INDEX)?;
 
     buffer.same_device(&state.device)?;
     buffer.check_usage(wgt::BufferUsages::INDEX)?;
 
-    let end = match size {
-        Some(s) => offset + s.get(),
-        None => buffer.size,
-    };
+    let end = offset + buffer.resolve_binding_size(offset, size)?;
+
     state
         .buffer_memory_init_actions
         .extend(buffer.initialization_status.read().create_action(
             &buffer,
-            offset..end,
+            offset..end.get(),
             MemoryInitKind::NeedsInitializedMemory,
         ));
-    state.set_index_buffer(buffer, index_format, offset..end);
+    state.set_index_buffer(buffer, index_format, offset..end.get());
     Ok(())
 }
 
+// This function is duplicative of `render::set_vertex_buffer`.
 fn set_vertex_buffer(
     state: &mut State,
     buffer_guard: &crate::storage::Storage<Fallible<Buffer>>,
     slot: u32,
     buffer_id: id::Id<id::markers::Buffer>,
     offset: u64,
     size: Option<NonZeroU64>,
 ) -> Result<(), RenderBundleErrorInner> {
@@ -657,28 +658,26 @@ fn set_vertex_buffer(
     state
         .trackers
         .buffers
         .merge_single(&buffer, wgt::BufferUses::VERTEX)?;
 
     buffer.same_device(&state.device)?;
     buffer.check_usage(wgt::BufferUsages::VERTEX)?;
 
-    let end = match size {
-        Some(s) => offset + s.get(),
-        None => buffer.size,
-    };
+    let end = offset + buffer.resolve_binding_size(offset, size)?;
+
     state
         .buffer_memory_init_actions
         .extend(buffer.initialization_status.read().create_action(
             &buffer,
-            offset..end,
+            offset..end.get(),
             MemoryInitKind::NeedsInitializedMemory,
         ));
-    state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end));
+    state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end.get()));
     Ok(())
 }
 
 fn set_push_constant(
     state: &mut State,
     stages: wgt::ShaderStages,
     offset: u32,
     size_bytes: u32,
@@ -960,35 +959,31 @@ impl RenderBundle {
                 }
                 Cmd::SetIndexBuffer {
                     buffer,
                     index_format,
                     offset,
                     size,
                 } => {
                     let buffer = buffer.try_raw(snatch_guard)?;
-                    let bb = hal::BufferBinding {
-                        buffer,
-                        offset: *offset,
-                        size: *size,
-                    };
+                    // SAFETY: The binding size was checked against the buffer size
+                    // in `set_index_buffer` and again in `IndexState::flush`.
+                    let bb = hal::BufferBinding::new_unchecked(buffer, *offset, *size);
                     unsafe { raw.set_index_buffer(bb, *index_format) };
                 }
                 Cmd::SetVertexBuffer {
                     slot,
                     buffer,
                     offset,
                     size,
                 } => {
                     let buffer = buffer.try_raw(snatch_guard)?;
-                    let bb = hal::BufferBinding {
-                        buffer,
-                        offset: *offset,
-                        size: *size,
-                    };
+                    // SAFETY: The binding size was checked against the buffer size
+                    // in `set_vertex_buffer` and again in `VertexState::flush`.
+                    let bb = hal::BufferBinding::new_unchecked(buffer, *offset, *size);
                     unsafe { raw.set_vertex_buffer(*slot, bb) };
                 }
                 Cmd::SetPushConstant {
                     stages,
                     offset,
                     size_bytes,
                     values_offset,
                 } => {
@@ -1126,16 +1121,19 @@ crate::impl_parent_device!(RenderBundle)
 crate::impl_storage_item!(RenderBundle);
 crate::impl_trackable!(RenderBundle);
 
 /// A render bundle's current index buffer state.
 ///
 /// [`RenderBundleEncoder::finish`] records the currently set index buffer here,
 /// and calls [`State::flush_index`] before any indexed draw command to produce
 /// a `SetIndexBuffer` command if one is necessary.
+///
+/// Binding ranges must be validated against the size of the buffer before
+/// being stored in `IndexState`.
 #[derive(Debug)]
 struct IndexState {
     buffer: Arc<Buffer>,
     format: wgt::IndexFormat,
     range: Range<wgt::BufferAddress>,
     is_dirty: bool,
 }
 
@@ -1147,66 +1145,87 @@ impl IndexState {
         let bytes_per_index = self.format.byte_size() as u64;
 
         (self.range.end - self.range.start) / bytes_per_index
     }
 
     /// Generate a `SetIndexBuffer` command to prepare for an indexed draw
     /// command, if needed.
     fn flush(&mut self) -> Option<ArcRenderCommand> {
+        // This was all checked before, but let's check again just in case.
+        let binding_size = self
+            .range
+            .end
+            .checked_sub(self.range.start)
+            .filter(|_| self.range.end <= self.buffer.size)
+            .expect("index range must be contained in buffer");
+
         if self.is_dirty {
             self.is_dirty = false;
             Some(ArcRenderCommand::SetIndexBuffer {
                 buffer: self.buffer.clone(),
                 index_format: self.format,
                 offset: self.range.start,
-                size: wgt::BufferSize::new(self.range.end - self.range.start),
+                size: NonZeroU64::new(binding_size),
             })
         } else {
             None
         }
     }
 }
 
 /// The state of a single vertex buffer slot during render bundle encoding.
 ///
 /// [`RenderBundleEncoder::finish`] uses this to drop redundant
 /// `SetVertexBuffer` commands from the final [`RenderBundle`]. It
 /// records one vertex buffer slot's state changes here, and then
 /// calls this type's [`flush`] method just before any draw command to
 /// produce a `SetVertexBuffer` commands if one is necessary.
 ///
+/// Binding ranges must be validated against the size of the buffer before
+/// being stored in `VertexState`.
+///
 /// [`flush`]: IndexState::flush
 #[derive(Debug)]
 struct VertexState {
     buffer: Arc<Buffer>,
     range: Range<wgt::BufferAddress>,
     is_dirty: bool,
 }
 
 impl VertexState {
+    /// Create a new `VertexState`.
+    ///
+    /// The `range` must be contained within `buffer`.
     fn new(buffer: Arc<Buffer>, range: Range<wgt::BufferAddress>) -> Self {
         Self {
             buffer,
             range,
             is_dirty: true,
         }
     }
 
     /// Generate a `SetVertexBuffer` command for this slot, if necessary.
     ///
     /// `slot` is the index of the vertex buffer slot that `self` tracks.
     fn flush(&mut self, slot: u32) -> Option<ArcRenderCommand> {
+        let binding_size = self
+            .range
+            .end
+            .checked_sub(self.range.start)
+            .filter(|_| self.range.end <= self.buffer.size)
+            .expect("vertex range must be contained in buffer");
+
         if self.is_dirty {
             self.is_dirty = false;
             Some(ArcRenderCommand::SetVertexBuffer {
                 slot,
                 buffer: self.buffer.clone(),
                 offset: self.range.start,
-                size: wgt::BufferSize::new(self.range.end - self.range.start),
+                size: NonZeroU64::new(binding_size),
             })
         } else {
             None
         }
     }
 }
 
 /// A bind group that has been set at a particular index during render bundle encoding.
--- a/third_party/rust/wgpu-core/src/command/clear.rs
+++ b/third_party/rust/wgpu-core/src/command/clear.rs
@@ -8,17 +8,17 @@ use crate::{
     command::EncoderStateError,
     device::DeviceError,
     get_lowest_common_denom,
     global::Global,
     id::{BufferId, CommandEncoderId, TextureId},
     init_tracker::{MemoryInitKind, TextureInitRange},
     resource::{
         DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError,
-        ParentDevice, ResourceErrorIdent, Texture, TextureClearMode,
+        ParentDevice, RawResourceAccess, ResourceErrorIdent, Texture, TextureClearMode,
     },
     snatch::SnatchGuard,
     track::TextureTrackerSetSingle,
 };
 
 use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
--- a/third_party/rust/wgpu-core/src/command/compute.rs
+++ b/third_party/rust/wgpu-core/src/command/compute.rs
@@ -2,19 +2,19 @@ use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
     BufferAddress, DynamicOffset,
 };
 
 use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
 use core::{fmt, str};
 
-use crate::binding_model::BindError;
 use crate::command::{pass, EncoderStateError, PassStateError, TimestampWritesError};
 use crate::resource::DestroyedResourceError;
+use crate::{binding_model::BindError, resource::RawResourceAccess};
 use crate::{
     binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError},
     command::{
         bind::{Binder, BinderError},
         compute_command::ArcComputeCommand,
         end_pipeline_statistics_query,
         memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
         pass_base, pass_try, validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites,
@@ -487,17 +487,17 @@ impl Global {
 
         self.compute_pass_end(&mut compute_pass).unwrap();
     }
 
     pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), EncoderStateError> {
         let pass_scope = PassErrorScope::Pass;
         profiling::scope!(
             "CommandEncoder::run_compute_pass {}",
-            base.label.as_deref().unwrap_or("")
+            pass.base.label.as_deref().unwrap_or("")
         );
 
         let cmd_buf = pass.parent.take().ok_or(EncoderStateError::Ended)?;
         let mut cmd_buf_data = cmd_buf.data.lock();
 
         if let Some(err) = pass.base.error.take() {
             if matches!(
                 err,
--- a/third_party/rust/wgpu-core/src/command/draw.rs
+++ b/third_party/rust/wgpu-core/src/command/draw.rs
@@ -2,17 +2,17 @@ use alloc::boxed::Box;
 
 use thiserror::Error;
 
 use wgt::error::{ErrorType, WebGpuError};
 
 use super::bind::BinderError;
 use crate::command::pass;
 use crate::{
-    binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError},
+    binding_model::{BindingError, LateMinBufferBindingSizeMismatch, PushConstantUploadError},
     resource::{
         DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError,
         ResourceErrorIdent,
     },
     track::ResourceUsageCompatibilityError,
 };
 
 /// Error validating a draw call.
@@ -84,16 +84,18 @@ pub enum RenderCommandError {
     #[error(transparent)]
     DestroyedResource(#[from] DestroyedResourceError),
     #[error(transparent)]
     MissingBufferUsage(#[from] MissingBufferUsageError),
     #[error(transparent)]
     MissingTextureUsage(#[from] MissingTextureUsageError),
     #[error(transparent)]
     PushConstants(#[from] PushConstantUploadError),
+    #[error(transparent)]
+    BindingError(#[from] BindingError),
     #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")]
     InvalidViewportRectSize { w: f32, h: f32, max: u32 },
     #[error("Viewport has invalid rect {rect:?} for device's requested `max_texture_dimension_2d` limit; Origin less than -2 * `max_texture_dimension_2d` ({min}), or rect extends past 2 * `max_texture_dimension_2d` - 1 ({max})")]
     InvalidViewportRectPosition { rect: Rect<f32>, min: f32, max: f32 },
     #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
     InvalidViewportDepth(f32, f32),
     #[error("Scissor {0:?} is not contained in the render target {1:?}")]
     InvalidScissorRect(Rect<u32>, wgt::Extent3d),
@@ -105,16 +107,17 @@ impl WebGpuError for RenderCommandError 
     fn webgpu_error_type(&self) -> ErrorType {
         let e: &dyn WebGpuError = match self {
             Self::IncompatiblePipelineTargets(e) => e,
             Self::ResourceUsageCompatibility(e) => e,
             Self::DestroyedResource(e) => e,
             Self::MissingBufferUsage(e) => e,
             Self::MissingTextureUsage(e) => e,
             Self::PushConstants(e) => e,
+            Self::BindingError(e) => e,
 
             Self::BindGroupIndexOutOfRange { .. }
             | Self::VertexBufferIndexOutOfRange { .. }
             | Self::IncompatibleDepthAccess(..)
             | Self::IncompatibleStencilAccess(..)
             | Self::InvalidViewportRectSize { .. }
             | Self::InvalidViewportRectPosition { .. }
             | Self::InvalidViewportDepth(..)
--- a/third_party/rust/wgpu-core/src/command/memory_init.rs
+++ b/third_party/rust/wgpu-core/src/command/memory_init.rs
@@ -4,17 +4,17 @@ use alloc::{
 };
 use core::ops::Range;
 
 use hashbrown::hash_map::Entry;
 
 use crate::{
     device::Device,
     init_tracker::*,
-    resource::{DestroyedResourceError, ParentDevice, Texture, Trackable},
+    resource::{DestroyedResourceError, ParentDevice, RawResourceAccess, Texture, Trackable},
     snatch::SnatchGuard,
     track::{DeviceTracker, TextureTracker},
     FastHashMap,
 };
 
 use super::{clear::clear_texture, BakedCommands, ClearError};
 
 /// Surface that was discarded by `StoreOp::Discard` of a preceding renderpass.
--- a/third_party/rust/wgpu-core/src/command/mod.rs
+++ b/third_party/rust/wgpu-core/src/command/mod.rs
@@ -26,16 +26,17 @@ pub use self::{
 };
 pub(crate) use allocator::CommandAllocator;
 
 pub(crate) use timestamp_writes::ArcPassTimestampWrites;
 pub use timestamp_writes::PassTimestampWrites;
 
 use self::memory_init::CommandBufferTextureMemoryActions;
 
+use crate::binding_model::BindingError;
 use crate::command::transition_resources::TransitionResourcesError;
 use crate::device::queue::TempResource;
 use crate::device::{Device, DeviceError, MissingFeatures};
 use crate::lock::{rank, Mutex};
 use crate::snatch::SnatchGuard;
 
 use crate::init_tracker::BufferInitTrackerAction;
 use crate::ray_tracing::{AsAction, BuildAccelerationStructureError};
@@ -1055,16 +1056,28 @@ impl CommandEncoderError {
                 | Self::ComputePass(ComputePassError {
                     inner: ComputePassErrorInner::DestroyedResource(_),
                     ..
                 })
                 | Self::RenderPass(RenderPassError {
                     inner: RenderPassErrorInner::DestroyedResource(_),
                     ..
                 })
+                | Self::RenderPass(RenderPassError {
+                    inner: RenderPassErrorInner::RenderCommand(
+                        RenderCommandError::DestroyedResource(_)
+                    ),
+                    ..
+                })
+                | Self::RenderPass(RenderPassError {
+                    inner: RenderPassErrorInner::RenderCommand(RenderCommandError::BindingError(
+                        BindingError::DestroyedResource(_)
+                    )),
+                    ..
+                })
         )
     }
 }
 
 impl WebGpuError for CommandEncoderError {
     fn webgpu_error_type(&self) -> ErrorType {
         let e: &dyn WebGpuError = match self {
             Self::Device(e) => e,
--- a/third_party/rust/wgpu-core/src/command/query.rs
+++ b/third_party/rust/wgpu-core/src/command/query.rs
@@ -6,17 +6,17 @@ use crate::device::trace::Command as Tra
 use crate::{
     command::{CommandBuffer, EncoderStateError},
     device::{DeviceError, MissingFeatures},
     global::Global,
     id,
     init_tracker::MemoryInitKind,
     resource::{
         DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ParentDevice,
-        QuerySet, Trackable,
+        QuerySet, RawResourceAccess, Trackable,
     },
     track::{StatelessTracker, TrackerIndex},
     FastHashMap,
 };
 use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
     BufferAddress,
--- a/third_party/rust/wgpu-core/src/command/ray_tracing.rs
+++ b/third_party/rust/wgpu-core/src/command/ray_tracing.rs
@@ -2,38 +2,36 @@ use alloc::{boxed::Box, sync::Arc, vec::
 use core::{
     cmp::max,
     num::NonZeroU64,
     ops::{Deref, Range},
 };
 
 use wgt::{math::align_to, BufferUsages, BufferUses, Features};
 
-use crate::lock::RwLockWriteGuard;
 use crate::ray_tracing::{AsAction, AsBuild, TlasBuild, ValidateAsActionsError};
 use crate::{
     command::CommandBufferMutable,
     device::queue::TempResource,
     global::Global,
     hub::Hub,
     id::CommandEncoderId,
     init_tracker::MemoryInitKind,
     ray_tracing::{
         BlasBuildEntry, BlasGeometries, BlasTriangleGeometry, BuildAccelerationStructureError,
         TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries,
         TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage,
     },
-    resource::{
-        AccelerationStructure, Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas,
-    },
+    resource::{Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas},
     scratch::ScratchBuffer,
     snatch::SnatchGuard,
     track::PendingTransition,
 };
 use crate::{command::EncoderStateError, device::resource::CommandIndices};
+use crate::{lock::RwLockWriteGuard, resource::RawResourceAccess};
 
 use crate::id::{BlasId, TlasId};
 
 struct TriangleBufferStore<'a> {
     vertex_buffer: Arc<Buffer>,
     vertex_transition: Option<PendingTransition<BufferUses>>,
     index_buffer_transition: Option<(Arc<Buffer>, Option<PendingTransition<BufferUses>>)>,
     transform_buffer_transition: Option<(Arc<Buffer>, Option<PendingTransition<BufferUses>>)>,
--- a/third_party/rust/wgpu-core/src/command/render.rs
+++ b/third_party/rust/wgpu-core/src/command/render.rs
@@ -10,16 +10,17 @@ use wgt::{
 };
 
 use crate::command::{
     pass, pass_base, pass_try, validate_and_begin_occlusion_query,
     validate_and_begin_pipeline_statistics_query, EncoderStateError, PassStateError,
     TimestampWritesError,
 };
 use crate::pipeline::{RenderPipeline, VertexStep};
+use crate::resource::RawResourceAccess;
 use crate::resource::{InvalidResourceError, ResourceErrorIdent};
 use crate::snatch::SnatchGuard;
 use crate::{
     api_log,
     command::{
         bind::Binder,
         end_occlusion_query, end_pipeline_statistics_query,
         memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
@@ -1798,17 +1799,17 @@ impl Global {
 
         self.render_pass_end(&mut render_pass).unwrap();
     }
 
     pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> {
         let pass_scope = PassErrorScope::Pass;
         profiling::scope!(
             "CommandEncoder::run_render_pass {}",
-            base.label.as_deref().unwrap_or("")
+            pass.base.label.as_deref().unwrap_or("")
         );
 
         let cmd_buf = pass.parent.take().ok_or(EncoderStateError::Ended)?;
         let mut cmd_buf_data = cmd_buf.data.lock();
 
         if let Some(err) = pass.base.error.take() {
             if matches!(
                 err,
@@ -2317,16 +2318,17 @@ fn set_pipeline(
         || {},
     )?;
 
     // Update vertex buffer limits.
     state.vertex.update_limits(&pipeline.vertex_steps);
     Ok(())
 }
 
+// This function is duplicative of `bundle::set_index_buffer`.
 fn set_index_buffer(
     state: &mut State,
     cmd_buf: &Arc<CommandBuffer>,
     buffer: Arc<crate::resource::Buffer>,
     index_format: IndexFormat,
     offset: u64,
     size: Option<BufferSize>,
 ) -> Result<(), RenderPassErrorInner> {
@@ -2336,43 +2338,38 @@ fn set_index_buffer(
         .general
         .scope
         .buffers
         .merge_single(&buffer, wgt::BufferUses::INDEX)?;
 
     buffer.same_device_as(cmd_buf.as_ref())?;
 
     buffer.check_usage(BufferUsages::INDEX)?;
-    let buf_raw = buffer.try_raw(state.general.snatch_guard)?;
-
-    let end = match size {
-        Some(s) => offset + s.get(),
-        None => buffer.size,
-    };
+
+    let (binding, resolved_size) = buffer
+        .binding(offset, size, state.general.snatch_guard)
+        .map_err(RenderCommandError::from)?;
+    let end = offset + resolved_size;
     state.index.update_buffer(offset..end, index_format);
 
     state.general.buffer_memory_init_actions.extend(
         buffer.initialization_status.read().create_action(
             &buffer,
             offset..end,
             MemoryInitKind::NeedsInitializedMemory,
         ),
     );
 
-    let bb = hal::BufferBinding {
-        buffer: buf_raw,
-        offset,
-        size,
-    };
     unsafe {
-        hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, bb, index_format);
+        hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, binding, index_format);
     }
     Ok(())
 }
 
+// This function is duplicative of `render::set_vertex_buffer`.
 fn set_vertex_buffer(
     state: &mut State,
     cmd_buf: &Arc<CommandBuffer>,
     slot: u32,
     buffer: Arc<crate::resource::Buffer>,
     offset: u64,
     size: Option<BufferSize>,
 ) -> Result<(), RenderPassErrorInner> {
@@ -2394,40 +2391,32 @@ fn set_vertex_buffer(
         return Err(RenderCommandError::VertexBufferIndexOutOfRange {
             index: slot,
             max: max_vertex_buffers,
         }
         .into());
     }
 
     buffer.check_usage(BufferUsages::VERTEX)?;
-    let buf_raw = buffer.try_raw(state.general.snatch_guard)?;
-
-    //TODO: where are we checking that the offset is in bound?
-    let buffer_size = match size {
-        Some(s) => s.get(),
-        None => buffer.size - offset,
-    };
+
+    let (binding, buffer_size) = buffer
+        .binding(offset, size, state.general.snatch_guard)
+        .map_err(RenderCommandError::from)?;
     state.vertex.buffer_sizes[slot as usize] = Some(buffer_size);
 
     state.general.buffer_memory_init_actions.extend(
         buffer.initialization_status.read().create_action(
             &buffer,
             offset..(offset + buffer_size),
             MemoryInitKind::NeedsInitializedMemory,
         ),
     );
 
-    let bb = hal::BufferBinding {
-        buffer: buf_raw,
-        offset,
-        size,
-    };
     unsafe {
-        hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, bb);
+        hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, binding);
     }
     if let Some(pipeline) = state.pipeline.as_ref() {
         state.vertex.update_limits(&pipeline.vertex_steps);
     }
     Ok(())
 }
 
 fn set_blend_constant(state: &mut State, color: &Color) {
--- a/third_party/rust/wgpu-core/src/command/render_command.rs
+++ b/third_party/rust/wgpu-core/src/command/render_command.rs
@@ -387,16 +387,27 @@ impl RenderCommand {
                     })
                 })
                 .collect::<Result<Vec<_>, RenderPassError>>()?;
         Ok(resolved_commands)
     }
 }
 
 /// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs.
+///
+/// In a render pass, commands are stored in this format between when they are
+/// added to the pass, and when the pass is `end()`ed and the commands are
+/// replayed to the HAL encoder. Validation occurs when the pass is ended, which
+/// means that parameters stored in an `ArcRenderCommand` for a pass operation
+/// have generally not been validated.
+///
+/// In a render bundle, commands are stored in this format between when the bundle
+/// 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>>,
     },
--- a/third_party/rust/wgpu-core/src/command/transfer.rs
+++ b/third_party/rust/wgpu-core/src/command/transfer.rs
@@ -1,33 +1,34 @@
 use alloc::{sync::Arc, vec::Vec};
 
 use arrayvec::ArrayVec;
 use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
-    BufferAddress, BufferUsages, Extent3d, TextureSelector, TextureUsages,
+    BufferAddress, BufferTextureCopyInfoError, BufferUsages, Extent3d, TextureSelector,
+    TextureUsages,
 };
 
 #[cfg(feature = "trace")]
 use crate::device::trace::Command as TraceCommand;
 use crate::{
     api_log,
     command::{clear_texture, CommandEncoderError, EncoderStateError},
     conv,
     device::{Device, MissingDownlevelFlags},
     global::Global,
     id::{BufferId, CommandEncoderId, TextureId},
     init_tracker::{
         has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange,
         TextureInitTrackerAction,
     },
     resource::{
-        MissingBufferUsageError, MissingTextureUsageError, ParentDevice, Texture,
-        TextureErrorDimension,
+        MissingBufferUsageError, MissingTextureUsageError, ParentDevice, RawResourceAccess,
+        Texture, TextureErrorDimension,
     },
     snatch::SnatchGuard,
 };
 
 use super::{ClearError, CommandBufferMutable};
 
 pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<BufferId>;
 pub type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo<TextureId>;
@@ -90,16 +91,18 @@ pub enum TransferError {
     #[error("Number of bytes per row needs to be specified since more than one row is copied")]
     UnspecifiedBytesPerRow,
     #[error("Number of rows per image needs to be specified since more than one image is copied")]
     UnspecifiedRowsPerImage,
     #[error("Number of bytes per row is less than the number of bytes in a complete row")]
     InvalidBytesPerRow,
     #[error("Number of rows per image is invalid")]
     InvalidRowsPerImage,
+    #[error("Overflow while computing the size of the copy")]
+    SizeOverflow,
     #[error("Copy source aspects must refer to all aspects of the source texture format")]
     CopySrcMissingAspects,
     #[error(
         "Copy destination aspects must refer to all aspects of the destination texture format"
     )]
     CopyDstMissingAspects,
     #[error("Copy aspect must refer to a single aspect of texture format")]
     CopyAspectNotOne,
@@ -159,16 +162,17 @@ impl WebGpuError for TransferError {
             | Self::UnalignedCopyHeight
             | Self::UnalignedCopyOriginX
             | Self::UnalignedCopyOriginY
             | Self::UnalignedBytesPerRow
             | Self::UnspecifiedBytesPerRow
             | Self::UnspecifiedRowsPerImage
             | Self::InvalidBytesPerRow
             | Self::InvalidRowsPerImage
+            | Self::SizeOverflow
             | Self::CopySrcMissingAspects
             | Self::CopyDstMissingAspects
             | Self::CopyAspectNotOne
             | Self::CopyFromForbiddenTextureFormat { .. }
             | Self::CopyToForbiddenTextureFormat { .. }
             | Self::ExternalCopyToForbiddenTextureFormat(..)
             | Self::TextureFormatsNotCopyCompatible { .. }
             | Self::MissingDownlevelFlags(..)
@@ -176,16 +180,28 @@ impl WebGpuError for TransferError {
             | Self::SampleCountNotEqual { .. }
             | Self::InvalidMipLevel { .. }
             | Self::SameSourceDestinationBuffer => return ErrorType::Validation,
         };
         e.webgpu_error_type()
     }
 }
 
+impl From<BufferTextureCopyInfoError> for TransferError {
+    fn from(value: BufferTextureCopyInfoError) -> Self {
+        match value {
+            BufferTextureCopyInfoError::InvalidBytesPerRow => Self::InvalidBytesPerRow,
+            BufferTextureCopyInfoError::InvalidRowsPerImage => Self::InvalidRowsPerImage,
+            BufferTextureCopyInfoError::ImageStrideOverflow
+            | BufferTextureCopyInfoError::ImageBytesOverflow(_)
+            | BufferTextureCopyInfoError::ArraySizeOverflow(_) => Self::SizeOverflow,
+        }
+    }
+}
+
 pub(crate) fn extract_texture_selector<T>(
     copy_texture: &wgt::TexelCopyTextureInfo<T>,
     copy_size: &Extent3d,
     texture: &Texture,
 ) -> Result<(TextureSelector, hal::TextureCopyBase), TransferError> {
     let format = texture.desc.format;
     let copy_aspect = hal::FormatAspects::new(format, copy_texture.aspect);
     if copy_aspect.is_empty() {
@@ -249,53 +265,47 @@ pub(crate) fn validate_linear_texture_da
 
         block_size_bytes,
         block_width_texels,
         block_height_texels,
 
         width_blocks: _,
         height_blocks,
 
-        row_bytes_dense,
+        row_bytes_dense: _,
         row_stride_bytes,
 
         image_stride_rows: _,
         image_stride_bytes,
 
         image_rows_dense: _,
         image_bytes_dense: _,
 
         bytes_in_copy,
-    } = layout.get_buffer_texture_copy_info(format, aspect, copy_size);
+    } = layout.get_buffer_texture_copy_info(format, aspect, copy_size)?;
 
     if copy_width % block_width_texels != 0 {
         return Err(TransferError::UnalignedCopyWidth);
     }
     if copy_height % block_height_texels != 0 {
         return Err(TransferError::UnalignedCopyHeight);
     }
 
     let requires_multiple_rows = depth_or_array_layers > 1 || height_blocks > 1;
     let requires_multiple_images = depth_or_array_layers > 1;
 
-    if let Some(raw_bytes_per_row) = layout.bytes_per_row {
-        let raw_bytes_per_row = raw_bytes_per_row as BufferAddress;
-        if raw_bytes_per_row < row_bytes_dense {
-            return Err(TransferError::InvalidBytesPerRow);
-        }
-    } else if requires_multiple_rows {
+    // `get_buffer_texture_copy_info()` already proceeded with defaults if these
+    // were not specified, and ensured that the values satisfy the minima if
+    // they were, but now we enforce the WebGPU requirement that they be
+    // specified any time they apply.
+    if layout.bytes_per_row.is_none() && requires_multiple_rows {
         return Err(TransferError::UnspecifiedBytesPerRow);
     }
 
-    if let Some(raw_rows_per_image) = layout.rows_per_image {
-        let raw_rows_per_image = raw_rows_per_image as BufferAddress;
-        if raw_rows_per_image < height_blocks {
-            return Err(TransferError::InvalidRowsPerImage);
-        }
-    } else if requires_multiple_images {
+    if layout.rows_per_image.is_none() && requires_multiple_images {
         return Err(TransferError::UnspecifiedRowsPerImage);
     };
 
     if need_copy_aligned_rows {
         let bytes_per_row_alignment = wgt::COPY_BYTES_PER_ROW_ALIGNMENT as BufferAddress;
 
         let mut offset_alignment = block_size_bytes;
         if format.is_depth_stencil_format() {
--- a/third_party/rust/wgpu-core/src/device/global.rs
+++ b/third_party/rust/wgpu-core/src/device/global.rs
@@ -202,16 +202,18 @@ impl Global {
 
     #[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)?;
@@ -378,16 +380,17 @@ impl Global {
         (id, Some(error))
     }
 
     /// # Safety
     ///
     /// - `hal_buffer` must be created from `device_id` corresponding raw handle.
     /// - `hal_buffer` must be created respecting `desc`
     /// - `hal_buffer` must be initialized
+    /// - `hal_buffer` must not have zero size.
     pub unsafe fn create_buffer_from_hal<A: HalApi>(
         &self,
         hal_buffer: A::Buffer,
         device_id: DeviceId,
         desc: &resource::BufferDescriptor,
         id_in: Option<id::BufferId>,
     ) -> (id::BufferId, Option<CreateBufferError>) {
         profiling::scope!("Device::create_buffer");
@@ -399,17 +402,17 @@ impl Global {
 
         // 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()));
         }
 
-        let (buffer, err) = device.create_buffer_from_hal(Box::new(hal_buffer), desc);
+        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:?}");
 
         (id, err)
     }
 
     pub fn texture_destroy(&self, texture_id: id::TextureId) {
--- a/third_party/rust/wgpu-core/src/device/mod.rs
+++ b/third_party/rust/wgpu-core/src/device/mod.rs
@@ -3,17 +3,17 @@ use core::{fmt, num::NonZeroU32};
 
 use crate::{
     binding_model,
     hub::Hub,
     id::{BindGroupLayoutId, PipelineLayoutId},
     ray_tracing::BlasCompactReadyPendingClosure,
     resource::{
         Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation, Labeled,
-        ResourceErrorIdent,
+        RawResourceAccess, ResourceErrorIdent,
     },
     snatch::SnatchGuard,
     Label, DOWNLEVEL_ERROR_MESSAGE,
 };
 
 use arrayvec::ArrayVec;
 use smallvec::SmallVec;
 use thiserror::Error;
--- a/third_party/rust/wgpu-core/src/device/queue.rs
+++ b/third_party/rust/wgpu-core/src/device/queue.rs
@@ -9,17 +9,16 @@ use core::{
 use smallvec::SmallVec;
 use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
     AccelerationStructureFlags,
 };
 
 use super::{life::LifetimeTracker, Device};
-use crate::device::resource::CommandIndices;
 #[cfg(feature = "trace")]
 use crate::device::trace::Action;
 use crate::{
     api_log,
     command::{
         extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range,
         ClearError, CommandAllocator, CommandBuffer, CommandEncoderError, CopySide,
         TexelCopyTextureInfo, TransferError,
@@ -28,27 +27,28 @@ use crate::{
     device::{DeviceError, WaitIdleError},
     get_lowest_common_denom,
     global::Global,
     id::{self, BlasId, QueueId},
     init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
     lock::{rank, Mutex, MutexGuard, RwLock, RwLockWriteGuard},
     ray_tracing::{BlasCompactReadyPendingClosure, CompactBlasError},
     resource::{
-        AccelerationStructure, Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState,
-        DestroyedBuffer, DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer,
+        Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, DestroyedBuffer,
+        DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer,
         InvalidResourceError, Labeled, ParentDevice, ResourceErrorIdent, StagingBuffer, Texture,
         TextureInner, Trackable, TrackingData,
     },
     resource_log,
     scratch::ScratchBuffer,
     snatch::{SnatchGuard, Snatchable},
     track::{self, Tracker, TrackerIndex},
     FastHashMap, SubmissionIndex,
 };
+use crate::{device::resource::CommandIndices, resource::RawResourceAccess};
 
 pub struct Queue {
     raw: Box<dyn hal::DynQueue>,
     pub(crate) pending_writes: Mutex<PendingWrites>,
     life_tracker: Mutex<LifetimeTracker>,
     // The device needs to be dropped last (`Device.zero_buffer` might be referenced by the encoder in pending writes).
     pub(crate) device: Arc<Device>,
 }
--- a/third_party/rust/wgpu-core/src/device/resource.rs
+++ b/third_party/rust/wgpu-core/src/device/resource.rs
@@ -6,16 +6,17 @@ use alloc::{
     vec::Vec,
 };
 use core::{
     fmt,
     mem::{self, ManuallyDrop},
     num::NonZeroU32,
     sync::atomic::{AtomicBool, Ordering},
 };
+use hal::ShouldBeNonZeroExt;
 
 use arrayvec::ArrayVec;
 use bitflags::Flags;
 use smallvec::SmallVec;
 use wgt::{
     math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureSelector,
     TextureViewDimension,
 };
@@ -35,17 +36,17 @@ use crate::{
         BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
         TextureInitTrackerAction,
     },
     instance::{Adapter, RequestDeviceError},
     lock::{rank, Mutex, RwLock},
     pipeline,
     pool::ResourcePool,
     resource::{
-        self, AccelerationStructure, Buffer, Fallible, Labeled, ParentDevice, QuerySet, Sampler,
+        self, Buffer, Fallible, Labeled, ParentDevice, QuerySet, RawResourceAccess, Sampler,
         StagingBuffer, Texture, TextureView, TextureViewNotRenderableReason, Tlas, TrackingData,
     },
     resource_log,
     snatch::{SnatchGuard, SnatchLock, Snatchable},
     timestamp_normalization::TIMESTAMP_NORMALIZATION_BUFFER_USES,
     track::{BindGroupStates, DeviceTracker, TrackerIndexAllocators, UsageScope, UsageScopePool},
     validation::{self, validate_color_attachment_bytes_per_sample},
     weak_vec::WeakVec,
@@ -697,28 +698,29 @@ impl Device {
             label: desc.label.to_hal(self.instance_flags),
             size: aligned_size,
             usage,
             memory_flags: hal::MemoryFlags::empty(),
         };
         let buffer = unsafe { self.raw().create_buffer(&hal_desc) }
             .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
 
-        let timestamp_normalization_bind_group = Snatchable::new(
+        let timestamp_normalization_bind_group = Snatchable::new(unsafe {
+            // SAFETY: The size passed here must not overflow the buffer.
             self.timestamp_normalizer
                 .get()
                 .unwrap()
                 .create_normalization_bind_group(
                     self,
                     &*buffer,
                     desc.label.as_deref(),
-                    desc.size,
+                    wgt::BufferSize::new(hal_desc.size).unwrap(),
                     desc.usage,
-                )?,
-        );
+                )
+        }?);
 
         let indirect_validation_bind_groups =
             self.create_indirect_validation_bind_groups(buffer.as_ref(), desc.size, desc.usage)?;
 
         let buffer = Buffer {
             raw: Snatchable::new(buffer),
             device: self.clone(),
             usage: desc.usage,
@@ -804,38 +806,46 @@ impl Device {
         self.trackers
             .lock()
             .textures
             .insert_single(&texture, wgt::TextureUses::UNINITIALIZED);
 
         Ok(texture)
     }
 
-    pub(crate) fn create_buffer_from_hal(
+    /// # Safety
+    ///
+    /// - `hal_buffer` must have been created on this device.
+    /// - `hal_buffer` must have been created respecting `desc` (in particular, the size).
+    /// - `hal_buffer` must be initialized.
+    /// - `hal_buffer` must not have zero size.
+    pub(crate) unsafe fn create_buffer_from_hal(
         self: &Arc<Self>,
         hal_buffer: Box<dyn hal::DynBuffer>,
         desc: &resource::BufferDescriptor,
     ) -> (Fallible<Buffer>, Option<resource::CreateBufferError>) {
-        let timestamp_normalization_bind_group = match self
-            .timestamp_normalizer
-            .get()
-            .unwrap()
-            .create_normalization_bind_group(
-                self,
-                &*hal_buffer,
-                desc.label.as_deref(),
-                desc.size,
-                desc.usage,
-            ) {
-            Ok(bg) => Snatchable::new(bg),
-            Err(e) => {
-                return (
-                    Fallible::Invalid(Arc::new(desc.label.to_string())),
-                    Some(e.into()),
-                )
+        let timestamp_normalization_bind_group = unsafe {
+            match self
+                .timestamp_normalizer
+                .get()
+                .unwrap()
+                .create_normalization_bind_group(
+                    self,
+                    &*hal_buffer,
+                    desc.label.as_deref(),
+                    wgt::BufferSize::new(desc.size).unwrap(),
+                    desc.usage,
+                ) {
+                Ok(bg) => Snatchable::new(bg),
+                Err(e) => {
+                    return (
+                        Fallible::Invalid(Arc::new(desc.label.to_string())),
+                        Some(e.into()),
+                    )
+                }
             }
         };
 
         let indirect_validation_bind_groups = match self.create_indirect_validation_bind_groups(
             hal_buffer.as_ref(),
             desc.size,
             desc.usage,
         ) {
@@ -2182,41 +2192,19 @@ impl Device {
 
         let buffer = &bb.buffer;
 
         used.buffers.insert_single(buffer.clone(), internal_use);
 
         buffer.same_device(self)?;
 
         buffer.check_usage(pub_usage)?;
-        let raw_buffer = buffer.try_raw(snatch_guard)?;
-
-        let (bind_size, bind_end) = match bb.size {
-            Some(size) => {
-                let end = bb.offset + size.get();
-                if end > buffer.size {
-                    return Err(Error::BindingRangeTooLarge {
-                        buffer: buffer.error_ident(),
-                        range: bb.offset..end,
-                        size: buffer.size,
-                    });
-                }
-                (size.get(), end)
-            }
-            None => {
-                if buffer.size < bb.offset {
-                    return Err(Error::BindingRangeTooLarge {
-                        buffer: buffer.error_ident(),
-                        range: bb.offset..bb.offset,
-                        size: buffer.size,
-                    });
-                }
-                (buffer.size - bb.offset, buffer.size)
-            }
-        };
+
+        let (bb, bind_size) = buffer.binding(bb.offset, bb.size, snatch_guard)?;
+        let bind_end = bb.offset + bind_size;
 
         if bind_size > range_limit as u64 {
             return Err(Error::BufferRangeTooLarge {
                 binding,
                 given: bind_size as u32,
                 limit: range_limit,
             });
         }
@@ -2260,21 +2248,17 @@ impl Device {
         let visible_size = align_to(bind_size, bounds_check_alignment);
 
         used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
             buffer,
             bb.offset..bb.offset + visible_size,
             MemoryInitKind::NeedsInitializedMemory,
         ));
 
-        Ok(hal::BufferBinding {
-            buffer: raw_buffer,
-            offset: bb.offset,
-            size: bb.size,
-        })
+        Ok(bb)
     }
 
     fn create_sampler_binding<'a>(
         &self,
         used: &mut BindGroupStates,
         binding: u32,
         decl: &wgt::BindGroupLayoutEntry,
         sampler: &'a Arc<Sampler>,
--- a/third_party/rust/wgpu-core/src/indirect_validation/dispatch.rs
+++ b/third_party/rust/wgpu-core/src/indirect_validation/dispatch.rs
@@ -227,21 +227,22 @@ impl Dispatch {
         let dst_bind_group_desc = hal::BindGroupDescriptor {
             label: None,
             layout: dst_bind_group_layout.as_ref(),
             entries: &[hal::BindGroupEntry {
                 binding: 0,
                 resource_index: 0,
                 count: 1,
             }],
-            buffers: &[hal::BufferBinding {
-                buffer: dst_buffer.as_ref(),
-                offset: 0,
-                size: Some(DST_BUFFER_SIZE),
-            }],
+            // SAFETY: We just created the buffer with this size.
+            buffers: &[hal::BufferBinding::new_unchecked(
+                dst_buffer.as_ref(),
+                0,
+                Some(DST_BUFFER_SIZE),
+            )],
             samplers: &[],
             textures: &[],
             acceleration_structures: &[],
         };
         let dst_bind_group = unsafe {
             device
                 .create_bind_group(&dst_bind_group_desc)
                 .map_err(DeviceError::from_hal)
@@ -273,21 +274,18 @@ impl Dispatch {
         let hal_desc = hal::BindGroupDescriptor {
             label: None,
             layout: self.src_bind_group_layout.as_ref(),
             entries: &[hal::BindGroupEntry {
                 binding: 0,
                 resource_index: 0,
                 count: 1,
             }],
-            buffers: &[hal::BufferBinding {
-                buffer,
-                offset: 0,
-                size: Some(binding_size),
-            }],
+            // SAFETY: We calculated the binding size to fit within the buffer.
+            buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, binding_size)],
             samplers: &[],
             textures: &[],
             acceleration_structures: &[],
         };
         unsafe {
             device
                 .create_bind_group(&hal_desc)
                 .map(Some)
--- a/third_party/rust/wgpu-core/src/indirect_validation/draw.rs
+++ b/third_party/rust/wgpu-core/src/indirect_validation/draw.rs
@@ -130,21 +130,18 @@ impl Draw {
         let hal_desc = hal::BindGroupDescriptor {
             label: None,
             layout: self.src_bind_group_layout.as_ref(),
             entries: &[hal::BindGroupEntry {
                 binding: 0,
                 resource_index: 0,
                 count: 1,
             }],
-            buffers: &[hal::BufferBinding {
-                buffer,
-                offset: 0,
-                size: Some(binding_size),
-            }],
+            // SAFETY: We calculated the binding size to fit within the buffer.
+            buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, binding_size)],
             samplers: &[],
             textures: &[],
             acceleration_structures: &[],
         };
         unsafe {
             device
                 .create_bind_group(&hal_desc)
                 .map(Some)
@@ -679,21 +676,22 @@ fn create_buffer_and_bind_group(
     let bind_group_desc = hal::BindGroupDescriptor {
         label: None,
         layout: bind_group_layout,
         entries: &[hal::BindGroupEntry {
             binding: 0,
             resource_index: 0,
             count: 1,
         }],
-        buffers: &[hal::BufferBinding {
-            buffer: buffer.as_ref(),
-            offset: 0,
-            size: Some(BUFFER_SIZE),
-        }],
+        // SAFETY: We just created the buffer with this size.
+        buffers: &[hal::BufferBinding::new_unchecked(
+            buffer.as_ref(),
+            0,
+            BUFFER_SIZE,
+        )],
         samplers: &[],
         textures: &[],
         acceleration_structures: &[],
     };
     let bind_group = unsafe { device.create_bind_group(&bind_group_desc) }?;
     Ok(BufferPoolEntry { buffer, bind_group })
 }
 
--- a/third_party/rust/wgpu-core/src/lib.rs
+++ b/third_party/rust/wgpu-core/src/lib.rs
@@ -60,16 +60,17 @@
 #![cfg_attr(not(send_sync), allow(clippy::arc_with_non_send_sync))]
 
 extern crate alloc;
 #[cfg(feature = "std")]
 extern crate std;
 extern crate wgpu_hal as hal;
 extern crate wgpu_types as wgt;
 
+mod as_hal;
 pub mod binding_model;
 pub mod command;
 mod conv;
 pub mod device;
 pub mod error;
 pub mod global;
 pub mod hal_api;
 mod hash_utils;
--- a/third_party/rust/wgpu-core/src/lock/mod.rs
+++ b/third_party/rust/wgpu-core/src/lock/mod.rs
@@ -47,9 +47,9 @@ mod vanilla;
 use ranked as chosen;
 
 #[cfg(feature = "observe_locks")]
 use observing as chosen;
 
 #[cfg(not(any(wgpu_validate_locks, feature = "observe_locks")))]
 use vanilla as chosen;
 
-pub use chosen::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
+pub use chosen::{Mutex, MutexGuard, RankData, RwLock, RwLockReadGuard, RwLockWriteGuard};
--- a/third_party/rust/wgpu-core/src/lock/observing.rs
+++ b/third_party/rust/wgpu-core/src/lock/observing.rs
@@ -33,16 +33,18 @@ use core::{cell::RefCell, panic::Locatio
 use std::{
     fs::File,
     path::{Path, PathBuf},
 };
 
 use super::rank::{LockRank, LockRankSet};
 use crate::FastHashSet;
 
+pub type RankData = Option<HeldLock>;
+
 /// A `Mutex` instrumented for lock acquisition order observation.
 ///
 /// This is just a wrapper around a [`parking_lot::Mutex`], along with
 /// its rank in the `wgpu_core` lock ordering.
 ///
 /// For details, see [the module documentation][self].
 pub struct Mutex<T> {
     inner: parking_lot::Mutex<T>,
@@ -155,16 +157,37 @@ impl<T> RwLock<T> {
     #[track_caller]
     pub fn write(&self) -> RwLockWriteGuard<T> {
         let saved = acquire(self.rank, Location::caller());
         RwLockWriteGuard {
             inner: self.inner.write(),
             _state: LockStateGuard { saved },
         }
     }
+
+    /// Force an read-unlock operation on this lock.
+    ///
+    /// Safety:
+    /// - A read lock must be held which is not held by a guard.
+    pub unsafe fn force_unlock_read(&self, data: RankData) {
+        release(data);
+        unsafe { self.inner.force_unlock_read() };
+    }
+}
+
+impl<'a, T> RwLockReadGuard<'a, T> {
+    // Forget the read guard, leaving the lock in a locked state with no guard.
+    //
+    // Equivalent to std::mem::forget, but preserves the information about the lock
+    // rank.
+    pub fn forget(this: Self) -> RankData {
+        core::mem::forget(this.inner);
+
+        this._state.saved
+    }
 }
 
 impl<'a, T> RwLockWriteGuard<'a, T> {
     pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> {
         RwLockReadGuard {
             inner: parking_lot::RwLockWriteGuard::downgrade(this.inner),
             _state: this._state,
         }
@@ -311,17 +334,17 @@ enum ThreadState {
     Enabled {
         held_lock: Option<HeldLock>,
         log: ObservationLog,
     },
 }
 
 /// Information about a currently held lock.
 #[derive(Debug, Copy, Clone)]
-struct HeldLock {
+pub struct HeldLock {
     /// The lock's rank.
     rank: LockRank,
 
     /// Where we acquired the lock.
     location: &'static Location<'static>,
 }
 
 /// A log to which we can write observations of lock activity.
--- a/third_party/rust/wgpu-core/src/lock/ranked.rs
+++ b/third_party/rust/wgpu-core/src/lock/ranked.rs
@@ -54,16 +54,18 @@
 //! dependent on any particular interleaving of execution.
 //!
 //! [`lock::rank`]: crate::lock::rank
 
 use core::{cell::Cell, fmt, ops, panic::Location};
 
 use super::rank::LockRank;
 
+pub use LockState as RankData;
+
 /// A `Mutex` instrumented for deadlock prevention.
 ///
 /// This is just a wrapper around a [`parking_lot::Mutex`], along with
 /// its rank in the `wgpu_core` lock ordering.
 ///
 /// For details, see [the module documentation][self].
 pub struct Mutex<T> {
     inner: parking_lot::Mutex<T>,
@@ -82,17 +84,17 @@ pub struct MutexGuard<'a, T> {
 }
 
 std::thread_local! {
     static LOCK_STATE: Cell<LockState> = const { Cell::new(LockState::INITIAL) };
 }
 
 /// Per-thread state for the deadlock checker.
 #[derive(Debug, Copy, Clone)]
-struct LockState {
+pub struct LockState {
     /// The last lock we acquired, and where.
     last_acquired: Option<(LockRank, &'static Location<'static>)>,
 
     /// The number of locks currently held.
     ///
     /// This is used to enforce stack-like lock acquisition and release.
     depth: u32,
 }
@@ -265,16 +267,37 @@ impl<T> RwLock<T> {
     #[track_caller]
     pub fn write(&self) -> RwLockWriteGuard<T> {
         let saved = acquire(self.rank, Location::caller());
         RwLockWriteGuard {
             inner: self.inner.write(),
             saved: LockStateGuard(saved),
         }
     }
+
+    /// Force an read-unlock operation on this lock.
+    ///
+    /// Safety:
+    /// - A read lock must be held which is not held by a guard.
+    pub unsafe fn force_unlock_read(&self, data: RankData) {
+        release(data);
+        unsafe { self.inner.force_unlock_read() };
+    }
+}
+
+impl<'a, T> RwLockReadGuard<'a, T> {
+    // Forget the read guard, leaving the lock in a locked state with no guard.
+    //
+    // Equivalent to std::mem::forget, but preserves the information about the lock
+    // rank.
+    pub fn forget(this: Self) -> RankData {
+        core::mem::forget(this.inner);
+
+        this.saved.0
+    }
 }
 
 impl<'a, T> RwLockWriteGuard<'a, T> {
     pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> {
         RwLockReadGuard {
             inner: parking_lot::RwLockWriteGuard::downgrade(this.inner),
             saved: this.saved,
         }
--- a/third_party/rust/wgpu-core/src/lock/vanilla.rs
+++ b/third_party/rust/wgpu-core/src/lock/vanilla.rs
@@ -1,15 +1,19 @@
 //! Plain, uninstrumented wrappers around [`parking_lot`] lock types.
 //!
 //! These definitions are used when no particular lock instrumentation
 //! Cargo feature is selected.
 
 use core::{fmt, ops};
 
+use crate::lock::rank::LockRank;
+
+pub struct RankData;
+
 /// A plain wrapper around [`parking_lot::Mutex`].
 ///
 /// This is just like [`parking_lot::Mutex`], except that our [`new`]
 /// method takes a rank, indicating where the new mutex should sit in
 /// `wgpu-core`'s lock ordering. The rank is ignored.
 ///
 /// See the [`lock`] module documentation for other wrappers.
 ///
@@ -18,17 +22,17 @@ use core::{fmt, ops};
 pub struct Mutex<T>(parking_lot::Mutex<T>);
 
 /// A guard produced by locking [`Mutex`].
 ///
 /// This is just a wrapper around a [`parking_lot::MutexGuard`].
 pub struct MutexGuard<'a, T>(parking_lot::MutexGuard<'a, T>);
 
 impl<T> Mutex<T> {
-    pub fn new(_rank: super::rank::LockRank, value: T) -> Mutex<T> {
+    pub fn new(_rank: LockRank, value: T) -> Mutex<T> {
         Mutex(parking_lot::Mutex::new(value))
     }
 
     pub fn lock(&self) -> MutexGuard<T> {
         MutexGuard(self.0.lock())
     }
 
     pub fn into_inner(self) -> T {
@@ -74,27 +78,47 @@ pub struct RwLock<T>(parking_lot::RwLock
 pub struct RwLockReadGuard<'a, T>(parking_lot::RwLockReadGuard<'a, T>);
 
 /// A write guard produced by locking [`RwLock`] as a writer.
 ///
 /// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`].
 pub struct RwLockWriteGuard<'a, T>(parking_lot::RwLockWriteGuard<'a, T>);
 
 impl<T> RwLock<T> {
-    pub fn new(_rank: super::rank::LockRank, value: T) -> RwLock<T> {
+    pub fn new(_rank: LockRank, value: T) -> RwLock<T> {
         RwLock(parking_lot::RwLock::new(value))
     }
 
     pub fn read(&self) -> RwLockReadGuard<T> {
         RwLockReadGuard(self.0.read())
     }
 
     pub fn write(&self) -> RwLockWriteGuard<T> {
         RwLockWriteGuard(self.0.write())
     }
+
+    /// Force an read-unlock operation on this lock.
+    ///
+    /// Safety:
+    /// - A read lock must be held which is not held by a guard.
+    pub unsafe fn force_unlock_read(&self, _data: RankData) {
+        unsafe { self.0.force_unlock_read() };
+    }
+}
+
+impl<'a, T> RwLockReadGuard<'a, T> {
+    // Forget the read guard, leaving the lock in a locked state with no guard.
+    //
+    // Equivalent to std::mem::forget, but preserves the information about the lock
+    // rank.
+    pub fn forget(this: Self) -> RankData {
+        core::mem::forget(this.0);
+
+        RankData
+    }
 }
 
 impl<'a, T> RwLockWriteGuard<'a, T> {
     pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> {
         RwLockReadGuard(parking_lot::RwLockWriteGuard::downgrade(this.0))
     }
 }
 
--- a/third_party/rust/wgpu-core/src/pipeline.rs
+++ b/third_party/rust/wgpu-core/src/pipeline.rs
@@ -366,16 +366,27 @@ pub struct VertexBufferLayout<'a> {
     /// The stride, in bytes, between elements of this buffer.
     pub array_stride: wgt::BufferAddress,
     /// How often this vertex buffer is "stepped" forward.
     pub step_mode: wgt::VertexStepMode,
     /// The list of attributes which comprise a single vertex.
     pub attributes: Cow<'a, [wgt::VertexAttribute]>,
 }
 
+/// A null vertex buffer layout that may be placed in unused slots.
+impl Default for VertexBufferLayout<'_> {
+    fn default() -> Self {
+        Self {
+            array_stride: Default::default(),
+            step_mode: Default::default(),
+            attributes: Cow::Borrowed(&[]),
+        }
+    }
+}
+
 /// Describes the vertex process in a render pipeline.
 #[derive(Clone, Debug)]
 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
 pub struct VertexState<'a, SM = ShaderModuleId> {
     /// The compiled vertex stage and its entry point.
     pub stage: ProgrammableStageDescriptor<'a, SM>,
     /// The format of any vertex buffers used with this pipeline.
     pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
--- a/third_party/rust/wgpu-core/src/resource.rs
+++ b/third_party/rust/wgpu-core/src/resource.rs
@@ -12,40 +12,32 @@ use thiserror::Error;
 use wgt::{
     error::{ErrorType, WebGpuError},
     TextureSelector,
 };
 
 #[cfg(feature = "trace")]
 use crate::device::trace;
 use crate::{
-    binding_model::BindGroup,
+    binding_model::{BindGroup, BindingError},
     device::{
         queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError,
         DeviceMismatch, HostMap, MissingDownlevelFlags, MissingFeatures,
     },
-    global::Global,
-    hal_api::HalApi,
-    id::{
-        AdapterId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId,
-        TextureViewId,
-    },
     init_tracker::{BufferInitTracker, TextureInitTracker},
     lock::{rank, Mutex, RwLock},
     ray_tracing::{BlasCompactReadyPendingClosure, BlasPrepareCompactError},
     resource_log,
     snatch::{SnatchGuard, Snatchable},
     timestamp_normalization::TimestampNormalizationBindGroup,
     track::{SharedTrackerIndexAllocator, TrackerIndex},
     weak_vec::WeakVec,
     Label, LabelHelpers, SubmissionIndex,
 };
 
-use crate::id::{BlasId, TlasId};
-
 /// Information about the wgpu-core resource.
 ///
 /// Each type representing a `wgpu-core` resource, like [`Device`],
 /// [`Buffer`], etc., contains a `ResourceInfo` which contains
 /// its latest submission index and label.
 ///
 /// A resource may need to be retained for any of several reasons:
 /// and any lifetime logic will be handled by `Arc<Resource>` refcount
@@ -138,16 +130,39 @@ macro_rules! impl_parent_device {
         impl $crate::resource::ParentDevice for $ty {
             fn device(&self) -> &Arc<Device> {
                 &self.device
             }
         }
     };
 }
 
+/// Allow access to the hal resource as guarded by the `SnatchGuard`.
+pub trait RawResourceAccess: ParentDevice {
+    type DynResource: hal::DynResource + ?Sized;
+
+    /// Get access to the raw resource if it is not destroyed.
+    ///
+    /// Returns `None` if the resource has been destroyed. This method
+    /// does not allocate in either case.
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource>;
+
+    /// Get access to the raw resource if it is not destroyed.
+    ///
+    /// Returns a full error if the resource has been destroyed. This
+    /// method allocates a label in the error case.
+    fn try_raw<'a>(
+        &'a self,
+        guard: &'a SnatchGuard,
+    ) -> Result<&'a Self::DynResource, DestroyedResourceError> {
+        self.raw(guard)
+            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
+    }
+}
+
 pub trait ResourceType {
     const TYPE: &'static str;
 }
 
 #[macro_export]
 macro_rules! impl_resource_type {
     ($ty:ident) => {
         impl $crate::resource::ResourceType for $ty {
@@ -438,31 +453,25 @@ impl Drop for Buffer {
             resource_log!("Destroy raw {}", self.error_ident());
             unsafe {
                 self.device.raw().destroy_buffer(raw);
             }
         }
     }
 }
 
-impl Buffer {
-    pub(crate) fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a dyn hal::DynBuffer> {
+impl RawResourceAccess for Buffer {
+    type DynResource = dyn hal::DynBuffer;
+
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> {
         self.raw.get(guard).map(|b| b.as_ref())
     }
+}
 
-    pub(crate) fn try_raw<'a>(
-        &'a self,
-        guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynBuffer, DestroyedResourceError> {
-        self.raw
-            .get(guard)
-            .map(|raw| raw.as_ref())
-            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
-    }
-
+impl Buffer {
     pub(crate) fn check_destroyed(
         &self,
         guard: &SnatchGuard,
     ) -> Result<(), DestroyedResourceError> {
         self.raw
             .get(guard)
             .map(|_| ())
             .ok_or_else(|| DestroyedResourceError(self.error_ident()))
@@ -480,16 +489,92 @@ impl Buffer {
             Err(MissingBufferUsageError {
                 res: self.error_ident(),
                 actual: self.usage,
                 expected,
             })
         }
     }
 
+    /// Resolve the size of a binding for buffer with `offset` and `size`.
+    ///
+    /// If `size` is `None`, then the remainder of the buffer starting from
+    /// `offset` is used.
+    ///
+    /// If the binding would overflow the buffer, then an error is returned.
+    ///
+    /// Zero-size bindings are permitted here for historical reasons. Although
+    /// zero-size bindings are permitted by WebGPU, they are not permitted by
+    /// some backends. See [`Buffer::binding`] and
+    /// [#3170](https://github.com/gfx-rs/wgpu/issues/3170).
+    pub fn resolve_binding_size(
+        &self,
+        offset: wgt::BufferAddress,
+        binding_size: Option<wgt::BufferSize>,
+    ) -> Result<u64, BindingError> {
+        let buffer_size = self.size;
+
+        match binding_size {
+            Some(binding_size) => match offset.checked_add(binding_size.get()) {
+                Some(end) if end <= buffer_size => Ok(binding_size.get()),
+                _ => Err(BindingError::BindingRangeTooLarge {
+                    buffer: self.error_ident(),
+                    offset,
+                    binding_size: binding_size.get(),
+                    buffer_size,
+                }),
+            },
+            None => {
+                buffer_size
+                    .checked_sub(offset)
+                    .ok_or_else(|| BindingError::BindingOffsetTooLarge {
+                        buffer: self.error_ident(),
+                        offset,
+                        buffer_size,
+                    })
+            }
+        }
+    }
+
+    /// Create a new [`hal::BufferBinding`] for the buffer with `offset` and
+    /// `binding_size`.
+    ///
+    /// If `binding_size` is `None`, then the remainder of the buffer starting
+    /// from `offset` is used.
+    ///
+    /// If the binding would overflow the buffer, then an error is returned.
+    ///
+    /// A zero-size binding at the end of the buffer is permitted here for historical reasons. Although
+    /// zero-size bindings are permitted by WebGPU, they are not permitted by
+    /// some backends. The zero-size binding need to be quashed or remapped to a
+    /// non-zero size, either universally in wgpu-core, or in specific backends
+    /// that do not support them. See
+    /// [#3170](https://github.com/gfx-rs/wgpu/issues/3170).
+    ///
+    /// Although it seems like it would be simpler and safer to use the resolved
+    /// size in the returned [`hal::BufferBinding`], doing this (and removing
+    /// redundant logic in backends to resolve the implicit size) was observed
+    /// to cause problems in certain CTS tests, so an implicit size
+    /// specification is preserved in the output.
+    pub fn binding<'a>(
+        &'a self,
+        offset: wgt::BufferAddress,
+        binding_size: Option<wgt::BufferSize>,
+        snatch_guard: &'a SnatchGuard,
+    ) -> Result<(hal::BufferBinding<'a, dyn hal::DynBuffer>, u64), BindingError> {
+        let buf_raw = self.try_raw(snatch_guard)?;
+        let resolved_size = self.resolve_binding_size(offset, binding_size)?;
+        // SAFETY: The offset and size passed to hal::BufferBinding::new_unchecked must
+        // define a binding contained within the buffer.
+        Ok((
+            hal::BufferBinding::new_unchecked(buf_raw, offset, binding_size),
+            resolved_size,
+        ))
+    }
+
     /// 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(
         self: &Arc<Self>,
         offset: wgt::BufferAddress,
         size: Option<wgt::BufferAddress>,
         op: BufferMapOperation,
     ) -> Result<SubmissionIndex, (BufferMapOperation, BufferAccessError)> {
@@ -642,33 +727,33 @@ impl Buffer {
             Ok(())
         };
         Some((pending_mapping.op, status))
     }
 
     // Note: This must not be called while holding a lock.
     pub(crate) fn unmap(
         self: &Arc<Self>,
-        #[cfg(feature = "trace")] buffer_id: BufferId,
+        #[cfg(feature = "trace")] buffer_id: crate::id::BufferId,
     ) -> Result<(), BufferAccessError> {
         if let Some((mut operation, status)) = self.unmap_inner(
             #[cfg(feature = "trace")]
             buffer_id,
         )? {
             if let Some(callback) = operation.callback.take() {
                 callback(status);
             }
         }
 
         Ok(())
     }
 
     fn unmap_inner(
         self: &Arc<Self>,
-        #[cfg(feature = "trace")] buffer_id: BufferId,
+        #[cfg(feature = "trace")] buffer_id: crate::id::BufferId,
     ) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> {
         let device = &self.device;
         let snatch_guard = device.snatchable_lock.read();
         let raw_buf = self.try_raw(&snatch_guard)?;
         match mem::replace(&mut *self.map_state.lock(), BufferMapState::Idle) {
             BufferMapState::Init { staging_buffer } => {
                 #[cfg(feature = "trace")]
                 if let Some(ref mut trace) = *device.trace.lock() {
@@ -910,19 +995,19 @@ unsafe impl Sync for StagingBuffer {}
 /// used with [`queue_write_staging_buffer`]. They are also used internally by
 /// operations like [`queue_write_texture`] that need to upload data to the GPU,
 /// but that don't belong to any particular wgpu command buffer.
 ///
 /// Used `StagingBuffer`s are accumulated in [`Device::pending_writes`], to be
 /// freed once their associated operation's queue submission has finished
 /// execution.
 ///
-/// [`queue_create_staging_buffer`]: Global::queue_create_staging_buffer
-/// [`queue_write_staging_buffer`]: Global::queue_write_staging_buffer
-/// [`queue_write_texture`]: Global::queue_write_texture
+/// [`queue_create_staging_buffer`]: crate::global::Global::queue_create_staging_buffer
+/// [`queue_write_staging_buffer`]: crate::global::Global::queue_write_staging_buffer
+/// [`queue_write_texture`]: crate::global::Global::queue_write_texture
 /// [`Device::pending_writes`]: crate::device::Device
 #[derive(Debug)]
 pub struct StagingBuffer {
     raw: Box<dyn hal::DynBuffer>,
     device: Arc<Device>,
     pub(crate) size: wgt::BufferSize,
     is_coherent: bool,
     ptr: NonNull<u8>,
@@ -1185,43 +1270,34 @@ impl Drop for Texture {
             resource_log!("Destroy raw {}", self.error_ident());
             unsafe {
                 self.device.raw().destroy_texture(raw);
             }
         }
     }
 }
 
+impl RawResourceAccess for Texture {
+    type DynResource = dyn hal::DynTexture;
+
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> {
+        self.inner.get(guard).map(|t| t.raw())
+    }
+}
+
 impl Texture {
     pub(crate) fn try_inner<'a>(
         &'a self,
         guard: &'a SnatchGuard,
     ) -> Result<&'a TextureInner, DestroyedResourceError> {
         self.inner
             .get(guard)
             .ok_or_else(|| DestroyedResourceError(self.error_ident()))
     }
 
-    pub(crate) fn raw<'a>(
-        &'a self,
-        snatch_guard: &'a SnatchGuard,
-    ) -> Option<&'a dyn hal::DynTexture> {
-        Some(self.inner.get(snatch_guard)?.raw())
-    }
-
-    pub(crate) fn try_raw<'a>(
-        &'a self,
-        guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynTexture, DestroyedResourceError> {
-        self.inner
-            .get(guard)
-            .map(|t| t.raw())
-            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
-    }
-
     pub(crate) fn check_destroyed(
         &self,
         guard: &SnatchGuard,
     ) -> Result<(), DestroyedResourceError> {
         self.inner
             .get(guard)
             .map(|_| ())
             .ok_or_else(|| DestroyedResourceError(self.error_ident()))
@@ -1301,246 +1377,16 @@ impl Texture {
                 if let Some(last_submit_index) = last_submit_index {
                     life_lock.schedule_resource_destruction(temp, last_submit_index);
                 }
             }
         }
     }
 }
 
-impl Global {
-    /// # Safety
-    ///
-    /// - The raw buffer handle must not be manually destroyed
-    pub unsafe fn buffer_as_hal<A: HalApi, F: FnOnce(Option<&A::Buffer>) -> R, R>(
-        &self,
-        id: BufferId,
-        hal_buffer_callback: F,
-    ) -> R {
-        profiling::scope!("Buffer::as_hal");
-
-        let hub = &self.hub;
-
-        if let Ok(buffer) = hub.buffers.get(id).get() {
-            let snatch_guard = buffer.device.snatchable_lock.read();
-            let hal_buffer = buffer
-                .raw(&snatch_guard)
-                .and_then(|b| b.as_any().downcast_ref());
-            hal_buffer_callback(hal_buffer)
-        } else {
-            hal_buffer_callback(None)
-        }
-    }
-
-    /// # Safety
-    ///
-    /// - The raw texture handle must not be manually destroyed
-    pub unsafe fn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>) -> R, R>(
-        &self,
-        id: TextureId,
-        hal_texture_callback: F,
-    ) -> R {
-        profiling::scope!("Texture::as_hal");
-
-        let hub = &self.hub;
-
-        if let Ok(texture) = hub.textures.get(id).get() {
-            let snatch_guard = texture.device.snatchable_lock.read();
-            let hal_texture = texture.raw(&snatch_guard);
-            let hal_texture = hal_texture
-                .as_ref()
-                .and_then(|it| it.as_any().downcast_ref());
-            hal_texture_callback(hal_texture)
-        } else {
-            hal_texture_callback(None)
-        }
-    }
-
-    /// # Safety
-    ///
-    /// - The raw texture view handle must not be manually destroyed
-    pub unsafe fn texture_view_as_hal<A: HalApi, F: FnOnce(Option<&A::TextureView>) -> R, R>(
-        &self,
-        id: TextureViewId,
-        hal_texture_view_callback: F,
-    ) -> R {
-        profiling::scope!("TextureView::as_hal");
-
-        let hub = &self.hub;
-
-        if let Ok(texture_view) = hub.texture_views.get(id).get() {
-            let snatch_guard = texture_view.device.snatchable_lock.read();
-            let hal_texture_view = texture_view.raw(&snatch_guard);
-            let hal_texture_view = hal_texture_view
-                .as_ref()
-                .and_then(|it| it.as_any().downcast_ref());
-            hal_texture_view_callback(hal_texture_view)
-        } else {
-            hal_texture_view_callback(None)
-        }
-    }
-
-    /// # Safety
-    ///
-    /// - The raw adapter handle must not be manually destroyed
-    pub unsafe fn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
-        &self,
-        id: AdapterId,
-        hal_adapter_callback: F,
-    ) -> R {
-        profiling::scope!("Adapter::as_hal");
-
-        let hub = &self.hub;
-        let adapter = hub.adapters.get(id);
-        let hal_adapter = adapter.raw.adapter.as_any().downcast_ref();
-
-        hal_adapter_callback(hal_adapter)
-    }
-
-    /// # Safety
-    ///
-    /// - The raw device handle must not be manually destroyed
-    pub unsafe fn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
-        &self,
-        id: DeviceId,
-        hal_device_callback: F,
-    ) -> R {
-        profiling::scope!("Device::as_hal");
-
-        let device = self.hub.devices.get(id);
-        let hal_device = device.raw().as_any().downcast_ref();
-
-        hal_device_callback(hal_device)
-    }
-
-    /// # Safety
-    ///
-    /// - The raw fence handle must not be manually destroyed
-    pub unsafe fn device_fence_as_hal<A: HalApi, F: FnOnce(Option<&A::Fence>) -> R, R>(
-        &self,
-        id: DeviceId,
-        hal_fence_callback: F,
-    ) -> R {
-        profiling::scope!("Device::fence_as_hal");
-
-        let device = self.hub.devices.get(id);
-        let fence = device.fence.read();
-        hal_fence_callback(fence.as_any().downcast_ref())
-    }
-
-    /// # Safety
-    /// - The raw surface handle must not be manually destroyed
-    pub unsafe fn surface_as_hal<A: HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
-        &self,
-        id: SurfaceId,
-        hal_surface_callback: F,
-    ) -> R {
-        profiling::scope!("Surface::as_hal");
-
-        let surface = self.surfaces.get(id);
-        let hal_surface = surface
-            .raw(A::VARIANT)
-            .and_then(|surface| surface.as_any().downcast_ref());
-
-        hal_surface_callback(hal_surface)
-    }
-
-    /// # Safety
-    ///
-    /// - The raw command encoder handle must not be manually destroyed
-    pub unsafe fn command_encoder_as_hal_mut<
-        A: HalApi,
-        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
-        R,
-    >(
-        &self,
-        id: CommandEncoderId,
-        hal_command_encoder_callback: F,
-    ) -> R {
-        profiling::scope!("CommandEncoder::as_hal");
-
-        let hub = &self.hub;
-
-        let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
-        let mut cmd_buf_data = cmd_buf.data.lock();
-        cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
-            hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
-                cmd_buf
-                    .encoder
-                    .open()
-                    .ok()
-                    .and_then(|encoder| encoder.as_any_mut().downcast_mut())
-            }))
-        })
-    }
-
-    /// # Safety
-    ///
-    /// - The raw queue handle must not be manually destroyed
-    pub unsafe fn queue_as_hal<A: HalApi, F, R>(&self, id: QueueId, hal_queue_callback: F) -> R
-    where
-        F: FnOnce(Option<&A::Queue>) -> R,
-    {
-        profiling::scope!("Queue::as_hal");
-
-        let queue = self.hub.queues.get(id);
-        let hal_queue = queue.raw().as_any().downcast_ref();
-
-        hal_queue_callback(hal_queue)
-    }
-
-    /// # Safety
-    ///
-    /// - The raw blas handle must not be manually destroyed
-    pub unsafe fn blas_as_hal<A: HalApi, F: FnOnce(Option<&A::AccelerationStructure>) -> R, R>(
-        &self,
-        id: BlasId,
-        hal_blas_callback: F,
-    ) -> R {
-        profiling::scope!("Blas::as_hal");
-
-        let hub = &self.hub;
-
-        if let Ok(blas) = hub.blas_s.get(id).get() {
-            let snatch_guard = blas.device.snatchable_lock.read();
-            let hal_blas = blas
-                .try_raw(&snatch_guard)
-                .ok()
-                .and_then(|b| b.as_any().downcast_ref());
-            hal_blas_callback(hal_blas)
-        } else {
-            hal_blas_callback(None)
-        }
-    }
-
-    /// # Safety
-    ///
-    /// - The raw tlas handle must not be manually destroyed
-    pub unsafe fn tlas_as_hal<A: HalApi, F: FnOnce(Option<&A::AccelerationStructure>) -> R, R>(
-        &self,
-        id: TlasId,
-        hal_tlas_callback: F,
-    ) -> R {
-        profiling::scope!("Blas::as_hal");
-
-        let hub = &self.hub;
-
-        if let Ok(tlas) = hub.tlas_s.get(id).get() {
-            let snatch_guard = tlas.device.snatchable_lock.read();
-            let hal_tlas = tlas
-                .try_raw(&snatch_guard)
-                .ok()
-                .and_then(|t| t.as_any().downcast_ref());
-            hal_tlas_callback(hal_tlas)
-        } else {
-            hal_tlas_callback(None)
-        }
-    }
-}
-
 /// A texture that has been marked as destroyed and is staged for actual deletion soon.
 #[derive(Debug)]
 pub struct DestroyedTexture {
     raw: ManuallyDrop<Box<dyn hal::DynTexture>>,
     views: WeakVec<TextureView>,
     clear_mode: TextureClearMode,
     bind_groups: WeakVec<BindGroup>,
     device: Arc<Device>,
@@ -1803,35 +1649,35 @@ impl Drop for TextureView {
             resource_log!("Destroy raw {}", self.error_ident());
             unsafe {
                 self.device.raw().destroy_texture_view(raw);
             }
         }
     }
 }
 
-impl TextureView {
-    pub(crate) fn raw<'a>(
-        &'a self,
-        snatch_guard: &'a SnatchGuard,
-    ) -> Option<&'a dyn hal::DynTextureView> {
-        self.raw.get(snatch_guard).map(|it| it.as_ref())
+impl RawResourceAccess for TextureView {
+    type DynResource = dyn hal::DynTextureView;
+
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> {
+        self.raw.get(guard).map(|it| it.as_ref())
     }
 
-    pub(crate) fn try_raw<'a>(
+    fn try_raw<'a>(
         &'a self,
         guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynTextureView, DestroyedResourceError> {
+    ) -> Result<&'a Self::DynResource, DestroyedResourceError> {
         self.parent.check_destroyed(guard)?;
-        self.raw
-            .get(guard)
-            .map(|it| it.as_ref())
+
+        self.raw(guard)
             .ok_or_else(|| DestroyedResourceError(self.error_ident()))
     }
+}
 
+impl TextureView {
     /// Checks that the given texture usage contains the required texture usage,
     /// returns an error otherwise.
     pub(crate) fn check_usage(
         &self,
         expected: wgt::TextureUsages,
     ) -> Result<(), MissingTextureUsageError> {
         if self.desc.usage.contains(expected) {
             Ok(())
@@ -2121,23 +1967,16 @@ impl QuerySet {
     pub(crate) fn raw(&self) -> &dyn hal::DynQuerySet {
         self.raw.as_ref()
     }
 }
 
 pub type BlasDescriptor<'a> = wgt::CreateBlasDescriptor<Label<'a>>;
 pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;
 
-pub(crate) trait AccelerationStructure: Trackable {
-    fn try_raw<'a>(
-        &'a self,
-        guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError>;
-}
-
 pub type BlasPrepareCompactResult = Result<(), BlasPrepareCompactError>;
 
 #[cfg(send_sync)]
 pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + Send + 'static>;
 #[cfg(not(send_sync))]
 pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + 'static>;
 
 pub(crate) struct BlasPendingCompact {
@@ -2203,25 +2042,21 @@ impl Drop for Blas {
                 self.device
                     .raw()
                     .destroy_buffer(ManuallyDrop::take(&mut raw))
             }
         }
     }
 }
 
-impl AccelerationStructure for Blas {
-    fn try_raw<'a>(
-        &'a self,
-        guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> {
-        self.raw
-            .get(guard)
-            .map(|raw| raw.as_ref())
-            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
+impl RawResourceAccess for Blas {
+    type DynResource = dyn hal::DynAccelerationStructure;
+
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> {
+        self.raw.get(guard).map(|it| it.as_ref())
     }
 }
 
 impl Blas {
     pub(crate) fn prepare_compact_async(
         self: &Arc<Self>,
         op: Option<BlasCompactCallback>,
     ) -> Result<SubmissionIndex, (Option<BlasCompactCallback>, BlasPrepareCompactError)> {
@@ -2351,25 +2186,21 @@ impl Drop for Tlas {
                 self.device.raw().destroy_acceleration_structure(structure);
             }
             let buffer = ManuallyDrop::take(&mut self.instance_buffer);
             self.device.raw().destroy_buffer(buffer);
         }
     }
 }
 
-impl AccelerationStructure for Tlas {
-    fn try_raw<'a>(
-        &'a self,
-        guard: &'a SnatchGuard,
-    ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> {
-        self.raw
-            .get(guard)
-            .map(|raw| raw.as_ref())
-            .ok_or_else(|| DestroyedResourceError(self.error_ident()))
+impl RawResourceAccess for Tlas {
+    type DynResource = dyn hal::DynAccelerationStructure;
+
+    fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> {
+        self.raw.get(guard).map(|raw| raw.as_ref())
     }
 }
 
 crate::impl_resource_type!(Tlas);
 crate::impl_labeled!(Tlas);
 crate::impl_parent_device!(Tlas);
 crate::impl_storage_item!(Tlas);
 crate::impl_trackable!(Tlas);
--- a/third_party/rust/wgpu-core/src/snatch.rs
+++ b/third_party/rust/wgpu-core/src/snatch.rs
@@ -1,14 +1,14 @@
-use core::{cell::UnsafeCell, fmt};
+use core::{cell::UnsafeCell, fmt, mem::ManuallyDrop};
 
-use crate::lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard};
+use crate::lock::{rank, RankData, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
 /// A guard that provides read access to snatchable data.
-pub struct SnatchGuard<'a>(#[expect(dead_code)] RwLockReadGuard<'a, ()>);
+pub struct SnatchGuard<'a>(RwLockReadGuard<'a, ()>);
 /// A guard that allows snatching the snatchable data.
 pub struct ExclusiveSnatchGuard<'a>(#[expect(dead_code)] RwLockWriteGuard<'a, ()>);
 
 /// A value that is mostly immutable but can be "snatched" if we need to destroy
 /// it early.
 ///
 /// In order to safely access the underlying data, the device's global snatchable
 /// lock must be taken. To guarantee it, methods take a read or write guard of that
@@ -153,16 +153,43 @@ impl SnatchLock {
     /// This should only be called when a resource needs to be snatched. This has
     /// a high risk of causing lock contention if called concurrently with other
     /// wgpu work.
     #[track_caller]
     pub fn write(&self) -> ExclusiveSnatchGuard {
         LockTrace::enter("write");
         ExclusiveSnatchGuard(self.lock.write())
     }
+
+    #[track_caller]
+    pub unsafe fn force_unlock_read(&self, data: RankData) {
+        // This is unsafe because it can cause deadlocks if the lock is held.
+        // It should only be used in very specific cases, like when a resource
+        // needs to be snatched in a panic handler.
+        LockTrace::exit();
+        unsafe { self.lock.force_unlock_read(data) };
+    }
+}
+
+impl SnatchGuard<'_> {
+    /// Forget the guard, leaving the lock in a locked state with no guard.
+    ///
+    /// This is equivalent to `std::mem::forget`, but preserves the information about the lock
+    /// rank.
+    pub fn forget(this: Self) -> RankData {
+        // Cancel the drop implementation of the current guard.
+        let manually_drop = ManuallyDrop::new(this);
+
+        // As we are unable to destructure out of this guard due to the drop implementation,
+        // so we manually read the inner value.
+        // SAFETY: This is safe because we never access the original guard again.
+        let inner_guard = unsafe { core::ptr::read(&manually_drop.0) };
+
+        RwLockReadGuard::forget(inner_guard)
+    }
 }
 
 impl Drop for SnatchGuard<'_> {
     fn drop(&mut self) {
         LockTrace::exit();
     }
 }
 
--- a/third_party/rust/wgpu-core/src/timestamp_normalization/mod.rs
+++ b/third_party/rust/wgpu-core/src/timestamp_normalization/mod.rs
@@ -237,38 +237,42 @@ impl TimestampNormalizer {
                     temporary_bind_group_layout,
                     pipeline_layout,
                     pipeline,
                 }),
             })
         }
     }
 
-    pub fn create_normalization_bind_group(
+    /// Create a bind group for normalizing timestamps in `buffer`.
+    ///
+    /// This function is unsafe because it does not know that `buffer_size` is
+    /// the true size of the buffer.
+    pub unsafe fn create_normalization_bind_group(
         &self,
         device: &Device,
         buffer: &dyn hal::DynBuffer,
         buffer_label: Option<&str>,
-        buffer_size: u64,
+        buffer_size: wgt::BufferSize,
         buffer_usages: wgt::BufferUsages,
     ) -> Result<TimestampNormalizationBindGroup, DeviceError> {
         unsafe {
             let Some(ref state) = &self.state else {
                 return Ok(TimestampNormalizationBindGroup { raw: None });
             };
 
             if !buffer_usages.contains(wgt::BufferUsages::QUERY_RESOLVE) {
                 return Ok(TimestampNormalizationBindGroup { raw: None });
             }
 
             // If this buffer is large enough that we wouldn't be able to bind the entire thing
             // at once to normalize the timestamps, we can't use it. We force the buffer to fail
             // to allocate. The lowest max binding size is 128MB, and query sets must be small
             // (no more than 4096), so this should never be hit in practice by sane programs.
-            if buffer_size > device.adapter.limits().max_storage_buffer_binding_size as u64 {
+            if buffer_size.get() > device.adapter.limits().max_storage_buffer_binding_size as u64 {
                 return Err(DeviceError::OutOfMemory);
             }
 
             let bg_label_alloc;
             let label = match buffer_label {
                 Some(label) => {
                     bg_label_alloc =
                         alloc::format!("Timestamp normalization bind group ({})", label);
@@ -277,21 +281,17 @@ impl TimestampNormalizer {
                 None => "Timestamp normalization bind group",
             };
 
             let bg = device
                 .raw()
                 .create_bind_group(&hal::BindGroupDescriptor {
                     label: Some(label),
                     layout: &*state.temporary_bind_group_layout,
-                    buffers: &[hal::BufferBinding {
-                        buffer,
-                        offset: 0,
-                        size: None,
-                    }],
+                    buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, buffer_size)],
                     samplers: &[],
                     textures: &[],
                     acceleration_structures: &[],
                     entries: &[hal::BindGroupEntry {
                         binding: 0,
                         resource_index: 0,
                         count: 1,
                     }],
--- a/third_party/rust/wgpu-core/src/track/mod.rs
+++ b/third_party/rust/wgpu-core/src/track/mod.rs
@@ -101,17 +101,17 @@ mod metadata;
 mod range;
 mod stateless;
 mod texture;
 
 use crate::{
     binding_model, command,
     lock::{rank, Mutex},
     pipeline,
-    resource::{self, Labeled, ResourceErrorIdent},
+    resource::{self, Labeled, RawResourceAccess, ResourceErrorIdent},
     snatch::SnatchGuard,
     track::blas::BlasTracker,
 };
 
 use alloc::{sync::Arc, vec::Vec};
 use core::{fmt, mem, ops};
 
 use thiserror::Error;
--- a/third_party/rust/wgpu-core/src/track/texture.rs
+++ b/third_party/rust/wgpu-core/src/track/texture.rs
@@ -15,17 +15,17 @@
 //!   It cannot leak into transitions, it is invalid to transition into UNKNOWN
 //!   state.
 //! - `UNINITIALIZED` is used in both simple and complex states to mean the texture
 //!   is known to be in some undefined state. Any transition away from UNINITIALIZED
 //!   will treat the contents as junk.
 
 use super::{range::RangedStates, PendingTransition, PendingTransitionList};
 use crate::{
-    resource::{Texture, TextureInner, TextureView, Trackable},
+    resource::{RawResourceAccess, Texture, TextureInner, TextureView, Trackable},
     snatch::SnatchGuard,
     track::{
         invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
         ResourceUsageCompatibilityError, ResourceUses,
     },
 };
 use hal::TextureBarrier;
 
--- a/third_party/rust/wgpu-hal/.cargo-checksum.json
+++ b/third_party/rust/wgpu-hal/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"05bb196b5da1be2afc2062b9650421841629cb29ed27997f5a5d0dc414b46692","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"f42ceef4ee26c1e2b5b917e697ae662099550fece8bb715b2076a55413662c6c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"f41b15e898da0047d33c7bed0dd311ca6fade507ba453c238a7babf789480b6c","examples/ray-traced-triangle/main.rs":"ecbd4625050f1be3d61af83f4effffa11b8baaef127ec17a2d3ca0465cb7d967","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"f451fb0c416a637f11542e9b166a48800be50c48925779b06d40a9bc87958d97","src/auxil/dxgi/exception.rs":"4ac0004d0efc88ba7738e166064796400ca1eb9518bd8cc642144401989ec796","src/auxil/dxgi/factory.rs":"1d8cfeb733e34b97d5b879705fc5621ab7b9be578aebb3c3ddadea992effb566","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"a3b52fd87e512bb94df79c8cadf89a1fbcf7ab0a3a8c7fa1280c2e54cb75d96e","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"e687710ea0c9e88c9be0e2acd39d136635b835ffb941886b875811b3ec945080","src/dx12/adapter.rs":"965016bde0f374b7ac3bd59e8952590a92a2c404da2c0f52372fd236466b73a5","src/dx12/command.rs":"f11a50b9ada035ed27affcb0e127c63bc62ba8bfae47a9357251b263e1e7f872","src/dx12/conv.rs":"f800cf605bda983828330f73a53d7f47549a17e7263572a356168dd656270c31","src/dx12/descriptor.rs":"e3371d7539c44ffc4c7b958b6d948855200bb3c4e7da9577835cc0bca695807b","src/dx12/device.rs":"9b7c547548aaeb4075d9bfa705758bcadfc0b5f6a0215da0bc234f9ead68b02b","src/dx12/instance.rs":"0c4bd516177ddb3724529aa30751ebde41d6f80e6bf294a23ec621712663cedd","src/dx12/mod.rs":"6156fae97db99b4e90e983533a3c08c85866dec113a412194d9e108641984ba4","src/dx12/sampler.rs":"64464c32452ee63ac49014a03ca3be894ab9b74e11dc853567b5da5f846faae6","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"44f5ab65c1eeb54a53841dc769b749ce7702e32b89a6bd2ddd1a270f63437a50","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"9635dea15d8a885011d2b8b6b9cc5ffe2126cc3f141f47f7aaf46e1f201abea9","src/dynamic/device.rs":"f00305d56cac0636d4cb86cc44ee69c291bfb3d5f6d5e8d745adce9a28a6a1d5","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"b02a3c11b22c896cf66ef206f5d4bb4e24988ecadc29972c572baf347f54aa04","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"bf6318ba3b45b277181b69d715184ff06ffe0173ce44872ad90d55098f04a1ab","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"7f885dd2bc72641d22f8f2e688ebdd857663bfe315f1b5364ea302f99a05adbf","src/gles/device.rs":"07aa761e7a5857fc25caecddc6ed6b0ea970a815feb7343f75cb76bc2196ca01","src/gles/egl.rs":"de77822e37369bb4c41e1efcd92134aa220acf0dd8a251a0d4499dd4d541a547","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"083cd49747aba6272002aba0b0c37e5768cdbc2a1b8bacd1a244ee905d3f7b0f","src/gles/mod.rs":"897365cdd34914a654532c8d9592cb3a3f460bd50ac2b6ba72106a105c12ac10","src/gles/queue.rs":"f0a75fa2431f84feaf9a2cd0ba156ffa011b0ba671b167066d2f9341bde89109","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":"8e6be7b49b9af7c2f19da313f173a19d8cf1ab007469b547318f7e8555b78769","src/metal/adapter.rs":"1b035bf4e69df1575b215cf5a6578afcf729ac26dbae81cf1344fbae5659f65f","src/metal/command.rs":"1ec1a9e0e1ccf298c2c416b96e60827173e6584c9061b8dd582b7789545ce60a","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"581472ed832c8b0960d61f0a0347dba42b649182a576285367f8198555e63051","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"8721673e6f9e88bca5318ff4286a91e5c441ae607b53940c45bda0d8c053e99d","src/metal/surface.rs":"50c628f0e555f936707e57dbff59bbc9b1b05b10747b8303189b878b6fb28795","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"c0d0b593e890e028deb88cc02a02c87c61f2049b6371cd0c788d3345b306f9a4","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"4d1f9feb3b7fdfa685038acb3f4ae4967de164ce9a09be519cadd837b7a717d9","src/vulkan/command.rs":"e058758398d4ec6fda1d0274d99b92ae541f4263ee804bcb1c42ca96f8610ac0","src/vulkan/conv.rs":"f416df65d0abceff8518c5ac86c1f88102b66e64403494d795691b56328374da","src/vulkan/device.rs":"2641631d6d20db6c72dbe9a67fbabccc8975f43f9aed1c2be6f7ed8b0cf1a590","src/vulkan/drm.rs":"09eaa92c6a17e219ee856ffc3fe5f9fe1c15063b4c3dbb7cd20bf2f4f9cac2c7","src/vulkan/instance.rs":"e7d3e7abec8ac8aa582f4facc28668f02dfdc8342cca948f359746851a6c6260","src/vulkan/mod.rs":"1de05dec5386cd701decda525512e48316347f87c48aa273c44a63fd510e8241","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"102266d8e1b9f2ec1decf681bcc9e1a4cbff29533a258f2699fb6c573c434771"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"a6f3ec315417a8d74aba436354d64a2f8ec01059a65b179f9877b2a26c2f1eba","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"4cfc7ca7d9ae764aa115549f774659ff524b1a56cced3e737a22efe861e7f12a","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"f41b15e898da0047d33c7bed0dd311ca6fade507ba453c238a7babf789480b6c","examples/ray-traced-triangle/main.rs":"ea8765315c464e285a0496fb9ee34d8c40d7b439d2d3ecac4475196eacae6786","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"f451fb0c416a637f11542e9b166a48800be50c48925779b06d40a9bc87958d97","src/auxil/dxgi/exception.rs":"4ac0004d0efc88ba7738e166064796400ca1eb9518bd8cc642144401989ec796","src/auxil/dxgi/factory.rs":"1d8cfeb733e34b97d5b879705fc5621ab7b9be578aebb3c3ddadea992effb566","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"a3b52fd87e512bb94df79c8cadf89a1fbcf7ab0a3a8c7fa1280c2e54cb75d96e","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"e687710ea0c9e88c9be0e2acd39d136635b835ffb941886b875811b3ec945080","src/dx12/adapter.rs":"965016bde0f374b7ac3bd59e8952590a92a2c404da2c0f52372fd236466b73a5","src/dx12/command.rs":"bad5f12c670e0d4cae5191ee0ee8cc82f9d90c408bdc648c7e2493881a9992fc","src/dx12/conv.rs":"f800cf605bda983828330f73a53d7f47549a17e7263572a356168dd656270c31","src/dx12/descriptor.rs":"e3371d7539c44ffc4c7b958b6d948855200bb3c4e7da9577835cc0bca695807b","src/dx12/device.rs":"929173beaca41ccd7e8c465a724c5ef8f6da96e5abd0b6fab533da5b761af966","src/dx12/instance.rs":"0c4bd516177ddb3724529aa30751ebde41d6f80e6bf294a23ec621712663cedd","src/dx12/mod.rs":"6156fae97db99b4e90e983533a3c08c85866dec113a412194d9e108641984ba4","src/dx12/sampler.rs":"64464c32452ee63ac49014a03ca3be894ab9b74e11dc853567b5da5f846faae6","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"44f5ab65c1eeb54a53841dc769b749ce7702e32b89a6bd2ddd1a270f63437a50","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"9635dea15d8a885011d2b8b6b9cc5ffe2126cc3f141f47f7aaf46e1f201abea9","src/dynamic/device.rs":"f00305d56cac0636d4cb86cc44ee69c291bfb3d5f6d5e8d745adce9a28a6a1d5","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"b02a3c11b22c896cf66ef206f5d4bb4e24988ecadc29972c572baf347f54aa04","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"bf6318ba3b45b277181b69d715184ff06ffe0173ce44872ad90d55098f04a1ab","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"7f885dd2bc72641d22f8f2e688ebdd857663bfe315f1b5364ea302f99a05adbf","src/gles/device.rs":"07aa761e7a5857fc25caecddc6ed6b0ea970a815feb7343f75cb76bc2196ca01","src/gles/egl.rs":"de77822e37369bb4c41e1efcd92134aa220acf0dd8a251a0d4499dd4d541a547","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"083cd49747aba6272002aba0b0c37e5768cdbc2a1b8bacd1a244ee905d3f7b0f","src/gles/mod.rs":"897365cdd34914a654532c8d9592cb3a3f460bd50ac2b6ba72106a105c12ac10","src/gles/queue.rs":"f0a75fa2431f84feaf9a2cd0ba156ffa011b0ba671b167066d2f9341bde89109","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":"012043474fbf7875224f2464e3202b73302a146da180dfaab259297e0c52ffdd","src/metal/adapter.rs":"1b035bf4e69df1575b215cf5a6578afcf729ac26dbae81cf1344fbae5659f65f","src/metal/command.rs":"1ec1a9e0e1ccf298c2c416b96e60827173e6584c9061b8dd582b7789545ce60a","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"581472ed832c8b0960d61f0a0347dba42b649182a576285367f8198555e63051","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"8721673e6f9e88bca5318ff4286a91e5c441ae607b53940c45bda0d8c053e99d","src/metal/surface.rs":"50c628f0e555f936707e57dbff59bbc9b1b05b10747b8303189b878b6fb28795","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"c0d0b593e890e028deb88cc02a02c87c61f2049b6371cd0c788d3345b306f9a4","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"4d1f9feb3b7fdfa685038acb3f4ae4967de164ce9a09be519cadd837b7a717d9","src/vulkan/command.rs":"e058758398d4ec6fda1d0274d99b92ae541f4263ee804bcb1c42ca96f8610ac0","src/vulkan/conv.rs":"f416df65d0abceff8518c5ac86c1f88102b66e64403494d795691b56328374da","src/vulkan/device.rs":"c31564d96f047c2cd4b583749b1d62bf9bd37f5e4c490c03a6f0498d9b743357","src/vulkan/drm.rs":"09eaa92c6a17e219ee856ffc3fe5f9fe1c15063b4c3dbb7cd20bf2f4f9cac2c7","src/vulkan/instance.rs":"e7d3e7abec8ac8aa582f4facc28668f02dfdc8342cca948f359746851a6c6260","src/vulkan/mod.rs":"22b74c1d6abd542b2790067dd6e80473efa03ec94d4ef9cb4e7ee4498def80a3","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"102266d8e1b9f2ec1decf681bcc9e1a4cbff29533a258f2699fb6c573c434771"},"package":null}
\ No newline at end of file
--- a/third_party/rust/wgpu-hal/Cargo.toml
+++ b/third_party/rust/wgpu-hal/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.82.0"
 name = "wgpu-hal"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = "build.rs"
 autolib = false
 autobins = false
 autoexamples = false
 autotests = false
 autobenches = false
 description = "Hardware abstraction layer for wgpu, the cross-platform, safe, pure-rust graphics API"
@@ -197,30 +197,30 @@ features = [
 optional = true
 default-features = false
 
 [dependencies.log]
 version = "0.4.21"
 optional = true
 
 [dependencies.naga]
-version = "25.0.0"
+version = "26.0.0"
 path = "../naga"
 
 [dependencies.ordered-float]
 version = ">=3, <=5.0"
 optional = true
 default-features = false
 
 [dependencies.parking_lot]
 version = "0.12.3"
 optional = true
 
 [dependencies.profiling]
-version = "1"
+version = "1.0.1"
 optional = true
 default-features = false
 
 [dependencies.raw-window-handle]
 version = "0.6.2"
 default-features = false
 
 [dependencies.rustc-hash]
@@ -228,29 +228,29 @@ version = "1.1"
 optional = true
 default-features = false
 
 [dependencies.thiserror]
 version = "2.0.3"
 default-features = false
 
 [dependencies.wgpu-types]
-version = "25.0.0"
+version = "26.0.0"
 path = "../wgpu-types"
 default-features = false
 
 [dev-dependencies.env_logger]
 version = "0.11"
 default-features = false
 
 [dev-dependencies.glam]
 version = "0.30"
 
 [dev-dependencies.naga]
-version = "25.0.0"
+version = "26.0.0"
 path = "../naga"
 features = [
     "wgsl-in",
     "termcolor",
 ]
 
 [dev-dependencies.winit]
 version = "0.29"
--- a/third_party/rust/wgpu-hal/examples/halmark/main.rs
+++ b/third_party/rust/wgpu-hal/examples/halmark/main.rs
@@ -9,17 +9,19 @@ use raw_window_handle::{HasDisplayHandle
 use winit::{
     event::{ElementState, Event, KeyEvent, WindowEvent},
     event_loop::ControlFlow,
     keyboard::{Key, NamedKey},
 };
 
 use std::{
     borrow::{Borrow, Cow},
-    iter, ptr,
+    iter,
+    num::NonZeroU64,
+    ptr,
     time::Instant,
 };
 
 const MAX_BUNNIES: usize = 1 << 20;
 const BUNNY_SIZE: f32 = 0.15 * 256.0;
 const GRAVITY: f32 = -9.8 * 100.0;
 const MAX_VELOCITY: f32 = 750.0;
 const DESIRED_MAX_LATENCY: u32 = 2;
@@ -440,21 +442,22 @@ impl<A: hal::Api> Example<A> {
             format: texture_desc.format,
             dimension: wgpu_types::TextureViewDimension::D2,
             usage: wgpu_types::TextureUses::RESOURCE,
             range: wgpu_types::ImageSubresourceRange::default(),
         };
         let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() };
 
         let global_group = {
-            let global_buffer_binding = hal::BufferBinding {
-                buffer: &global_buffer,
-                offset: 0,
-                size: None,
-            };
+            // SAFETY: This is the same size that was specified for buffer creation.
+            let global_buffer_binding = hal::BufferBinding::new_unchecked(
+                &global_buffer,
+                0,
+                NonZeroU64::new(global_buffer_desc.size),
+            );
             let texture_binding = hal::TextureBinding {
                 view: &texture_view,
                 usage: wgpu_types::TextureUses::RESOURCE,
             };
             let global_group_desc = hal::BindGroupDescriptor {
                 label: Some("global"),
                 layout: &global_group_layout,
                 buffers: &[global_buffer_binding],
@@ -478,21 +481,22 @@ impl<A: hal::Api> Example<A> {
                         count: 1,
                     },
                 ],
             };
             unsafe { device.create_bind_group(&global_group_desc).unwrap() }
         };
 
         let local_group = {
-            let local_buffer_binding = hal::BufferBinding {
-                buffer: &local_buffer,
-                offset: 0,
-                size: wgpu_types::BufferSize::new(size_of::<Locals>() as _),
-            };
+            // SAFETY: The size must fit within the buffer.
+            let local_buffer_binding = hal::BufferBinding::new_unchecked(
+                &local_buffer,
+                0,
+                wgpu_types::BufferSize::new(size_of::<Locals>() as _),
+            );
             let local_group_desc = hal::BindGroupDescriptor {
                 label: Some("local"),
                 layout: &local_group_layout,
                 buffers: &[local_buffer_binding],
                 samplers: &[],
                 textures: &[],
                 acceleration_structures: &[],
                 entries: &[hal::BindGroupEntry {
--- a/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs
+++ b/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs
@@ -598,20 +598,23 @@ impl<A: hal::Api> Example<A> {
             format: texture_desc.format,
             dimension: wgpu_types::TextureViewDimension::D2,
             usage: wgpu_types::TextureUses::STORAGE_READ_WRITE | wgpu_types::TextureUses::COPY_SRC,
             range: wgpu_types::ImageSubresourceRange::default(),
         };
         let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() };
 
         let bind_group = {
-            let buffer_binding = hal::BufferBinding {
-                buffer: &uniform_buffer,
-                offset: 0,
-                size: None,
+            let buffer_binding = unsafe {
+                // SAFETY: The size matches the buffer allocation.
+                hal::BufferBinding::new_unchecked(
+                    &uniform_buffer,
+                    0,
+                    wgpu_types::BufferSize::new_unchecked(uniforms_size as u64),
+                )
             };
             let texture_binding = hal::TextureBinding {
                 view: &texture_view,
                 usage: wgpu_types::TextureUses::STORAGE_READ_WRITE,
             };
             let group_desc = hal::BindGroupDescriptor {
                 label: Some("bind group"),
                 layout: &bgl,
--- a/third_party/rust/wgpu-hal/src/dx12/command.rs
+++ b/third_party/rust/wgpu-hal/src/dx12/command.rs
@@ -1131,30 +1131,30 @@ impl crate::CommandEncoder for super::Co
 
     unsafe fn set_index_buffer<'a>(
         &mut self,
         binding: crate::BufferBinding<'a, super::Buffer>,
         format: wgt::IndexFormat,
     ) {
         let ibv = Direct3D12::D3D12_INDEX_BUFFER_VIEW {
             BufferLocation: binding.resolve_address(),
-            SizeInBytes: binding.resolve_size() as u32,
+            SizeInBytes: binding.resolve_size().try_into().unwrap(),
             Format: auxil::dxgi::conv::map_index_format(format),
         };
 
         unsafe { self.list.as_ref().unwrap().IASetIndexBuffer(Some(&ibv)) }
     }
     unsafe fn set_vertex_buffer<'a>(
         &mut self,
         index: u32,
         binding: crate::BufferBinding<'a, super::Buffer>,
     ) {
         let vb = &mut self.pass.vertex_buffers[index as usize];
         vb.BufferLocation = binding.resolve_address();
-        vb.SizeInBytes = binding.resolve_size() as u32;
+        vb.SizeInBytes = binding.resolve_size().try_into().unwrap();
         self.pass.dirty_vertex_buffers |= 1 << index;
     }
 
     unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {
         let raw_vp = Direct3D12::D3D12_VIEWPORT {
             TopLeftX: rect.x,
             TopLeftY: rect.y,
             Width: rect.w,
--- a/third_party/rust/wgpu-hal/src/dx12/device.rs
+++ b/third_party/rust/wgpu-hal/src/dx12/device.rs
@@ -1437,17 +1437,17 @@ impl crate::Device for super::Device {
                     ty,
                     has_dynamic_offset,
                     ..
                 } => {
                     let start = entry.resource_index as usize;
                     let end = start + entry.count as usize;
                     for data in &desc.buffers[start..end] {
                         let gpu_address = data.resolve_address();
-                        let mut size = data.resolve_size() as u32;
+                        let mut size = data.resolve_size().try_into().unwrap();
 
                         if has_dynamic_offset {
                             match ty {
                                 wgt::BufferBindingType::Uniform => {
                                     dynamic_buffers.push(super::DynamicBuffer::Uniform(
                                         Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE {
                                             ptr: data.resolve_address(),
                                         },
--- a/third_party/rust/wgpu-hal/src/lib.rs
+++ b/third_party/rust/wgpu-hal/src/lib.rs
@@ -292,17 +292,17 @@ pub use dynamic::{
 
 #[allow(unused)]
 use alloc::boxed::Box;
 use alloc::{borrow::Cow, string::String, vec::Vec};
 use core::{
     borrow::Borrow,
     error::Error,
     fmt,
-    num::NonZeroU32,
+    num::{NonZeroU32, NonZeroU64},
     ops::{Range, RangeInclusive},
     ptr::NonNull,
 };
 
 use bitflags::bitflags;
 use thiserror::Error;
 use wgt::WasmNotSendSync;
 
@@ -1963,21 +1963,28 @@ pub struct PipelineLayoutDescriptor<'a, 
     pub bind_group_layouts: &'a [&'a B],
     pub push_constant_ranges: &'a [wgt::PushConstantRange],
 }
 
 /// A region of a buffer made visible to shaders via a [`BindGroup`].
 ///
 /// [`BindGroup`]: Api::BindGroup
 ///
+/// ## Construction
+///
+/// The recommended way to construct a `BufferBinding` is using the `binding`
+/// method on a wgpu-core `Buffer`, which will validate the binding size
+/// against the buffer size. A `new_unchecked` constructor is also provided for
+/// cases where direct construction is necessary.
+///
 /// ## Accessible region
 ///
 /// `wgpu_hal` guarantees that shaders compiled with
 /// [`ShaderModuleDescriptor::runtime_checks`] set to `true` cannot read or
-/// write data via this binding outside the *accessible region* of [`buffer`]:
+/// write data via this binding outside the *accessible region* of a buffer:
 ///
 /// - The accessible region starts at [`offset`].
 ///
 /// - For [`Storage`] bindings, the size of the accessible region is [`size`],
 ///   which must be a multiple of 4.
 ///
 /// - For [`Uniform`] bindings, the size of the accessible region is [`size`]
 ///   rounded up to the next multiple of
@@ -1987,58 +1994,128 @@ pub struct PipelineLayoutDescriptor<'a, 
 /// [out-of-bounds accesses][woob], as WGSL allows them to return values from
 /// elsewhere in the buffer. But this guarantee is necessary anyway, to permit
 /// `wgpu-core` to avoid clearing uninitialized regions of buffers that will
 /// never be read by the application before they are overwritten. This
 /// optimization consults bind group buffer binding regions to determine which
 /// parts of which buffers shaders might observe. This optimization is only
 /// sound if shader access is bounds-checked.
 ///
-/// [`buffer`]: BufferBinding::buffer
+/// ## Zero-length bindings
+///
+/// Some back ends cannot tolerate zero-length regions; for example, see
+/// [VUID-VkDescriptorBufferInfo-offset-00340][340] and
+/// [VUID-VkDescriptorBufferInfo-range-00341][341], or the
+/// documentation for GLES's [glBindBufferRange][bbr]. This documentation
+/// previously stated that a `BufferBinding` must have `offset` strictly less
+/// than the size of the buffer, but this restriction was not honored elsewhere
+/// in the code, so has been removed. However, it remains the case that
+/// some backends do not support zero-length bindings, so additional
+/// logic is needed somewhere to handle this properly. See
+/// [#3170](https://github.com/gfx-rs/wgpu/issues/3170).
+///
 /// [`offset`]: BufferBinding::offset
 /// [`size`]: BufferBinding::size
 /// [`Storage`]: wgt::BufferBindingType::Storage
 /// [`Uniform`]: wgt::BufferBindingType::Uniform
+/// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340
+/// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341
+/// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml
 /// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec
 #[derive(Debug)]
 pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
     /// The buffer being bound.
-    pub buffer: &'a B,
+    ///
+    /// This is not fully `pub` to prevent direct construction of
+    /// `BufferBinding`s, while still allowing public read access to the `offset`
+    /// and `size` properties.
+    pub(crate) buffer: &'a B,
 
     /// The offset at which the bound region starts.
     ///
-    /// This must be less than the size of the buffer. Some back ends
-    /// cannot tolerate zero-length regions; for example, see
-    /// [VUID-VkDescriptorBufferInfo-offset-00340][340] and
-    /// [VUID-VkDescriptorBufferInfo-range-00341][341], or the
-    /// documentation for GLES's [glBindBufferRange][bbr].
-    ///
-    /// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340
-    /// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341
-    /// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml
+    /// This must be less or equal to the size of the buffer.
     pub offset: wgt::BufferAddress,
 
     /// The size of the region bound, in bytes.
     ///
     /// If `None`, the region extends from `offset` to the end of the
     /// buffer. Given the restrictions on `offset`, this means that
     /// the size is always greater than zero.
     pub size: Option<wgt::BufferSize>,
 }
 
-impl<'a, T: DynBuffer + ?Sized> Clone for BufferBinding<'a, T> {
+// We must implement this manually because `B` is not necessarily `Clone`.
+impl<B: DynBuffer + ?Sized> Clone for BufferBinding<'_, B> {
     fn clone(&self) -> Self {
         BufferBinding {
             buffer: self.buffer,
             offset: self.offset,
             size: self.size,
         }
     }
 }
 
+/// Temporary convenience trait to let us call `.get()` on `u64`s in code that
+/// really wants to be using `NonZeroU64`.
+/// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove this
+pub trait ShouldBeNonZeroExt {
+    fn get(&self) -> u64;
+}
+
+impl ShouldBeNonZeroExt for NonZeroU64 {
+    fn get(&self) -> u64 {
+        NonZeroU64::get(*self)
+    }
+}
+
+impl ShouldBeNonZeroExt for u64 {
+    fn get(&self) -> u64 {
+        *self
+    }
+}
+
+impl ShouldBeNonZeroExt for Option<NonZeroU64> {
+    fn get(&self) -> u64 {
+        match *self {
+            Some(non_zero) => non_zero.get(),
+            None => 0,
+        }
+    }
+}
+
+impl<'a, B: DynBuffer + ?Sized> BufferBinding<'a, B> {
+    /// Construct a `BufferBinding` with the given contents.
+    ///
+    /// When possible, use the `binding` method on a wgpu-core `Buffer` instead
+    /// of this method. `Buffer::binding` validates the size of the binding
+    /// against the size of the buffer.
+    ///
+    /// It is more difficult to provide a validating constructor here, due to
+    /// not having direct access to the size of a `DynBuffer`.
+    ///
+    /// SAFETY: The caller is responsible for ensuring that a binding of `size`
+    /// bytes starting at `offset` is contained within the buffer.
+    ///
+    /// The `S` type parameter is a temporary convenience to allow callers to
+    /// pass a zero size. When the zero-size binding issue is resolved, the
+    /// argument should just match the type of the member.
+    /// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove the parameter
+    pub fn new_unchecked<S: Into<Option<NonZeroU64>>>(
+        buffer: &'a B,
+        offset: wgt::BufferAddress,
+        size: S,
+    ) -> Self {
+        Self {
+            buffer,
+            offset,
+            size: size.into(),
+        }
+    }
+}
+
 #[derive(Debug)]
 pub struct TextureBinding<'a, T: DynTextureView + ?Sized> {
     pub view: &'a T,
     pub usage: wgt::TextureUses,
 }
 
 impl<'a, T: DynTextureView + ?Sized> Clone for TextureBinding<'a, T> {
     fn clone(&self) -> Self {
--- a/third_party/rust/wgpu-hal/src/vulkan/device.rs
+++ b/third_party/rust/wgpu-hal/src/vulkan/device.rs
@@ -803,27 +803,16 @@ impl super::Device {
             drop_guard: None,
             external_memory: Some(memory),
             block: None,
             format: desc.format,
             copy_size: image.copy_size,
         })
     }
 
-    /// # Safety
-    ///
-    /// - `vk_buffer`'s memory must be managed by the caller
-    /// - Externally imported buffers can't be mapped by `wgpu`
-    pub unsafe fn buffer_from_raw(vk_buffer: vk::Buffer) -> super::Buffer {
-        super::Buffer {
-            raw: vk_buffer,
-            block: None,
-        }
-    }
-
     fn create_shader_module_impl(
         &self,
         spv: &[u32],
     ) -> Result<vk::ShaderModule, crate::DeviceError> {
         let vk_info = vk::ShaderModuleCreateInfo::default()
             .flags(vk::ShaderModuleCreateFlags::empty())
             .code(spv);
 
@@ -1148,25 +1137,32 @@ impl crate::Device for super::Device {
             unsafe { self.shared.set_object_name(raw, label) };
         }
 
         self.counters.buffer_memory.add(block.size() as isize);
         self.counters.buffers.add(1);
 
         Ok(super::Buffer {
             raw,
-            block: Some(Mutex::new(block)),
+            block: Some(Mutex::new(super::BufferMemoryBacking::Managed(block))),
         })
     }
     unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
         unsafe { self.shared.raw.destroy_buffer(buffer.raw, None) };
         if let Some(block) = buffer.block {
             let block = block.into_inner();
             self.counters.buffer_memory.sub(block.size() as isize);
-            unsafe { self.mem_allocator.lock().dealloc(&*self.shared, block) };
+            match block {
+                super::BufferMemoryBacking::Managed(block) => unsafe {
+                    self.mem_allocator.lock().dealloc(&*self.shared, block)
+                },
+                super::BufferMemoryBacking::VulkanMemory { memory, .. } => unsafe {
+                    self.shared.raw.free_memory(memory, None);
+                },
+            }
         }
 
         self.counters.buffers.sub(1);
     }
 
     unsafe fn add_raw_buffer(&self, _buffer: &super::Buffer) {
         self.counters.buffers.add(1);
     }
@@ -1174,28 +1170,37 @@ impl crate::Device for super::Device {
     unsafe fn map_buffer(
         &self,
         buffer: &super::Buffer,
         range: crate::MemoryRange,
     ) -> Result<crate::BufferMapping, crate::DeviceError> {
         if let Some(ref block) = buffer.block {
             let size = range.end - range.start;
             let mut block = block.lock();
-            let ptr = unsafe { block.map(&*self.shared, range.start, size as usize)? };
-            let is_coherent = block
-                .props()
-                .contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT);
-            Ok(crate::BufferMapping { ptr, is_coherent })
+            if let super::BufferMemoryBacking::Managed(ref mut block) = *block {
+                let ptr = unsafe { block.map(&*self.shared, range.start, size as usize)? };
+                let is_coherent = block
+                    .props()
+                    .contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT);
+                Ok(crate::BufferMapping { ptr, is_coherent })
+            } else {
+                crate::hal_usage_error("tried to map externally created buffer")
+            }
         } else {
             crate::hal_usage_error("tried to map external buffer")
         }
     }
     unsafe fn unmap_buffer(&self, buffer: &super::Buffer) {
         if let Some(ref block) = buffer.block {
-            unsafe { block.lock().unmap(&*self.shared) };
+            match &mut *block.lock() {
+                super::BufferMemoryBacking::Managed(block) => unsafe { block.unmap(&*self.shared) },
+                super::BufferMemoryBacking::VulkanMemory { .. } => {
+                    crate::hal_usage_error("tried to unmap externally created buffer")
+                }
+            };
         } else {
             crate::hal_usage_error("tried to unmap external buffer")
         }
     }
 
     unsafe fn flush_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I)
     where
         I: Iterator<Item = crate::MemoryRange>,
--- a/third_party/rust/wgpu-hal/src/vulkan/mod.rs
+++ b/third_party/rust/wgpu-hal/src/vulkan/mod.rs
@@ -771,21 +771,80 @@ impl Queue {
     }
 }
 
 impl Drop for Queue {
     fn drop(&mut self) {
         unsafe { self.relay_semaphores.lock().destroy(&self.device.raw) };
     }
 }
-
+#[derive(Debug)]
+enum BufferMemoryBacking {
+    Managed(gpu_alloc::MemoryBlock<vk::DeviceMemory>),
+    VulkanMemory {
+        memory: vk::DeviceMemory,
+        offset: u64,
+        size: u64,
+    },
+}
+impl BufferMemoryBacking {
+    fn memory(&self) -> &vk::DeviceMemory {
+        match self {
+            Self::Managed(m) => m.memory(),
+            Self::VulkanMemory { memory, .. } => memory,
+        }
+    }
+    fn offset(&self) -> u64 {
+        match self {
+            Self::Managed(m) => m.offset(),
+            Self::VulkanMemory { offset, .. } => *offset,
+        }
+    }
+    fn size(&self) -> u64 {
+        match self {
+            Self::Managed(m) => m.size(),
+            Self::VulkanMemory { size, .. } => *size,
+        }
+    }
+}
 #[derive(Debug)]
 pub struct Buffer {
     raw: vk::Buffer,
-    block: Option<Mutex<gpu_alloc::MemoryBlock<vk::DeviceMemory>>>,
+    block: Option<Mutex<BufferMemoryBacking>>,
+}
+impl Buffer {
+    /// # Safety
+    ///
+    /// - `vk_buffer`'s memory must be managed by the caller
+    /// - Externally imported buffers can't be mapped by `wgpu`
+    pub unsafe fn from_raw(vk_buffer: vk::Buffer) -> Self {
+        Self {
+            raw: vk_buffer,
+            block: None,
+        }
+    }
+    /// # Safety
+    /// - We will use this buffer and the buffer's backing memory range as if we have exclusive ownership over it, until the wgpu resource is dropped and the wgpu-hal object is cleaned up
+    /// - Externally imported buffers can't be mapped by `wgpu`
+    /// - `offset` and `size` must be valid with the allocation of `memory`
+    pub unsafe fn from_raw_managed(
+        vk_buffer: vk::Buffer,
+        memory: vk::DeviceMemory,
+        offset: u64,
+        size: u64,
+    ) -> Self {
+        Self {
+            raw: vk_buffer,
+            block: Some(Mutex::new(BufferMemoryBacking::VulkanMemory {
+                memory,
+                offset,
+                size,
+            })),
+        }
+    }
 }
 
 impl crate::DynBuffer for Buffer {}
 
 #[derive(Debug)]
 pub struct AccelerationStructure {
     raw: vk::AccelerationStructureKHR,
     buffer: vk::Buffer,
--- a/third_party/rust/wgpu-types/.cargo-checksum.json
+++ b/third_party/rust/wgpu-types/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"8202270e283ceac9e9ea19937413a5bbc2f7380a9aa87710fb0bc3e06a991a73","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"be6930dfba6465fb84f43ac41d3e62f49a2be607ade17904dd7e49f69caef678","src/instance.rs":"984b152b4653142516b82bc5c3b8bb5e112603d19cf09aa38ede2ca5eb91d706","src/lib.rs":"05a1bdb8141d98f7b9294f89ad522a86cfef78d564507cf96d44e28d3adba5b1","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/transfers.rs":"66fbca652e04751f7912d1b75f009d1f6ad83d41ed6c624ca7f7c34b26b480b3"},"package":null}
\ No newline at end of file
+{"files":{"Cargo.toml":"1c4e4f9ab000d2ff511c6e9f2bccfc1469ac9c5d7b40798b2422a67910e3118a","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"be6930dfba6465fb84f43ac41d3e62f49a2be607ade17904dd7e49f69caef678","src/instance.rs":"984b152b4653142516b82bc5c3b8bb5e112603d19cf09aa38ede2ca5eb91d706","src/lib.rs":"05a1bdb8141d98f7b9294f89ad522a86cfef78d564507cf96d44e28d3adba5b1","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null}
\ No newline at end of file
--- a/third_party/rust/wgpu-types/Cargo.toml
+++ b/third_party/rust/wgpu-types/Cargo.toml
@@ -8,17 +8,17 @@
 # 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 = "2021"
 rust-version = "1.82.0"
 name = "wgpu-types"
-version = "25.0.0"
+version = "26.0.0"
 authors = ["gfx-rs developers"]
 build = false
 autolib = false
 autobins = false
 autoexamples = false
 autotests = false
 autobenches = false
 description = "Common types and utilities for wgpu, the cross-platform, safe, pure-rust graphics API"
--- a/third_party/rust/wgpu-types/src/transfers.rs
+++ b/third_party/rust/wgpu-types/src/transfers.rs
@@ -1,52 +1,87 @@
 use crate::{BufferAddress, Extent3d, TexelCopyBufferLayout, TextureAspect, TextureFormat};
 
 impl TexelCopyBufferLayout {
     /// Extract a variety of information about the given copy operation.
+    ///
+    /// Returns an error if the size of the copy overflows a `u64`, or if the arguments are
+    /// not valid in conjunction with the `bytes_per_row` or `rows_per_image` parameters in
+    /// `self`.
+    ///
+    /// This is public for use by `wgpu-core` and `wgpu-hal`, it is not a stable API.
+    ///
+    /// Although WebGPU requires that `bytes_per_row` and `rows_per_image` be specified in
+    /// cases where they apply, we are more lenient here (although it's not clear if that is
+    /// necessary). Our caller, `validate_linear_texture_data`, enforces this and other
+    /// WebGPU requirements on the copy parameters that we do not check here.
+    #[doc(hidden)]
     #[inline(always)]
     pub fn get_buffer_texture_copy_info(
         &self,
         format: TextureFormat,
         aspect: TextureAspect,
         copy_size: &Extent3d,
-    ) -> BufferTextureCopyInfo {
-        // Convert all inputs to BufferAddress (u64) to avoid some of the overflow issues
-        // Note: u64 is not always enough to prevent overflow, especially when multiplying
-        // something with a potentially large depth value, so it is preferable to validate
-        // the copy size before calling this function (for example via `validate_texture_copy_range`).
-        let copy_width = copy_size.width as BufferAddress;
-        let copy_height = copy_size.height as BufferAddress;
-        let depth_or_array_layers = copy_size.depth_or_array_layers as BufferAddress;
+    ) -> Result<BufferTextureCopyInfo, Error> {
+        let copy_width = BufferAddress::from(copy_size.width);
+        let copy_height = BufferAddress::from(copy_size.height);
+        let depth_or_array_layers = BufferAddress::from(copy_size.depth_or_array_layers);
 
-        let block_size_bytes = format.block_copy_size(Some(aspect)).unwrap() as BufferAddress;
+        let block_size_bytes = BufferAddress::from(format.block_copy_size(Some(aspect)).unwrap());
         let (block_width, block_height) = format.block_dimensions();
-        let block_width_texels = block_width as BufferAddress;
-        let block_height_texels = block_height as BufferAddress;
+        let block_width_texels = BufferAddress::from(block_width);
+        let block_height_texels = BufferAddress::from(block_height);
 
         let width_blocks = copy_width.div_ceil(block_width_texels);
         let height_blocks = copy_height.div_ceil(block_height_texels);
 
+        // The spec calls this bytesInLastRow.
         let row_bytes_dense = width_blocks * block_size_bytes;
-
-        let row_stride_bytes = self.bytes_per_row.map_or(row_bytes_dense, u64::from);
-        let image_stride_rows = self.rows_per_image.map_or(height_blocks, u64::from);
-
-        let image_stride_bytes = row_stride_bytes * image_stride_rows;
+        let row_stride_bytes = match self.bytes_per_row.map(BufferAddress::from) {
+            Some(bytes_per_row) if bytes_per_row >= row_bytes_dense => bytes_per_row,
+            Some(_) => return Err(Error::InvalidBytesPerRow),
+            None => row_bytes_dense,
+        };
 
         let image_rows_dense = height_blocks;
-        let image_bytes_dense =
-            image_rows_dense.saturating_sub(1) * row_stride_bytes + row_bytes_dense;
+        let image_stride_rows = match self.rows_per_image.map(BufferAddress::from) {
+            Some(rows_per_image) if rows_per_image >= image_rows_dense => rows_per_image,
+            Some(_) => return Err(Error::InvalidRowsPerImage),
+            None => image_rows_dense,
+        };
+
+        let image_bytes_dense = match image_rows_dense.checked_sub(1) {
+            Some(rows_minus_one) => rows_minus_one
+                .checked_mul(row_stride_bytes)
+                .ok_or(Error::ImageBytesOverflow(false))?
+                .checked_add(row_bytes_dense)
+                .ok_or(Error::ImageBytesOverflow(true))?,
+            None => 0,
+        };
 
-        let mut bytes_in_copy = image_stride_bytes * depth_or_array_layers.saturating_sub(1);
-        if height_blocks > 0 {
-            bytes_in_copy += row_stride_bytes * (height_blocks - 1) + row_bytes_dense;
-        }
+        // It is possible that `image_stride_bytes` overflows, but the actual
+        // copy size does not, when the copy only has a single layer and
+        // `image_size_bytes` is not used. We don't worry about handling this
+        // gracefully because WebGPU texture size limits should keep things out
+        // of this realm entirely.
+        let image_stride_bytes = row_stride_bytes
+            .checked_mul(image_stride_rows)
+            .ok_or(Error::ImageStrideOverflow)?;
 
-        BufferTextureCopyInfo {
+        let bytes_in_copy = if depth_or_array_layers <= 1 {
+            depth_or_array_layers * image_bytes_dense
+        } else {
+            (depth_or_array_layers - 1)
+                .checked_mul(image_stride_bytes)
+                .ok_or(Error::ArraySizeOverflow(false))?
+                .checked_add(image_bytes_dense)
+                .ok_or(Error::ArraySizeOverflow(true))?
+        };
+
+        Ok(BufferTextureCopyInfo {
             copy_width,
             copy_height,
             depth_or_array_layers,
 
             offset: self.offset,
 
             block_size_bytes,
             block_width_texels,
@@ -60,17 +95,17 @@ impl TexelCopyBufferLayout {
 
             image_stride_rows,
             image_stride_bytes,
 
             image_rows_dense,
             image_bytes_dense,
 
             bytes_in_copy,
-        }
+        })
     }
 }
 
 /// Information about a copy between a buffer and a texture.
 ///
 /// Mostly used for internal calculations, but useful nonetheless.
 /// Generated by [`TexelCopyBufferLayout::get_buffer_texture_copy_info`].
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -122,35 +157,78 @@ pub struct BufferTextureCopyInfo {
     pub image_bytes_dense: u64,
 
     /// The total number of bytes in the copy region.
     ///
     /// This includes all padding except the padding after the last row in the copy.
     pub bytes_in_copy: u64,
 }
 
+/// Errors that can occur while populating `BufferTextureCopyInfo`.
+//
+// We use the additional detail provided by these errors (over wgpu-core's
+// `TransferError`) to improve the reliability of the tests in this module. It
+// doesn't seem worth plumbing them upwards, because at the API level it
+// shouldn't be possible to exceed them without exceeding the WebGPU limits on
+// texture dimension. But the WebGPU limits are not currently enforced, so we
+// have to do something here to protect against overflows.
+//
+// Even when the WebGPU limits are enforced, it may still be useful to keep the
+// checks here as a failsafe if the correctness of the primary limit enforcement
+// is not immediately apparent.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum BufferTextureCopyInfoError {
+    /// The `bytes_per_row` is too small for the texture width.
+    InvalidBytesPerRow,
+    /// The `rows_per_image` is too small for the texture height.
+    InvalidRowsPerImage,
+    /// The image stride overflows a `u64`.
+    ImageStrideOverflow,
+    /// The last-layer byte size overflows a `u64`.
+    ///
+    /// The bool value indicates whether the multiplication (false) or the
+    /// addition (true) overflowed.
+    ImageBytesOverflow(bool),
+    /// The total size of the copy overflows a `u64`.
+    ///
+    /// The bool value indicates whether the multiplication (false) or the
+    /// addition (true) overflowed.
+    ArraySizeOverflow(bool),
+}
+type Error = BufferTextureCopyInfoError;
+
 #[cfg(test)]
 mod tests {
     use super::*;
 
+    #[derive(Clone)]
     struct LTDTest {
         layout: TexelCopyBufferLayout,
         format: TextureFormat,
         aspect: TextureAspect,
         copy_size: Extent3d,
         expected_result: BufferTextureCopyInfo,
+        // Normally a Result<BufferTextureCopyInfo, Error> would be make sense,
+        // but since the existing tests were written to mutate
+        // `LTDTest.expected_result`, keeping this separate avoids a bunch of
+        // `unwrap`s.
+        expected_error: Option<Error>,
     }
 
     impl LTDTest {
         #[track_caller]
         fn run(&self) {
             let linear_texture_data =
                 self.layout
                     .get_buffer_texture_copy_info(self.format, self.aspect, &self.copy_size);
-            assert_eq!(linear_texture_data, self.expected_result);
+            let expected = match self.expected_error {
+                Some(err) => Err(err),
+                None => Ok(self.expected_result),
+            };
+            assert_eq!(linear_texture_data, expected);
         }
     }
 
     #[test]
     fn linear_texture_data_1d_copy() {
         let mut test = LTDTest {
             layout: TexelCopyBufferLayout {
                 offset: 0,
@@ -177,16 +255,17 @@ mod tests {
                 row_bytes_dense: 16,
                 row_stride_bytes: 16,
                 image_stride_rows: 1,
                 image_stride_bytes: 16,
                 image_rows_dense: 1,
                 image_bytes_dense: 16,
                 bytes_in_copy: 16,
             },
+            expected_error: None,
         };
 
         test.run();
 
         // Changing bytes_per_row should only change the bytes_per_row, not the bytes_in_copy
         // as that is only affected by the last row size.
         test.layout.bytes_per_row = Some(32);
         test.expected_result.row_stride_bytes = 32;
@@ -206,17 +285,17 @@ mod tests {
         test.layout.offset = 4;
         test.expected_result.offset = 4;
 
         test.run();
     }
 
     #[test]
     fn linear_texture_data_2d_3d_copy() {
-        let mut test = LTDTest {
+        let template = LTDTest {
             layout: TexelCopyBufferLayout {
                 offset: 0,
                 bytes_per_row: None,
                 rows_per_image: None,
             },
             format: TextureFormat::Rgba8Unorm,
             aspect: TextureAspect::All,
             copy_size: Extent3d {
@@ -237,32 +316,93 @@ mod tests {
                 row_bytes_dense: 4 * 7,
                 row_stride_bytes: 4 * 7,
                 image_stride_rows: 12,
                 image_stride_bytes: 4 * 7 * 12,
                 image_rows_dense: 12,
                 image_bytes_dense: 4 * 7 * 12,
                 bytes_in_copy: 4 * 7 * 12,
             },
+            expected_error: None,
         };
 
+        let mut test = template.clone();
         test.run();
 
         // Changing bytes_per_row changes a number of other properties.
         test.layout.bytes_per_row = Some(48);
         test.expected_result.row_stride_bytes = 48;
         test.expected_result.image_stride_bytes = 48 * 12;
         test.expected_result.image_bytes_dense = 48 * 11 + (4 * 7);
         test.expected_result.bytes_in_copy = 48 * 11 + (4 * 7);
+        test.run();
 
         // Making this a 3D copy only changes the depth_or_array_layers and the bytes_in_copy.
         test.copy_size.depth_or_array_layers = 4;
         test.expected_result.depth_or_array_layers = 4;
         test.expected_result.bytes_in_copy = 48 * 12 * 3 + 48 * 11 + (4 * 7); // 4 layers
+        test.run();
 
+        // Changing rows_per_image
+        test.layout.rows_per_image = Some(20);
+        test.expected_result.image_stride_rows = 20;
+        test.expected_result.image_stride_bytes = 20 * test.expected_result.row_stride_bytes;
+        test.expected_result.bytes_in_copy = 48 * 20 * 3 + 48 * 11 + (4 * 7); // 4 layers
+        test.run();
+
+        // Invalid because the row stride is too small.
+        let mut test = template.clone();
+        test.layout.bytes_per_row = Some(20);
+        test.expected_error = Some(Error::InvalidBytesPerRow);
+        test.run();
+
+        // Invalid because the image stride is too small.
+        let mut test = template.clone();
+        test.layout.rows_per_image = Some(8);
+        test.expected_error = Some(Error::InvalidRowsPerImage);
+        test.run();
+
+        // Invalid because width * height * texel_size_bytes overflows.
+        let mut test = template.clone();
+        test.copy_size.width = u32::MAX;
+        test.copy_size.height = u32::MAX;
+        test.expected_error = Some(Error::ImageBytesOverflow(false));
+        test.run();
+
+        // Invalid because the addition of row_bytes_dense overflows.
+        // (But the product rows_minus_one * row_stride_bytes does not overflow.)
+        let mut test = template.clone();
+        test.copy_size.width = 0x8000_0000;
+        test.copy_size.height = 0x8000_0000;
+        test.expected_error = Some(Error::ImageBytesOverflow(true));
+        test.run();
+
+        // Invalid because image_stride_bytes overflows.
+        let mut test = template.clone();
+        test.copy_size.width = 0x8000_0000;
+        test.layout.rows_per_image = Some(0x8000_0000);
+        test.expected_result.image_stride_rows = 0x8000_0000;
+        test.expected_error = Some(Error::ImageStrideOverflow);
+        test.run();
+
+        // Invalid because (layers - 1) * image_stride_bytes overflows.
+        let mut test = template.clone();
+        test.copy_size.depth_or_array_layers = 0x8000_0000;
+        test.copy_size.width = 0x1_0000;
+        test.copy_size.height = 0x1_0000;
+        test.expected_error = Some(Error::ArraySizeOverflow(false));
+        test.run();
+
+        // Invalid because the total size of the copy overflows (but the product
+        // (layers - 1) * image_stride_bytes does not overflow).
+        let mut test = template.clone();
+        test.copy_size.depth_or_array_layers = 0x3fff_8001;
+        test.copy_size.width = 0x1_0001;
+        test.copy_size.height = 0x1_0001;
+        test.expected_error = Some(Error::ArraySizeOverflow(true));
         test.run();
     }
 
     #[test]
     fn linear_texture_data_2d_3d_compressed_copy() {
         let mut test = LTDTest {
             layout: TexelCopyBufferLayout {
                 offset: 0,
@@ -289,16 +429,17 @@ mod tests {
                 row_bytes_dense: 8 * 2, // block size * width_blocks
                 row_stride_bytes: 8 * 2,
                 image_stride_rows: 4,
                 image_stride_bytes: 8 * 2 * 4, // block size * width_blocks * height_blocks
                 image_rows_dense: 4,
                 image_bytes_dense: 8 * 2 * 4,
                 bytes_in_copy: 8 * 2 * 4,
             },
+            expected_error: None,
         };
 
         test.run();
 
         // Changing bytes_per_row.
         test.layout.bytes_per_row = Some(48);
         test.expected_result.row_stride_bytes = 48;
         test.expected_result.image_stride_bytes = 48 * 4;