Merge pull request #235 from zed-industries/handle-screen-scale-factor-change

Antonio Scandurra created

Fix incorrect rendering when window moves between displays with different scale factors

Change summary

crates/gpui/src/platform/mac/renderer.rs     |  6 ++++--
crates/gpui/src/platform/mac/sprite_cache.rs | 14 +++++++++++++-
crates/gpui/src/platform/mac/window.rs       | 19 ++++++++++++++-----
3 files changed, 31 insertions(+), 8 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/renderer.rs 🔗

@@ -40,6 +40,7 @@ impl Renderer {
     pub fn new(
         device: metal::Device,
         pixel_format: metal::MTLPixelFormat,
+        scale_factor: f32,
         fonts: Arc<dyn platform::FontSystem>,
     ) -> Self {
         let library = device
@@ -64,7 +65,7 @@ impl Renderer {
             MTLResourceOptions::StorageModeManaged,
         );
 
-        let sprite_cache = SpriteCache::new(device.clone(), vec2i(1024, 768), fonts);
+        let sprite_cache = SpriteCache::new(device.clone(), vec2i(1024, 768), scale_factor, fonts);
         let image_cache = ImageCache::new(device.clone(), vec2i(1024, 768));
         let path_atlases =
             AtlasAllocator::new(device.clone(), build_path_atlas_texture_descriptor());
@@ -522,6 +523,8 @@ impl Renderer {
             return;
         }
 
+        self.sprite_cache.set_scale_factor(scale_factor);
+
         let mut sprites_by_atlas = HashMap::new();
 
         for glyph in glyphs {
@@ -530,7 +533,6 @@ impl Renderer {
                 glyph.font_size,
                 glyph.id,
                 glyph.origin,
-                scale_factor,
             ) {
                 // Snap sprite to pixel grid.
                 let origin = (glyph.origin * scale_factor).floor() + sprite.offset.to_f32();

crates/gpui/src/platform/mac/sprite_cache.rs 🔗

@@ -43,12 +43,14 @@ pub struct SpriteCache {
     atlases: AtlasAllocator,
     glyphs: HashMap<GlyphDescriptor, Option<GlyphSprite>>,
     icons: HashMap<IconDescriptor, IconSprite>,
+    scale_factor: f32,
 }
 
 impl SpriteCache {
     pub fn new(
         device: metal::Device,
         size: Vector2I,
+        scale_factor: f32,
         fonts: Arc<dyn platform::FontSystem>,
     ) -> Self {
         let descriptor = TextureDescriptor::new();
@@ -60,19 +62,29 @@ impl SpriteCache {
             atlases: AtlasAllocator::new(device, descriptor),
             glyphs: Default::default(),
             icons: Default::default(),
+            scale_factor,
         }
     }
 
+    pub fn set_scale_factor(&mut self, scale_factor: f32) {
+        if scale_factor != self.scale_factor {
+            self.icons.clear();
+            self.glyphs.clear();
+            self.atlases.clear();
+        }
+        self.scale_factor = scale_factor;
+    }
+
     pub fn render_glyph(
         &mut self,
         font_id: FontId,
         font_size: f32,
         glyph_id: GlyphId,
         target_position: Vector2F,
-        scale_factor: f32,
     ) -> Option<GlyphSprite> {
         const SUBPIXEL_VARIANTS: u8 = 4;
 
+        let scale_factor = self.scale_factor;
         let target_position = target_position * scale_factor;
         let fonts = &self.fonts;
         let atlases = &mut self.atlases;

crates/gpui/src/platform/mac/window.rs 🔗

@@ -205,7 +205,12 @@ impl Window {
                 synthetic_drag_counter: 0,
                 executor,
                 scene_to_render: Default::default(),
-                renderer: Renderer::new(device.clone(), PIXEL_FORMAT, fonts),
+                renderer: Renderer::new(
+                    device.clone(),
+                    PIXEL_FORMAT,
+                    get_scale_factor(native_window),
+                    fonts,
+                ),
                 command_queue: device.new_command_queue(),
                 last_fresh_keydown: None,
                 layer,
@@ -405,10 +410,7 @@ impl platform::WindowContext for WindowState {
     }
 
     fn scale_factor(&self) -> f32 {
-        unsafe {
-            let screen: id = msg_send![self.native_window, screen];
-            NSScreen::backingScaleFactor(screen) as f32
-        }
+        get_scale_factor(self.native_window)
     }
 
     fn titlebar_height(&self) -> f32 {
@@ -427,6 +429,13 @@ impl platform::WindowContext for WindowState {
     }
 }
 
+fn get_scale_factor(native_window: id) -> f32 {
+    unsafe {
+        let screen: id = msg_send![native_window, screen];
+        NSScreen::backingScaleFactor(screen) as f32
+    }
+}
+
 unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
     let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
     let rc1 = Rc::from_raw(raw as *mut RefCell<WindowState>);