From e5e9d43d52aabc7826a8efa2e77bf4cc94441d86 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 21 Apr 2025 13:55:35 -0700 Subject: [PATCH] renderer/opengl: reduce flickering/stretching on resize Fixes #2446 Two separate issues: 1. Ensure that our screen size matches the viewport size when drawFrame is called. By the time drawFrame is called, GTK will have updated the OpenGL context, but our deferred screen size may still be incorrect since we wait for the pty to update the screen size. 2. Do not clear our cells buffer when the screen size changes, instead changing to a mechanism that only clears the buffers when we have over 50% wasted space. Co-authored-by: Andrew de los Reyes --- src/renderer/OpenGL.zig | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index ba9e5d81f..a3a2d8f7e 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1779,6 +1779,15 @@ pub fn rebuildCells( } } + // Free up memory, generally in case where surface has shrunk. + // If more than half of the capacity is unused, remove all unused capacity. + if (self.cells.items.len * 2 < self.cells.capacity) { + self.cells.shrinkAndFree(self.alloc, self.cells.items.len); + } + if (self.cells_bg.items.len * 2 < self.cells_bg.capacity) { + self.cells_bg.shrinkAndFree(self.alloc, self.cells_bg.items.len); + } + // Some debug mode safety checks if (std.debug.runtime_safety) { for (self.cells_bg.items) |cell| assert(cell.mode == .bg); @@ -2196,12 +2205,6 @@ pub fn setScreenSize( if (single_threaded_draw) self.draw_mutex.lock(); defer if (single_threaded_draw) self.draw_mutex.unlock(); - // Reset our buffer sizes so that we free memory when the screen shrinks. - // This could be made more clever by only doing this when the screen - // shrinks but the performance cost really isn't that much. - self.cells.clearAndFree(self.alloc); - self.cells_bg.clearAndFree(self.alloc); - // Store our screen size self.size = size; @@ -2338,6 +2341,23 @@ pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void { if (comptime is_darwin) _ = ogl.CGLLockContext(cgl_ctx); defer _ = if (comptime is_darwin) ogl.CGLUnlockContext(cgl_ctx); + // If our viewport size doesn't match the saved screen size then + // we need to update it. We rely on this over setScreenSize because + // we can pull it directly from the OpenGL context instead of relying + // on the eventual message. + { + var viewport: [4]gl.c.GLint = undefined; + gl.glad.context.GetIntegerv.?(gl.c.GL_VIEWPORT, &viewport); + const screen: renderer.ScreenSize = .{ + .width = @intCast(viewport[2]), + .height = @intCast(viewport[3]), + }; + if (!screen.equals(self.size.screen)) { + self.size.screen = screen; + self.deferred_screen_size = .{ .size = self.size }; + } + } + // Draw our terminal cells try self.drawCellProgram(gl_state);