Repository: gfx-rs/wgpu
Pull request #5716 (2024-05-18 14:55:02)

Backport bugfixes to v0.20
**Description**

Backports all of:
* https://github.com/gfx-rs/wgpu/pull/5595
* https://github.com/gfx-rs/wgpu/pull/5624
* https://github.com/gfx-rs/wgpu/pull/5640
* https://github.com/gfx-rs/wgpu/pull/5642
* https://github.com/gfx-rs/wgpu/pull/5682
* https://github.com/gfx-rs/wgpu/pull/5625
    * not actually needed for anything but making tests on my mac happy 

... and cleaned up changelog in anticipation of wgpu 0.20.1.

**Testing**
... 🤞 
Low risk, these worked on `trunk` and not much time has passed. Merge conflicts were minimal

<!-- 
Thanks for filing! The codeowners file will automatically request reviews from the appropriate teams.

After you get a review and have addressed any comments, please explicitly re-request a review from the
person(s) who reviewed your changes. This will make sure it gets re-added to their review queue - you're no bothering us!
-->

**Checklist**

- [x] Run `cargo fmt`.
- [x] Run `cargo clippy`. If applicable, add:
  - [x] `--target wasm32-unknown-unknown`
  - [ ] `--target wasm32-unknown-emscripten`
- [x] Run `cargo xtask test` to run tests.
- [x] Add change to `CHANGELOG.md`. See simple instructions inside file.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e15d2f28..8036a3d93 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,7 +37,23 @@ Bottom level categories:
 - Hal
 -->
 
-## Unreleased
+## Unreleased -- v0.20.1 (2024-04-??)
+
+### Bug Fixes
+
+#### General
+
+- Clean up weak references to texture views and bind groups to prevent memory leaks. By @xiaopengli89 in [#5595](https://github.com/gfx-rs/wgpu/pull/5595).
+- Fix segfault on exit is queue & device are dropped before surface. By @sagudev in [#5640](https://github.com/gfx-rs/wgpu/pull/5640).
+
+#### Vulkan
+
+- Fix enablement of subgroup ops extension on Vulkan devices that don't support Vulkan 1.3. By @cwfitzgerald in [#5624](https://github.com/gfx-rs/wgpu/pull/5624).
+
+
+#### GLES / OpenGL
+
+-  Fix regression on OpenGL (EGL) where non-sRGB still used sRGB [#5642](https://github.com/gfx-rs/wgpu/pull/5642)
 
 ## v0.20.0 (2024-04-28)
 
diff --git a/wgpu-core/src/device/any_device.rs b/wgpu-core/src/device/any_device.rs
index 693155a75..9e459c1a9 100644
--- a/wgpu-core/src/device/any_device.rs
+++ b/wgpu-core/src/device/any_device.rs
@@ -34,7 +34,7 @@ impl AnyDevice {
         unsafe fn drop_glue<A: HalApi>(ptr: *mut ()) {
             // Drop the arc this instance is holding.
             unsafe {
-                _ = Arc::from_raw(ptr.cast::<A::Surface>());
+                _ = Arc::from_raw(ptr.cast::<A::Device>());
             }
         }
 
diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs
index 23f09682e..1f1881ce9 100644
--- a/wgpu-core/src/device/life.rs
+++ b/wgpu-core/src/device/life.rs
@@ -596,6 +596,18 @@ impl<A: HalApi> LifetimeTracker<A> {
             &mut trackers.textures,
             |maps| &mut maps.textures,
         );
+
+        // We may have been suspected because a texture view or bind group
+        // referring to us was dropped. Remove stale weak references, so that
+        // the backlink table doesn't grow without bound.
+        for texture in self.suspected_resources.textures.values() {
+            texture.views.lock().retain(|view| view.strong_count() > 0);
+            texture
+                .bind_groups
+                .lock()
+                .retain(|bg| bg.strong_count() > 0);
+        }
+
         self
     }
 
@@ -621,6 +633,13 @@ impl<A: HalApi> LifetimeTracker<A> {
             |maps| &mut maps.buffers,
         );
 
+        // We may have been suspected because a bind group referring to us was
+        // dropped. Remove stale weak references, so that the backlink table
+        // doesn't grow without bound.
+        for buffer in self.suspected_resources.buffers.values() {
+            buffer.bind_groups.lock().retain(|bg| bg.strong_count() > 0);
+        }
+
         self
     }
 
diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs
index 7494dcad7..a91358676 100644
--- a/wgpu-hal/src/gles/egl.rs
+++ b/wgpu-hal/src/gles/egl.rs
@@ -1130,6 +1130,13 @@ impl Surface {
 
         unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
         unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) };
+
+        if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) {
+            // Disable sRGB conversions for `glBlitFramebuffer` as behavior does diverge between
+            // drivers and formats otherwise and we want to ensure no sRGB conversions happen.
+            unsafe { gl.disable(glow::FRAMEBUFFER_SRGB) };
+        }
+
         // Note the Y-flipping here. GL's presentation is not flipped,
         // but main rendering is. Therefore, we Y-flip the output positions
         // in the shader, and also this blit.
