only send resize messages to renderer/io thread if changes happen

Previously, we'd send renderer screen size updates and termio sigwnch
updates on every single resize event even if the screen size or grid
sizes didn't change. This is super noisy and given how many resize
events macOS sends, its also very expensive.

This commit makes it so that we only update the renderer if the screen
changed. If the screen size didn't change, the grid size couldn't have
changed either.

If the screen size did change, its still possible the grid size didn't
change since Ghostty supports fluid pixel-level resizing. We have to
send the screen size event to the renderer so all the GPU shader vars
are right but we do not have to send a termio event.

So, only if the grid size changed do we then notify the pty that the
terminal dimensions changed. Note that the resize event for ptys does
have a pixel-level x/y but I don't think the granularity is useful
beyond grid changes.
This commit is contained in:
Mitchell Hashimoto
2023-08-04 19:50:21 -07:00
parent 90cdcab190
commit 437c1ca261
2 changed files with 34 additions and 15 deletions

View File

@ -444,8 +444,8 @@ pub fn init(
.io = io,
.io_thread = io_thread,
.io_thr = undefined,
.screen_size = screen_size,
.grid_size = grid_size,
.screen_size = .{ .width = 0, .height = 0 },
.grid_size = .{},
.cell_size = cell_size,
.padding = padding,
.config = try DerivedConfig.init(alloc, config),
@ -827,20 +827,35 @@ pub fn sizeCallback(self: *Surface, size: apprt.SurfaceSize) !void {
const tracy = trace(@src());
defer tracy.end();
// TODO: if our screen size didn't change, then we should avoid the
// overhead of inter-thread communication
// Save our screen size
self.screen_size = .{
const new_screen_size: renderer.ScreenSize = .{
.width = size.width,
.height = size.height,
};
// Recalculate our grid size
self.grid_size = renderer.GridSize.init(
// Update our screen size, but only if it actually changed. And if
// the screen size didn't change, then our grid size could not have
// changed, so we just return.
if (self.screen_size.equals(new_screen_size)) return;
// Save our screen size
self.screen_size = new_screen_size;
// Mail the renderer so that it can update the GPU and re-render
_ = self.renderer_thread.mailbox.push(.{
.screen_size = self.screen_size,
}, .{ .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.
const new_grid_size = renderer.GridSize.init(
self.screen_size.subPadding(self.padding),
self.cell_size,
);
if (self.grid_size.equals(new_grid_size)) return;
// Grid size changed, update our grid size and notify the terminal
self.grid_size = new_grid_size;
if (self.grid_size.columns < 5 and (self.padding.left > 0 or self.padding.right > 0)) {
log.warn("WARNING: very small terminal grid detected with padding " ++
"set. Is your padding reasonable?", .{});
@ -850,12 +865,6 @@ pub fn sizeCallback(self: *Surface, size: apprt.SurfaceSize) !void {
"set. Is your padding reasonable?", .{});
}
// Mail the renderer
_ = self.renderer_thread.mailbox.push(.{
.screen_size = self.screen_size,
}, .{ .forever = {} });
try self.queueRender();
// Mail the IO thread
_ = self.io_thread.mailbox.push(.{
.resize = .{

View File

@ -52,6 +52,11 @@ pub const ScreenSize = struct {
.height = self.height -| (padding.top + padding.bottom),
};
}
/// Returns true if two sizes are equal.
pub fn equals(self: ScreenSize, other: ScreenSize) bool {
return self.width == other.width and self.height == other.height;
}
};
/// The dimensions of the grid itself, in rows/columns units.
@ -80,6 +85,11 @@ pub const GridSize = struct {
self.columns = @max(1, calc_cols);
self.rows = @max(1, calc_rows);
}
/// Returns true if two sizes are equal.
pub fn equals(self: GridSize, other: GridSize) bool {
return self.columns == other.columns and self.rows == other.rows;
}
};
/// The padding to add to a screen.