diff --git a/src/Surface.zig b/src/Surface.zig index 2e283f985..fc3144ade 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1197,15 +1197,6 @@ fn resize(self: *Surface, size: renderer.ScreenSize) !void { // Save our screen size self.screen_size = size; - // Mail the renderer so that it can update the GPU and re-render - _ = self.renderer_thread.mailbox.push(.{ - .resize = .{ - .screen_size = self.screen_size, - .padding = self.padding, - }, - }, .{ .forever = {} }); - try self.queueRender(); - // Recalculate our grid size. Because Ghostty supports fluid resizing, // its possible the grid doesn't change at all even if the screen size changes. // We have to update the IO thread no matter what because we send diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index ebd5d9b0d..80ba787b2 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -908,12 +908,14 @@ pub fn updateFrame( } // If our terminal screen size doesn't match our expected renderer - // size then we skip a frame. This can happen if we get resized - // before the terminal gets resized. The terminal resize event also - // wakes up the renderer so we'll get another chance to update frame - // data. - if (self.cells.size.rows < state.terminal.rows or - self.cells.size.columns < state.terminal.cols) + // size then we skip a frame. This can happen if the terminal state + // is resized between when the renderer mailbox is drained and when + // the state mutex is acquired inside this function. + // + // For some reason this doesn't seem to cause any significant issues + // with flickering while resizing. '\_('-')_/' + if (self.cells.size.rows != state.terminal.rows or + self.cells.size.columns != state.terminal.cols) { return; } @@ -2012,11 +2014,13 @@ pub fn setScreenSize( .cursor_color = old.cursor_color, }; - // Reset our cell contents. - try self.cells.resize(self.alloc, grid_size); + // Reset our cell contents if our grid size has changed. + if (!self.cells.size.equals(grid_size)) { + try self.cells.resize(self.alloc, grid_size); - // Reset our viewport to force a rebuild - self.cells_viewport = null; + // Reset our viewport to force a rebuild + self.cells_viewport = null; + } // If we have custom shaders then we update the state if (self.custom_shader_state) |*state| { diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index a8d0198e2..498a1e967 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -739,6 +739,19 @@ pub fn updateFrame( self.foreground_color = bg; } + // If our terminal screen size doesn't match our expected renderer + // size then we skip a frame. This can happen if the terminal state + // is resized between when the renderer mailbox is drained and when + // the state mutex is acquired inside this function. + // + // For some reason this doesn't seem to cause any significant issues + // with flickering while resizing. '\_('-')_/' + if (self.grid_size.rows != state.terminal.rows or + self.grid_size.columns != state.terminal.cols) + { + return; + } + // Get the viewport pin so that we can compare it to the current. const viewport_pin = state.terminal.screen.pages.pin(.{ .viewport = .{} }).?; diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index 459fc105a..2521d18a4 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -480,7 +480,7 @@ fn drawCallback( r: xev.Timer.RunError!void, ) xev.CallbackAction { _ = r catch unreachable; - const t = self_ orelse { + const t: *Thread = self_ orelse { // This shouldn't happen so we log it. log.warn("render callback fired without data set", .{}); return .disarm; @@ -504,7 +504,7 @@ fn renderCallback( r: xev.Timer.RunError!void, ) xev.CallbackAction { _ = r catch unreachable; - const t = self_ orelse { + const t: *Thread = self_ orelse { // This shouldn't happen so we log it. log.warn("render callback fired without data set", .{}); return .disarm; @@ -522,6 +522,8 @@ fn renderCallback( t.flags.cursor_blink_visible, ) catch |err| log.warn("error rendering err={}", .{err}); + + // Draw t.drawFrame(false); return .disarm; @@ -543,7 +545,7 @@ fn cursorTimerCallback( }, }; - const t = self_ orelse { + const t: *Thread = self_ orelse { // This shouldn't happen so we log it. log.warn("render callback fired without data set", .{}); return .disarm; diff --git a/src/termio/Termio.zig b/src/termio/Termio.zig index 246b9b2f8..ae38eb043 100644 --- a/src/termio/Termio.zig +++ b/src/termio/Termio.zig @@ -378,14 +378,20 @@ pub fn resize( // immediately for a resize. This is allowed by the spec. self.terminal.modes.set(.synchronized_output, false); - // Wake up our renderer so any changes will be shown asap - self.renderer_wakeup.notify() catch {}; - // If we have size reporting enabled we need to send a report. if (self.terminal.modes.get(.in_band_size_reports)) { try self.sizeReportLocked(td, .mode_2048); } } + + // Mail the renderer so that it can update the GPU and re-render + _ = self.renderer_mailbox.push(.{ + .resize = .{ + .screen_size = screen_size, + .padding = padding, + }, + }, .{ .forever = {} }); + self.renderer_wakeup.notify() catch {}; } /// Make a size report.