mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
renderer/opengl: remove gpucell lru cache
There was no noticable performance improvement and it complicated the code and also diverged it from Metal.
This commit is contained in:
@ -17,20 +17,10 @@ const Terminal = terminal.Terminal;
|
|||||||
const gl = @import("opengl/main.zig");
|
const gl = @import("opengl/main.zig");
|
||||||
const trace = @import("tracy").trace;
|
const trace = @import("tracy").trace;
|
||||||
const math = @import("../math.zig");
|
const math = @import("../math.zig");
|
||||||
const lru = @import("../lru.zig");
|
|
||||||
const Surface = @import("../Surface.zig");
|
const Surface = @import("../Surface.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.grid);
|
const log = std.log.scoped(.grid);
|
||||||
|
|
||||||
/// The LRU is keyed by (screen, row_id) since we need to cache rows
|
|
||||||
/// separately for alt screens. By storing that in the key, we very likely
|
|
||||||
/// have the cache already for when the primary screen is reactivated.
|
|
||||||
const CellsLRU = lru.AutoHashMap(struct {
|
|
||||||
selection: ?terminal.Selection,
|
|
||||||
screen: terminal.Terminal.ScreenType,
|
|
||||||
row_id: terminal.Screen.RowHeader.Id,
|
|
||||||
}, std.ArrayListUnmanaged(GPUCell));
|
|
||||||
|
|
||||||
/// The runtime can request a single-threaded draw by setting this boolean
|
/// The runtime can request a single-threaded draw by setting this boolean
|
||||||
/// to true. In this case, the renderer.draw() call is expected to be called
|
/// to true. In this case, the renderer.draw() call is expected to be called
|
||||||
/// from the runtime.
|
/// from the runtime.
|
||||||
@ -58,10 +48,6 @@ screen_size: ?renderer.ScreenSize,
|
|||||||
cells_bg: std.ArrayListUnmanaged(GPUCell),
|
cells_bg: std.ArrayListUnmanaged(GPUCell),
|
||||||
cells: std.ArrayListUnmanaged(GPUCell),
|
cells: std.ArrayListUnmanaged(GPUCell),
|
||||||
|
|
||||||
/// The LRU that stores our GPU cells cached by row IDs. This is used to
|
|
||||||
/// prevent high CPU activity when shaping rows.
|
|
||||||
cells_lru: CellsLRU,
|
|
||||||
|
|
||||||
/// The size of the cells list that was sent to the GPU. This is used
|
/// The size of the cells list that was sent to the GPU. This is used
|
||||||
/// to detect when the cells array was reallocated/resized and handle that
|
/// to detect when the cells array was reallocated/resized and handle that
|
||||||
/// accordingly.
|
/// accordingly.
|
||||||
@ -309,7 +295,6 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
|
|||||||
.config = options.config,
|
.config = options.config,
|
||||||
.cells_bg = .{},
|
.cells_bg = .{},
|
||||||
.cells = .{},
|
.cells = .{},
|
||||||
.cells_lru = CellsLRU.init(0),
|
|
||||||
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
||||||
.screen_size = null,
|
.screen_size = null,
|
||||||
.gl_state = gl_state,
|
.gl_state = gl_state,
|
||||||
@ -329,9 +314,6 @@ pub fn deinit(self: *OpenGL) void {
|
|||||||
|
|
||||||
if (self.gl_state) |*v| v.deinit();
|
if (self.gl_state) |*v| v.deinit();
|
||||||
|
|
||||||
self.resetCellsLRU();
|
|
||||||
self.cells_lru.deinit(self.alloc);
|
|
||||||
|
|
||||||
self.cells.deinit(self.alloc);
|
self.cells.deinit(self.alloc);
|
||||||
self.cells_bg.deinit(self.alloc);
|
self.cells_bg.deinit(self.alloc);
|
||||||
|
|
||||||
@ -340,22 +322,6 @@ pub fn deinit(self: *OpenGL) void {
|
|||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resetCellsLRU(self: *OpenGL) void {
|
|
||||||
// Preserve the old capacity so that we have space in our LRU
|
|
||||||
const cap = self.cells_lru.capacity;
|
|
||||||
|
|
||||||
// Our LRU values are array lists so we need to deallocate those first
|
|
||||||
var it = self.cells_lru.queue.first;
|
|
||||||
while (it) |node| {
|
|
||||||
it = node.next;
|
|
||||||
node.data.value.deinit(self.alloc);
|
|
||||||
}
|
|
||||||
self.cells_lru.deinit(self.alloc);
|
|
||||||
|
|
||||||
// Initialize our new LRU
|
|
||||||
self.cells_lru = CellsLRU.init(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the hints that we want for this
|
/// Returns the hints that we want for this
|
||||||
pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
|
pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
|
||||||
return .{
|
return .{
|
||||||
@ -535,9 +501,6 @@ pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void {
|
|||||||
// Set our new size, this will also reset our font atlas.
|
// Set our new size, this will also reset our font atlas.
|
||||||
try self.font_group.setSize(size);
|
try self.font_group.setSize(size);
|
||||||
|
|
||||||
// Invalidate our cell cache.
|
|
||||||
self.resetCellsLRU();
|
|
||||||
|
|
||||||
// Reset our GPU uniforms
|
// Reset our GPU uniforms
|
||||||
const metrics = try resetFontMetrics(
|
const metrics = try resetFontMetrics(
|
||||||
self.alloc,
|
self.alloc,
|
||||||
@ -607,7 +570,6 @@ pub fn render(
|
|||||||
// Data we extract out of the critical area.
|
// Data we extract out of the critical area.
|
||||||
const Critical = struct {
|
const Critical = struct {
|
||||||
gl_bg: terminal.color.RGB,
|
gl_bg: terminal.color.RGB,
|
||||||
active_screen: terminal.Terminal.ScreenType,
|
|
||||||
selection: ?terminal.Selection,
|
selection: ?terminal.Selection,
|
||||||
screen: terminal.Screen,
|
screen: terminal.Screen,
|
||||||
preedit: ?renderer.State.Preedit,
|
preedit: ?renderer.State.Preedit,
|
||||||
@ -668,7 +630,6 @@ pub fn render(
|
|||||||
|
|
||||||
break :critical .{
|
break :critical .{
|
||||||
.gl_bg = self.config.background,
|
.gl_bg = self.config.background,
|
||||||
.active_screen = state.terminal.active_screen,
|
|
||||||
.selection = selection,
|
.selection = selection,
|
||||||
.screen = screen_copy,
|
.screen = screen_copy,
|
||||||
.preedit = if (cursor_style != null) state.preedit else null,
|
.preedit = if (cursor_style != null) state.preedit else null,
|
||||||
@ -687,7 +648,6 @@ pub fn render(
|
|||||||
|
|
||||||
// Build our GPU cells
|
// Build our GPU cells
|
||||||
try self.rebuildCells(
|
try self.rebuildCells(
|
||||||
critical.active_screen,
|
|
||||||
critical.selection,
|
critical.selection,
|
||||||
&critical.screen,
|
&critical.screen,
|
||||||
critical.preedit,
|
critical.preedit,
|
||||||
@ -718,7 +678,6 @@ pub fn render(
|
|||||||
/// the renderer will do this when it needs more memory space.
|
/// the renderer will do this when it needs more memory space.
|
||||||
pub fn rebuildCells(
|
pub fn rebuildCells(
|
||||||
self: *OpenGL,
|
self: *OpenGL,
|
||||||
active_screen: terminal.Terminal.ScreenType,
|
|
||||||
term_selection: ?terminal.Selection,
|
term_selection: ?terminal.Selection,
|
||||||
screen: *terminal.Screen,
|
screen: *terminal.Screen,
|
||||||
preedit: ?renderer.State.Preedit,
|
preedit: ?renderer.State.Preedit,
|
||||||
@ -804,25 +763,6 @@ pub fn rebuildCells(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get our value from the cache.
|
|
||||||
const gop = try self.cells_lru.getOrPut(self.alloc, .{
|
|
||||||
.selection = selection,
|
|
||||||
.screen = active_screen,
|
|
||||||
.row_id = row.getId(),
|
|
||||||
});
|
|
||||||
if (!row.isDirty() and gop.found_existing) {
|
|
||||||
var i: usize = self.cells.items.len;
|
|
||||||
for (gop.value_ptr.items) |cell| {
|
|
||||||
self.cells.appendAssumeCapacity(cell);
|
|
||||||
self.cells.items[i].grid_row = @intCast(y);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Get the starting index for our row so we can cache any new GPU cells.
|
|
||||||
const start = self.cells.items.len;
|
|
||||||
|
|
||||||
// Split our row into runs and shape each one.
|
// Split our row into runs and shape each one.
|
||||||
var iter = self.font_shaper.runIterator(
|
var iter = self.font_shaper.runIterator(
|
||||||
self.font_group,
|
self.font_group,
|
||||||
@ -852,23 +792,6 @@ pub fn rebuildCells(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize our list
|
|
||||||
if (!gop.found_existing) {
|
|
||||||
gop.value_ptr.* = .{};
|
|
||||||
|
|
||||||
// If we evicted another value in our LRU for this one, free it
|
|
||||||
if (gop.evicted) |kv| {
|
|
||||||
var list = kv.value;
|
|
||||||
list.deinit(self.alloc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var row_cells = gop.value_ptr;
|
|
||||||
|
|
||||||
// Get our new length and cache the cells.
|
|
||||||
try row_cells.ensureTotalCapacity(self.alloc, screen.cols);
|
|
||||||
row_cells.clearRetainingCapacity();
|
|
||||||
try row_cells.appendSlice(self.alloc, self.cells.items[start..]);
|
|
||||||
|
|
||||||
// Set row is not dirty anymore
|
// Set row is not dirty anymore
|
||||||
row.setDirty(false);
|
row.setDirty(false);
|
||||||
}
|
}
|
||||||
@ -1331,15 +1254,6 @@ pub fn setScreenSize(
|
|||||||
self.padding.explicit,
|
self.padding.explicit,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update our LRU. We arbitrarily support a certain number of pages here.
|
|
||||||
// We also always support a minimum number of caching in case a user
|
|
||||||
// is resizing tiny then growing again we can save some of the renders.
|
|
||||||
const evicted = try self.cells_lru.resize(self.alloc, @max(80, grid_size.rows * 10));
|
|
||||||
if (evicted) |list| {
|
|
||||||
for (list) |*value| value.deinit(self.alloc);
|
|
||||||
self.alloc.free(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update our shaper
|
// Update our shaper
|
||||||
var shape_buf = try self.alloc.alloc(font.shape.Cell, grid_size.columns * 2);
|
var shape_buf = try self.alloc.alloc(font.shape.Cell, grid_size.columns * 2);
|
||||||
errdefer self.alloc.free(shape_buf);
|
errdefer self.alloc.free(shape_buf);
|
||||||
|
Reference in New Issue
Block a user