Clamp window size on wgpu (#50329) (cherry-pick to preview) (#50346)

zed-zippy[bot] and Conrad Irwin created

Cherry-pick of #50329 to preview

----
Fixes ZED-59P

Release Notes:

- Linux: Fix panic when requested window size was larger than supported
by your GPU

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
(cherry picked from commit 496e115fd3a7ec42a19bb2ff3588ffe5e8e6df7f)

Change summary

crates/gpui/src/platform/linux/wayland/window.rs |  6 ++
crates/gpui/src/platform/wgpu/wgpu_renderer.rs   | 42 +++++++++++++++--
2 files changed, 43 insertions(+), 5 deletions(-)

Detailed changes

crates/gpui/src/platform/linux/wayland/window.rs 🔗

@@ -347,6 +347,12 @@ impl WaylandWindowState {
             if let Some(title) = options.titlebar.and_then(|titlebar| titlebar.title) {
                 xdg_state.toplevel.set_title(title.to_string());
             }
+            // Set max window size based on the GPU's maximum texture dimension.
+            // This prevents the window from being resized larger than what the GPU can render.
+            let max_texture_size = renderer.max_texture_size() as i32;
+            xdg_state
+                .toplevel
+                .set_max_size(max_texture_size, max_texture_size);
         }
 
         Ok(Self {

crates/gpui/src/platform/wgpu/wgpu_renderer.rs 🔗

@@ -116,6 +116,7 @@ pub struct WgpuRenderer {
     adapter_info: wgpu::AdapterInfo,
     transparent_alpha_mode: wgpu::CompositeAlphaMode,
     opaque_alpha_mode: wgpu::CompositeAlphaMode,
+    max_texture_size: u32,
 }
 
 impl WgpuRenderer {
@@ -215,11 +216,27 @@ impl WgpuRenderer {
             opaque_alpha_mode
         };
 
+        let device = Arc::clone(&context.device);
+        let max_texture_size = device.limits().max_texture_dimension_2d;
+
+        let requested_width = config.size.width.0 as u32;
+        let requested_height = config.size.height.0 as u32;
+        let clamped_width = requested_width.min(max_texture_size);
+        let clamped_height = requested_height.min(max_texture_size);
+
+        if clamped_width != requested_width || clamped_height != requested_height {
+            warn!(
+                "Requested surface size ({}, {}) exceeds maximum texture dimension {}. \
+                 Clamping to ({}, {}). Window content may not fill the entire window.",
+                requested_width, requested_height, max_texture_size, clamped_width, clamped_height
+            );
+        }
+
         let surface_config = wgpu::SurfaceConfiguration {
             usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
             format: surface_format,
-            width: config.size.width.0 as u32,
-            height: config.size.height.0 as u32,
+            width: clamped_width.max(1),
+            height: clamped_height.max(1),
             present_mode: wgpu::PresentMode::Fifo,
             desired_maximum_frame_latency: 2,
             alpha_mode,
@@ -227,7 +244,6 @@ impl WgpuRenderer {
         };
         surface.configure(&context.device, &surface_config);
 
-        let device = Arc::clone(&context.device);
         let queue = Arc::clone(&context.queue);
         let dual_source_blending = context.supports_dual_source_blending();
 
@@ -348,6 +364,7 @@ impl WgpuRenderer {
             adapter_info,
             transparent_alpha_mode,
             opaque_alpha_mode,
+            max_texture_size,
         })
     }
 
@@ -762,6 +779,17 @@ impl WgpuRenderer {
         let height = size.height.0 as u32;
 
         if width != self.surface_config.width || height != self.surface_config.height {
+            let clamped_width = width.min(self.max_texture_size);
+            let clamped_height = height.min(self.max_texture_size);
+
+            if clamped_width != width || clamped_height != height {
+                warn!(
+                    "Requested surface size ({}, {}) exceeds maximum texture dimension {}. \
+                     Clamping to ({}, {}). Window content may not fill the entire window.",
+                    width, height, self.max_texture_size, clamped_width, clamped_height
+                );
+            }
+
             // Wait for any in-flight GPU work to complete before destroying textures
             if let Err(e) = self.device.poll(wgpu::PollType::Wait {
                 submission_index: None,
@@ -778,8 +806,8 @@ impl WgpuRenderer {
                 texture.destroy();
             }
 
-            self.surface_config.width = width.max(1);
-            self.surface_config.height = height.max(1);
+            self.surface_config.width = clamped_width.max(1);
+            self.surface_config.height = clamped_height.max(1);
             self.surface.configure(&self.device, &self.surface_config);
 
             // Invalidate intermediate textures - they will be lazily recreated
@@ -864,6 +892,10 @@ impl WgpuRenderer {
         }
     }
 
+    pub fn max_texture_size(&self) -> u32 {
+        self.max_texture_size
+    }
+
     pub fn draw(&mut self, scene: &Scene) {
         self.atlas.before_frame();