Repository: gfx-rs/wgpu
Pull request #5564 (2024-04-19 16:02:37)

[naga] add `Expression::Override` to `needs_pre_emit`
We need to add `Expression::Override` to `needs_pre_emit` or else we get `ExpressionError::NotInScope` on the updated snapshot.


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9dd8086d9..735759e79 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -623,7 +623,7 @@ jobs:
           cargo fmt --manifest-path xtask/Cargo.toml -- --check
 
       - name: Check for typos
-        uses: crate-ci/typos@v1.20.8
+        uses: crate-ci/typos@v1.20.9
 
   check-cts-runner:
     # runtime is normally 2 minutes
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index ceecbb703..9017220fe 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -41,7 +41,7 @@ jobs:
         if: ${{ failure() }}
 
       - name: Deploy the docs
-        uses: JamesIves/github-pages-deploy-action@v4.5.0
+        uses: JamesIves/github-pages-deploy-action@v4.6.0
         if: github.ref == 'refs/heads/trunk'
         with:
           token: ${{ secrets.WEB_DEPLOY }}
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 6dfed56f6..258c788a4 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -41,7 +41,7 @@ jobs:
         run: cargo xtask run-wasm --no-serve
 
       - name: Deploy WebGPU examples
-        uses: JamesIves/github-pages-deploy-action@v4.5.0
+        uses: JamesIves/github-pages-deploy-action@v4.6.0
         if: github.ref == 'refs/heads/trunk'
         with:
           token: ${{ secrets.WEB_DEPLOY }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e01cac176..e7538ed4b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -128,6 +128,7 @@ Bottom level categories:
 - Log an error when GLES texture format heuristics fail. By @PolyMeilex in [#5266](https://github.com/gfx-rs/wgpu/issues/5266)
 - Cache the sample count to keep `get_texture_format_features` cheap. By @Dinnerbone in [#5346](https://github.com/gfx-rs/wgpu/pull/5346)
 - Mark `DEPTH32FLOAT_STENCIL8` as supported in GLES. By @Dinnerbone in [#5370](https://github.com/gfx-rs/wgpu/pull/5370)
+- Desktop GL now also supports `TEXTURE_COMPRESSION_ETC2`. By @Valaphee in [#5568](https://github.com/gfx-rs/wgpu/pull/5568)
 
 #### Naga
 
diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs
index 549bce694..93aac5b3e 100644
--- a/naga/src/proc/mod.rs
+++ b/naga/src/proc/mod.rs
@@ -508,6 +508,7 @@ impl crate::Expression {
         match *self {
             Self::Literal(_)
             | Self::Constant(_)
+            | Self::Override(_)
             | Self::ZeroValue(_)
             | Self::FunctionArgument(_)
             | Self::GlobalVariable(_)
diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs
index 46e5960ce..e898ccdce 100644
--- a/wgpu-core/src/registry.rs
+++ b/wgpu-core/src/registry.rs
@@ -38,6 +38,7 @@ impl RegistryReport {
 ///
 #[derive(Debug)]
 pub(crate) struct Registry<T: Resource> {
+    // Must only contain an id which has either never been used or has been released from `storage`
     identity: Arc<IdentityManager<T::Marker>>,
     storage: RwLock<Storage<T>>,
     backend: Backend,
@@ -162,8 +163,11 @@ impl<T: Resource> Registry<T> {
         storage.insert_error(id, label);
     }
     pub(crate) fn unregister(&self, id: Id<T::Marker>) -> Option<Arc<T>> {
-        self.identity.free(id);
         let value = self.storage.write().remove(id);
+        // This needs to happen *after* removing it from the storage, to maintain the
+        // invariant that `self.identity` only contains ids which are actually available
+        // See https://github.com/gfx-rs/wgpu/issues/5372
+        self.identity.free(id);
         //Returning None is legal if it's an error ID
         value
     }
@@ -206,3 +210,53 @@ impl<T: Resource> Registry<T> {
         report
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use std::sync::Arc;
+
+    use crate::{
+        id::Marker,
+        resource::{Resource, ResourceInfo, ResourceType},
+    };
+
+    use super::Registry;
+    struct TestData {
+        info: ResourceInfo<TestData>,
+    }
+    struct TestDataId;
+    impl Marker for TestDataId {}
+
+    impl Resource for TestData {
+        type Marker = TestDataId;
+
+        const TYPE: ResourceType = "Test data";
+
+        fn as_info(&self) -> &ResourceInfo<Self> {
+            &self.info
+        }
+
+        fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
+            &mut self.info
+        }
+    }
+
+    #[test]
+    fn simultaneous_registration() {
+        let registry = Registry::without_backend();
+        std::thread::scope(|s| {
+            for _ in 0..5 {
+                s.spawn(|| {
+                    for _ in 0..1000 {
+                        let value = Arc::new(TestData {
+                            info: ResourceInfo::new("Test data", None),
+                        });
+                        let new_id = registry.prepare(None);
+                        let (id, _) = new_id.assign(value);
+                        registry.unregister(id);
+                    }
+                });
+            }
+        })
+    }
+}
diff --git a/wgpu-core/src/snatch.rs b/wgpu-core/src/snatch.rs
index d5cd1a3d3..80221aeaa 100644
--- a/wgpu-core/src/snatch.rs
+++ b/wgpu-core/src/snatch.rs
@@ -64,8 +64,58 @@ impl<T> std::fmt::Debug for Snatchable<T> {
 
 unsafe impl<T> Sync for Snatchable<T> {}
 
+struct LockTrace {
+    purpose: &'static str,
+    caller: &'static Location<'static>,
+    backtrace: Backtrace,
+}
+
+impl std::fmt::Display for LockTrace {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "a {} lock at {}\n{}",
+            self.purpose, self.caller, self.backtrace
+        )
+    }
+}
+
+#[cfg(debug_assertions)]
+impl LockTrace {
+    #[track_caller]
+    fn enter(purpose: &'static str) {
+        let new = LockTrace {
+            purpose,
+            caller: Location::caller(),
+            backtrace: Backtrace::capture(),
+        };
+
+        if let Some(prev) = SNATCH_LOCK_TRACE.take() {
+            let current = thread::current();
+            let name = current.name().unwrap_or("<unnamed>");
+            panic!(
+                "thread '{name}' attempted to acquire a snatch lock recursively.\n\
+                 - Currently trying to acquire {new}\n\
+                 - Previously acquired {prev}",
+            );
+        } else {
+            SNATCH_LOCK_TRACE.set(Some(new));
+        }
+    }
+
+    fn exit() {
+        SNATCH_LOCK_TRACE.take();
+    }
+}
+
+#[cfg(not(debug_assertions))]
+impl LockTrace {
+    fn enter(purpose: &'static str) {}
+    fn exit() {}
+}
+
 thread_local! {
-    static READ_LOCK_LOCATION: Cell<Option<(&'static Location<'static>, Backtrace)>> = const { Cell::new(None) };
+    static SNATCH_LOCK_TRACE: Cell<Option<LockTrace>> = const { Cell::new(None) };
 }
 
 /// A Device-global lock for all snatchable data.
@@ -87,22 +137,7 @@ impl SnatchLock {
     /// Request read access to snatchable resources.
     #[track_caller]
     pub fn read(&self) -> SnatchGuard {
-        if cfg!(debug_assertions) {
-            let caller = Location::caller();
-            let backtrace = Backtrace::capture();
-            if let Some((prev, bt)) = READ_LOCK_LOCATION.take() {
-                let current = thread::current();
-                let name = current.name().unwrap_or("<unnamed>");
-                panic!(
-                    "thread '{name}' attempted to acquire a snatch read lock recursively.\n
-                    - {prev}\n{bt}\n
-                    - {caller}\n{backtrace}"
-                );
-            } else {
-                READ_LOCK_LOCATION.set(Some((caller, backtrace)));
-            }
-        }
-
+        LockTrace::enter("read");
         SnatchGuard(self.lock.read())
     }
 
@@ -111,14 +146,21 @@ 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())
     }
 }
 
 impl Drop for SnatchGuard<'_> {
     fn drop(&mut self) {
-        #[cfg(debug_assertions)]
-        READ_LOCK_LOCATION.take();
+        LockTrace::exit();
+    }
+}
+
+impl Drop for ExclusiveSnatchGuard<'_> {
+    fn drop(&mut self) {
+        LockTrace::exit();
     }
 }
diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs
index 408c6b3c0..faf25cc85 100644
--- a/wgpu-hal/src/dx12/adapter.rs
+++ b/wgpu-hal/src/dx12/adapter.rs
@@ -115,23 +115,6 @@ impl super::Adapter {
             )
         });
 
-        let mut shader_model_support: d3d12_ty::D3D12_FEATURE_DATA_SHADER_MODEL =
-            d3d12_ty::D3D12_FEATURE_DATA_SHADER_MODEL {
-                HighestShaderModel: d3d12_ty::D3D_SHADER_MODEL_6_0,
-            };
-        assert_eq!(0, unsafe {
-            device.CheckFeatureSupport(
-                d3d12_ty::D3D12_FEATURE_SHADER_MODEL,
-                &mut shader_model_support as *mut _ as *mut _,
-                mem::size_of::<d3d12_ty::D3D12_FEATURE_DATA_SHADER_MODEL>() as _,
-            )
-        });
-
-        // If we don't have dxc, we reduce the max to 5.1
-        if dxc_container.is_none() {
-            shader_model_support.HighestShaderModel = d3d12_ty::D3D_SHADER_MODEL_5_1;
-        }
-
         let mut workarounds = super::Workarounds::default();
 
         let info = wgt::AdapterInfo {
@@ -326,7 +309,7 @@ impl super::Adapter {
             wgt::Features::TEXTURE_BINDING_ARRAY
                 | wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
                 | wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
-            shader_model_support.HighestShaderModel >= d3d12_ty::D3D_SHADER_MODEL_5_1,
+            shader_model >= naga::back::hlsl::ShaderModel::V5_1,
         );
 
         let bgra8unorm_storage_supported = {
@@ -357,16 +340,16 @@ impl super::Adapter {
             )
         };
 
-        // we must be using DXC because uint64_t was added with Shader Model 6
-        // and FXC only supports up to 5.1
         features.set(
             wgt::Features::SHADER_INT64,
-            dxc_container.is_some() && hr == 0 && features1.Int64ShaderOps != 0,
+            shader_model >= naga::back::hlsl::ShaderModel::V6_0
+                && hr == 0
+                && features1.Int64ShaderOps != 0,
         );
 
         features.set(
             wgt::Features::SUBGROUP,
-            shader_model_support.HighestShaderModel >= d3d12_ty::D3D_SHADER_MODEL_6_0
+            shader_model >= naga::back::hlsl::ShaderModel::V6_0
                 && hr == 0
                 && features1.WaveOps != 0,
         );
diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs
index 317c595d6..052c77006 100644
--- a/wgpu-hal/src/gles/adapter.rs
+++ b/wgpu-hal/src/gles/adapter.rs
@@ -527,8 +527,7 @@ impl super::Adapter {
         let has_etc = if cfg!(any(webgl, Emscripten)) {
             extensions.contains("WEBGL_compressed_texture_etc")
         } else {
-            // This is a required part of GLES3, but not part of Desktop GL at all.
-            es_ver.is_some()
+            es_ver.is_some() || extensions.contains("GL_ARB_ES3_compatibility")
         };
         features.set(wgt::Features::TEXTURE_COMPRESSION_ETC2, has_etc);
 


Test patch:
diff --git a/naga/tests/in/overrides.wgsl b/naga/tests/in/overrides.wgsl
index 6173c3463..a746ce1c7 100644
--- a/naga/tests/in/overrides.wgsl
+++ b/naga/tests/in/overrides.wgsl
@@ -14,6 +14,7 @@
 override inferred_f32 = 2.718;
 
 var<private> gain_x_10: f32 = gain * 10.;
+var<private> store_override: f32;
 
 @compute @workgroup_size(1)
 fn main() {
@@ -22,4 +23,6 @@ fn main() {
     var x = a;
 
     var gain_x_100 = gain_x_10 * 10.;
+
+    store_override = gain;
 }
diff --git a/naga/tests/out/analysis/overrides.info.ron b/naga/tests/out/analysis/overrides.info.ron
index 00d8ce1ea..12fa4b339 100644
--- a/naga/tests/out/analysis/overrides.info.ron
+++ b/naga/tests/out/analysis/overrides.info.ron
@@ -16,6 +16,7 @@
             sampling_set: [],
             global_uses: [
                 ("READ"),
+                ("WRITE"),
             ],
             expressions: [
                 (
@@ -138,6 +139,27 @@
                         space: Function,
                     )),
                 ),
+                (
+                    uniformity: (
+                        non_uniform_result: Some(12),
+                        requirements: (""),
+                    ),
+                    ref_count: 1,
+                    assignable_global: Some(2),
+                    ty: Value(Pointer(
+                        base: 2,
+                        space: Private,
+                    )),
+                ),
+                (
+                    uniformity: (
+                        non_uniform_result: None,
+                        requirements: (""),
+                    ),
+                    ref_count: 1,
+                    assignable_global: None,
+                    ty: Handle(2),
+                ),
             ],
             sampling: [],
             dual_source_blending: false,
diff --git a/naga/tests/out/glsl/overrides.main.Compute.glsl b/naga/tests/out/glsl/overrides.main.Compute.glsl
index b6d86d50b..d1170df96 100644
--- a/naga/tests/out/glsl/overrides.main.Compute.glsl
+++ b/naga/tests/out/glsl/overrides.main.Compute.glsl
@@ -15,6 +15,8 @@ const float inferred_f32_ = 2.718;
 
 float gain_x_10_ = 11.0;
 
+float store_override = 0.0;
+
 
 void main() {
     float t = 23.0;
@@ -23,6 +25,7 @@ void main() {
     x = true;
     float _e9 = gain_x_10_;
     gain_x_100_ = (_e9 * 10.0);
+    store_override = gain;
     return;
 }
 
diff --git a/naga/tests/out/hlsl/overrides.hlsl b/naga/tests/out/hlsl/overrides.hlsl
index b0582d544..a7c49f9ba 100644
--- a/naga/tests/out/hlsl/overrides.hlsl
+++ b/naga/tests/out/hlsl/overrides.hlsl
@@ -7,6 +7,7 @@ static const float height = 4.6;
 static const float inferred_f32_ = 2.718;
 
 static float gain_x_10_ = 11.0;
+static float store_override = (float)0;
 
 [numthreads(1, 1, 1)]
 void main()
@@ -18,5 +19,6 @@ void main()
     x = true;
     float _expr9 = gain_x_10_;
     gain_x_100_ = (_expr9 * 10.0);
+    store_override = gain;
     return;
 }
diff --git a/naga/tests/out/ir/overrides.compact.ron b/naga/tests/out/ir/overrides.compact.ron
index bc25af3bc..111a13489 100644
--- a/naga/tests/out/ir/overrides.compact.ron
+++ b/naga/tests/out/ir/overrides.compact.ron
@@ -73,6 +73,13 @@
             ty: 2,
             init: Some(10),
         ),
+        (
+            name: Some("store_override"),
+            space: Private,
+            binding: None,
+            ty: 2,
+            init: None,
+        ),
     ],
     global_expressions: [
         Literal(Bool(true)),
@@ -147,6 +154,8 @@
                         right: 9,
                     ),
                     LocalVariable(3),
+                    GlobalVariable(2),
+                    Override(3),
                 ],
                 named_expressions: {
                     5: "a",
@@ -176,6 +185,10 @@
                         pointer: 11,
                         value: 10,
                     ),
