mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
fix: prevent flicker while shrinking screen by eliminating thread race
Before this fix, if vsync was on the GPU cells buffer could be cleared for a frame while resizing the terminal down. This was due to the fact that the surface sent messages for the resize to both the renderer and the IO thread. If the renderer thread was processed first then the GPU cells buffer(s) would be cleared and not rebuilt, because the terminal state would be larger than the GPU cell buffers causing updateFrame to bail out early, leaving empty cell buffers. This fixes the problem by changing the origin of the renderer's resize message to be the IO thread, only after properly updating the terminal state, to avoid clearing the GPU cells buffers at a time they can't be successfully rebuilt.
This commit is contained in:
@ -1197,15 +1197,6 @@ fn resize(self: *Surface, size: renderer.ScreenSize) !void {
|
|||||||
// Save our screen size
|
// Save our screen size
|
||||||
self.screen_size = 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,
|
// Recalculate our grid size. Because Ghostty supports fluid resizing,
|
||||||
// its possible the grid doesn't change at all even if the screen size changes.
|
// 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
|
// We have to update the IO thread no matter what because we send
|
||||||
|
@ -2012,11 +2012,13 @@ pub fn setScreenSize(
|
|||||||
.cursor_color = old.cursor_color,
|
.cursor_color = old.cursor_color,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reset our cell contents.
|
// Reset our cell contents if our grid size has changed.
|
||||||
try self.cells.resize(self.alloc, grid_size);
|
if (!self.cells.size.equals(grid_size)) {
|
||||||
|
try self.cells.resize(self.alloc, grid_size);
|
||||||
|
|
||||||
// Reset our viewport to force a rebuild
|
// Reset our viewport to force a rebuild
|
||||||
self.cells_viewport = null;
|
self.cells_viewport = null;
|
||||||
|
}
|
||||||
|
|
||||||
// If we have custom shaders then we update the state
|
// If we have custom shaders then we update the state
|
||||||
if (self.custom_shader_state) |*state| {
|
if (self.custom_shader_state) |*state| {
|
||||||
|
@ -480,7 +480,7 @@ fn drawCallback(
|
|||||||
r: xev.Timer.RunError!void,
|
r: xev.Timer.RunError!void,
|
||||||
) xev.CallbackAction {
|
) xev.CallbackAction {
|
||||||
_ = r catch unreachable;
|
_ = r catch unreachable;
|
||||||
const t = self_ orelse {
|
const t: *Thread = self_ orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
return .disarm;
|
return .disarm;
|
||||||
@ -504,7 +504,7 @@ fn renderCallback(
|
|||||||
r: xev.Timer.RunError!void,
|
r: xev.Timer.RunError!void,
|
||||||
) xev.CallbackAction {
|
) xev.CallbackAction {
|
||||||
_ = r catch unreachable;
|
_ = r catch unreachable;
|
||||||
const t = self_ orelse {
|
const t: *Thread = self_ orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
return .disarm;
|
return .disarm;
|
||||||
@ -543,7 +543,7 @@ fn cursorTimerCallback(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const t = self_ orelse {
|
const t: *Thread = self_ orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
return .disarm;
|
return .disarm;
|
||||||
|
@ -378,7 +378,13 @@ pub fn resize(
|
|||||||
// immediately for a resize. This is allowed by the spec.
|
// immediately for a resize. This is allowed by the spec.
|
||||||
self.terminal.modes.set(.synchronized_output, false);
|
self.terminal.modes.set(.synchronized_output, false);
|
||||||
|
|
||||||
// Wake up our renderer so any changes will be shown asap
|
// 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 {};
|
self.renderer_wakeup.notify() catch {};
|
||||||
|
|
||||||
// If we have size reporting enabled we need to send a report.
|
// If we have size reporting enabled we need to send a report.
|
||||||
|
Reference in New Issue
Block a user