@@ -1147,6 +1154,11 @@ impl Surface {
                 glow::NEAREST,
             )
         };
+
+        if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) {
+            unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) };
+        }
+
         unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
 
         self.egl
diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs
index 21219361f..bbf44feac 100644
--- a/wgpu-hal/src/vulkan/adapter.rs
+++ b/wgpu-hal/src/vulkan/adapter.rs
@@ -1485,9 +1485,6 @@ impl super::Instance {
                 }),
             image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2
                 || phd_capabilities.supports_extension(vk::KhrImageFormatListFn::name()),
-            subgroup_size_control: phd_features
-                .subgroup_size_control
-                .map_or(false, |ext| ext.subgroup_size_control == vk::TRUE),
         };
         let capabilities = crate::Capabilities {
             limits: phd_capabilities.to_wgpu_limits(),
@@ -1792,6 +1789,7 @@ impl super::Adapter {
             vendor_id: self.phd_capabilities.properties.vendor_id,
             timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
             private_caps: self.private_caps.clone(),
+            features,
             workarounds: self.workarounds,
             render_passes: Mutex::new(Default::default()),
             framebuffers: Mutex::new(Default::default()),
diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs
index ec392533a..aba36311d 100644
--- a/wgpu-hal/src/vulkan/device.rs
+++ b/wgpu-hal/src/vulkan/device.rs
@@ -789,7 +789,7 @@ impl super::Device {
         };
 
         let mut flags = vk::PipelineShaderStageCreateFlags::empty();
-        if self.shared.private_caps.subgroup_size_control {
+        if self.shared.features.contains(wgt::Features::SUBGROUP) {
             flags |= vk::PipelineShaderStageCreateFlags::ALLOW_VARYING_SUBGROUP_SIZE
         }
 
diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs
index d1ea82772..0dd361e0b 100644
--- a/wgpu-hal/src/vulkan/mod.rs
+++ b/wgpu-hal/src/vulkan/mod.rs
@@ -238,7 +238,6 @@ struct PrivateCapabilities {
     robust_image_access2: bool,
     zero_initialize_workgroup_memory: bool,
     image_format_list: bool,
-    subgroup_size_control: bool,
 }
 
 bitflags::bitflags!(
@@ -344,6 +343,7 @@ struct DeviceShared {
     timestamp_period: f32,
     private_caps: PrivateCapabilities,
     workarounds: Workarounds,
+    features: wgt::Features,
     render_passes: Mutex<rustc_hash::FxHashMap<RenderPassKey, vk::RenderPass>>,
     framebuffers: Mutex<rustc_hash::FxHashMap<FramebufferKey, vk::Framebuffer>>,
 }
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 2807c55cb..bde91f419 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -69,32 +69,27 @@ pub use wgt::{
 /// Re-export of our `wgpu-core` dependency.
 ///
 #[cfg(wgpu_core)]
-#[doc(inline)]
 pub use ::wgc as core;
 
 /// Re-export of our `wgpu-hal` dependency.
 ///
 ///
 #[cfg(wgpu_core)]
-#[doc(inline)]
 pub use ::hal;
 
 /// Re-export of our `naga` dependency.
 ///
 #[cfg(wgpu_core)]
 #[cfg_attr(docsrs, doc(cfg(any(wgpu_core, naga))))]
-#[doc(inline)]
 // We re-export wgpu-core's re-export of naga, as we may not have direct access to it.
 pub use ::wgc::naga;
 /// Re-export of our `naga` dependency.
 ///
 #[cfg(all(not(wgpu_core), naga))]
 #[cfg_attr(docsrs, doc(cfg(any(wgpu_core, naga))))]
-#[doc(inline)]
 // If that's not available, we re-export our own.
 pub use naga;
 
-#[doc(inline)]
 /// Re-export of our `raw-window-handle` dependency.
 ///
 pub use raw_window_handle as rwh;
@@ -102,7 +97,6 @@ pub use raw_window_handle as rwh;
 /// Re-export of our `web-sys` dependency.
 ///
 #[cfg(any(webgl, webgpu))]
-#[doc(inline)]
 pub use web_sys;
 
 // wasm-only types, we try to keep as many types non-platform


Test patch:
diff --git a/tests/tests/subgroup_operations/mod.rs b/tests/tests/subgroup_operations/mod.rs
index c78cf131a..2c518a9d9 100644
--- a/tests/tests/subgroup_operations/mod.rs
+++ b/tests/tests/subgroup_operations/mod.rs
@@ -11,10 +11,22 @@ static SUBGROUP_OPERATIONS: GpuTestConfiguration = GpuTestConfiguration::new()
         TestParameters::default()
             .features(wgpu::Features::SUBGROUP)
             .limits(wgpu::Limits::downlevel_defaults())
-            .expect_fail(wgpu_test::FailureCase::molten_vk())
+            // Expect metal to fail on tests involving operations in divergent control flow
+            //
+            // Newlines are included in the panic message to ensure that _additional_ failures
+            // are not matched against.
+            .expect_fail(
+                wgpu_test::FailureCase::molten_vk()
+                    // 14.3 doesn't fail test 29
+                    .panic("thread 0 failed tests: 27,\nthread 1 failed tests: 27, 28,\n")
+                    // Prior versions do.
+                    .panic("thread 0 failed tests: 27, 29,\nthread 1 failed tests: 27, 28, 29,\n"),
+            )
             .expect_fail(
-                // Expect metal to fail on tests involving operations in divergent control flow
                 wgpu_test::FailureCase::backend(wgpu::Backends::METAL)
+                    // 14.3 doesn't fail test 29
+                    .panic("thread 0 failed tests: 27,\nthread 1 failed tests: 27, 28,\n")
+                    // Prior versions do.
                     .panic("thread 0 failed tests: 27, 29,\nthread 1 failed tests: 27, 28, 29,\n"),
             ),
     )
diff --git a/tests/tests/subgroup_operations/shader.wgsl b/tests/tests/subgroup_operations/shader.wgsl
index 7834514cb..77cb81ce7 100644
--- a/tests/tests/subgroup_operations/shader.wgsl
+++ b/tests/tests/subgroup_operations/shader.wgsl
@@ -111,6 +111,7 @@ fn main(
     add_result_to_mask(&passed, 25u, subgroup_invocation_id == 0u || subgroupShuffleUp(subgroup_invocation_id, 1u) == subgroup_invocation_id - 1u);
     add_result_to_mask(&passed, 26u, subgroupShuffleXor(subgroup_invocation_id, subgroup_size - 1u) == (subgroup_invocation_id ^ (subgroup_size - 1u)));
 
+    // Mac/Apple will fail this test.
     var passed_27 = false;
     if subgroup_invocation_id % 2u == 0u {
         passed_27 |= subgroupAdd(1u) == (subgroup_size / 2u);
@@ -119,6 +120,7 @@ fn main(
     }
     add_result_to_mask(&passed, 27u, passed_27);
 
+    // Mac/Apple will fail this test.
     var passed_28 = false;
     switch subgroup_invocation_id % 3u {
         case 0u: {
@@ -134,6 +136,7 @@ fn main(
     }
     add_result_to_mask(&passed, 28u, passed_28);
 
+    // Mac/Apple will sometimes fail this test. MacOS 14.3 passes it, so the bug in the metal compiler seems to be fixed.
     expected = 0u;
     for (var i = subgroup_size; i >= 0u; i -= 1u) {
         expected = subgroupAdd(1u);