+                    Store(
+                        pointer: 12,
+                        value: 13,
+                    ),
                     Return(
                         value: None,
                     ),
diff --git a/naga/tests/out/ir/overrides.ron b/naga/tests/out/ir/overrides.ron
index bc25af3bc..111a13489 100644
--- a/naga/tests/out/ir/overrides.ron
+++ b/naga/tests/out/ir/overrides.ron
@@ -73,6 +73,13 @@
             ty: 2,
             init: Some(10),
         ),
+        (
+            name: Some("store_override"),
+            space: Private,
+            binding: None,
+            ty: 2,
+            init: None,
+        ),
     ],
     global_expressions: [
         Literal(Bool(true)),
@@ -147,6 +154,8 @@
                         right: 9,
                     ),
                     LocalVariable(3),
+                    GlobalVariable(2),
+                    Override(3),
                 ],
                 named_expressions: {
                     5: "a",
@@ -176,6 +185,10 @@
                         pointer: 11,
                         value: 10,
                     ),
+                    Store(
+                        pointer: 12,
+                        value: 13,
+                    ),
                     Return(
                         value: None,
                     ),
diff --git a/naga/tests/out/msl/overrides.msl b/naga/tests/out/msl/overrides.msl
index d9e95d070..d3638dd4c 100644
--- a/naga/tests/out/msl/overrides.msl
+++ b/naga/tests/out/msl/overrides.msl
@@ -15,11 +15,13 @@ constant float inferred_f32_ = 2.718;
 kernel void main_(
 ) {
     float gain_x_10_ = 11.0;
+    float store_override = {};
     float t = 23.0;
     bool x = {};
     float gain_x_100_ = {};
     x = true;
     float _e9 = gain_x_10_;
     gain_x_100_ = _e9 * 10.0;
+    store_override = gain;
     return;
 }
