Relax device limits for WGPU (#50270)

John Tur created

Plus some minor cleanup.

Release Notes:

- Fixed GPU acceleration not working on certain Linux devices.

Change summary

crates/gpui_wgpu/src/wgpu_context.rs  | 69 ++++++++--------------------
crates/gpui_wgpu/src/wgpu_renderer.rs |  7 ++
crates/zlog/src/filter.rs             |  2 
3 files changed, 26 insertions(+), 52 deletions(-)

Detailed changes

crates/gpui_wgpu/src/wgpu_context.rs 🔗

@@ -52,7 +52,8 @@ impl WgpuContext {
             adapter.get_info().backend
         );
 
-        let (device, queue, dual_source_blending) = Self::create_device(&adapter)?;
+        let (device, queue, dual_source_blending) =
+            pollster::block_on(Self::create_device(&adapter))?;
 
         Ok(Self {
             instance,
@@ -80,29 +81,36 @@ impl WgpuContext {
             })
             .await
             .map_err(|e| anyhow::anyhow!("Failed to request GPU adapter: {e}"))?;
-        Self::create_context(instance, adapter).await
-    }
 
-    #[cfg(target_family = "wasm")]
-    async fn create_context(
-        instance: wgpu::Instance,
-        adapter: wgpu::Adapter,
-    ) -> anyhow::Result<Self> {
         log::info!(
             "Selected GPU adapter: {:?} ({:?})",
             adapter.get_info().name,
             adapter.get_info().backend
         );
 
-        let dual_source_blending_available = adapter
+        let (device, queue, dual_source_blending) = Self::create_device(&adapter).await?;
+
+        Ok(Self {
+            instance,
+            adapter,
+            device: Arc::new(device),
+            queue: Arc::new(queue),
+            dual_source_blending,
+        })
+    }
+
+    async fn create_device(
+        adapter: &wgpu::Adapter,
+    ) -> anyhow::Result<(wgpu::Device, wgpu::Queue, bool)> {
+        let dual_source_blending = adapter
             .features()
             .contains(wgpu::Features::DUAL_SOURCE_BLENDING);
 
         let mut required_features = wgpu::Features::empty();
-        if dual_source_blending_available {
+        if dual_source_blending {
             required_features |= wgpu::Features::DUAL_SOURCE_BLENDING;
         } else {
-            log::info!(
+            log::warn!(
                 "Dual-source blending not available on this GPU. \
                 Subpixel text antialiasing will be disabled."
             );
@@ -112,7 +120,7 @@ impl WgpuContext {
             .request_device(&wgpu::DeviceDescriptor {
                 label: Some("gpui_device"),
                 required_features,
-                required_limits: wgpu::Limits::default(),
+                required_limits: wgpu::Limits::downlevel_defaults(),
                 memory_hints: wgpu::MemoryHints::MemoryUsage,
                 trace: wgpu::Trace::Off,
                 experimental_features: wgpu::ExperimentalFeatures::disabled(),
@@ -120,13 +128,7 @@ impl WgpuContext {
             .await
             .map_err(|e| anyhow::anyhow!("Failed to create wgpu device: {e}"))?;
 
-        Ok(Self {
-            instance,
-            adapter,
-            device: Arc::new(device),
-            queue: Arc::new(queue),
-            dual_source_blending: dual_source_blending_available,
-        })
+        Ok((device, queue, dual_source_blending))
     }
 
     #[cfg(not(target_family = "wasm"))]
@@ -154,35 +156,6 @@ impl WgpuContext {
         Ok(())
     }
 
-    #[cfg(not(target_family = "wasm"))]
-    fn create_device(adapter: &wgpu::Adapter) -> anyhow::Result<(wgpu::Device, wgpu::Queue, bool)> {
-        let dual_source_blending_available = adapter
-            .features()
-            .contains(wgpu::Features::DUAL_SOURCE_BLENDING);
-
-        let mut required_features = wgpu::Features::empty();
-        if dual_source_blending_available {
-            required_features |= wgpu::Features::DUAL_SOURCE_BLENDING;
-        } else {
-            log::warn!(
-                "Dual-source blending not available on this GPU. \
-                Subpixel text antialiasing will be disabled."
-            );
-        }
-
-        let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
-            label: Some("gpui_device"),
-            required_features,
-            required_limits: wgpu::Limits::default(),
-            memory_hints: wgpu::MemoryHints::MemoryUsage,
-            trace: wgpu::Trace::Off,
-            experimental_features: wgpu::ExperimentalFeatures::disabled(),
-        }))
-        .map_err(|e| anyhow::anyhow!("Failed to create wgpu device: {e}"))?;
-
-        Ok((device, queue, dual_source_blending_available))
-    }
-
     #[cfg(not(target_family = "wasm"))]
     async fn select_adapter(
         instance: &wgpu::Instance,

crates/gpui_wgpu/src/wgpu_renderer.rs 🔗

@@ -106,6 +106,7 @@ pub struct WgpuRenderer {
     path_globals_bind_group: wgpu::BindGroup,
     instance_buffer: wgpu::Buffer,
     instance_buffer_capacity: u64,
+    max_buffer_size: u64,
     storage_buffer_alignment: u64,
     path_intermediate_texture: wgpu::Texture,
     path_intermediate_view: wgpu::TextureView,
@@ -285,6 +286,7 @@ impl WgpuRenderer {
             mapped_at_creation: false,
         });
 
+        let max_buffer_size = device.limits().max_buffer_size;
         let storage_buffer_alignment = device.limits().min_storage_buffer_offset_alignment as u64;
         let initial_instance_buffer_capacity = 2 * 1024 * 1024;
         let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
@@ -375,6 +377,7 @@ impl WgpuRenderer {
             path_globals_bind_group,
             instance_buffer,
             instance_buffer_capacity: initial_instance_buffer_capacity,
+            max_buffer_size,
             storage_buffer_alignment,
             path_intermediate_texture,
             path_intermediate_view,
@@ -1070,7 +1073,7 @@ impl WgpuRenderer {
 
             if overflow {
                 drop(encoder);
-                if self.instance_buffer_capacity >= 256 * 1024 * 1024 {
+                if self.instance_buffer_capacity >= self.max_buffer_size {
                     log::error!(
                         "instance buffer size grew too large: {}",
                         self.instance_buffer_capacity
@@ -1379,7 +1382,7 @@ impl WgpuRenderer {
     }
 
     fn grow_instance_buffer(&mut self) {
-        let new_capacity = self.instance_buffer_capacity * 2;
+        let new_capacity = (self.instance_buffer_capacity * 2).min(self.max_buffer_size);
         log::info!("increased instance buffer size to {}", new_capacity);
         self.instance_buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
             label: Some("instance_buffer"),

crates/zlog/src/filter.rs 🔗

@@ -38,8 +38,6 @@ const DEFAULT_FILTERS: &[(&str, log::LevelFilter)] = &[
     #[cfg(any(target_os = "linux", target_os = "freebsd"))]
     ("zbus", log::LevelFilter::Warn),
     #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "windows"))]
-    ("wgpu", log::LevelFilter::Warn),
-    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "windows"))]
     ("naga::back::spv::writer", log::LevelFilter::Warn),
     // usvg prints a lot of warnings on rendering an SVG with partial errors, which
     // can happen a lot with the SVG preview