diff --git a/naga/tests/out/spv/overrides.main.spvasm b/naga/tests/out/spv/overrides.main.spvasm
index d21eb7c67..5c748a01b 100644
--- a/naga/tests/out/spv/overrides.main.spvasm
+++ b/naga/tests/out/spv/overrides.main.spvasm
@@ -1,12 +1,12 @@
 ; SPIR-V
 ; Version: 1.0
 ; Generator: rspirv
-; Bound: 31
+; Bound: 33
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint GLCompute %18 "main"
-OpExecutionMode %18 LocalSize 1 1 1
+OpEntryPoint GLCompute %20 "main"
+OpExecutionMode %20 LocalSize 1 1 1
 %2 = OpTypeVoid
 %3 = OpTypeBool
 %4 = OpTypeFloat 32
@@ -22,22 +22,25 @@ OpExecutionMode %18 LocalSize 1 1 1
 %14 = OpConstant  %4  11.0
 %16 = OpTypePointer Private %4
 %15 = OpVariable  %16  Private %14
-%19 = OpTypeFunction %2
-%20 = OpConstant  %4  23.0
-%22 = OpTypePointer Function %4
-%24 = OpTypePointer Function %3
-%25 = OpConstantNull  %3
-%27 = OpConstantNull  %4
-%18 = OpFunction  %2  None %19
-%17 = OpLabel
-%21 = OpVariable  %22  Function %20
-%23 = OpVariable  %24  Function %25
-%26 = OpVariable  %22  Function %27
-OpBranch %28
-%28 = OpLabel
-OpStore %23 %5
-%29 = OpLoad  %4  %15
-%30 = OpFMul  %4  %29 %13
-OpStore %26 %30
+%18 = OpConstantNull  %4
+%17 = OpVariable  %16  Private %18
+%21 = OpTypeFunction %2
+%22 = OpConstant  %4  23.0
+%24 = OpTypePointer Function %4
+%26 = OpTypePointer Function %3
+%27 = OpConstantNull  %3
+%29 = OpConstantNull  %4
+%20 = OpFunction  %2  None %21
+%19 = OpLabel
+%23 = OpVariable  %24  Function %22
+%25 = OpVariable  %26  Function %27
+%28 = OpVariable  %24  Function %29
+OpBranch %30
+%30 = OpLabel
+OpStore %25 %5
+%31 = OpLoad  %4  %15
+%32 = OpFMul  %4  %31 %13
+OpStore %28 %32
+OpStore %17 %9
 OpReturn
 OpFunctionEnd
\ No newline at end of file