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:
Mitchell Hashimoto
2023-09-22 09:47:01 -07:00
parent bebf6bb108
commit 4b8056afd8

View File

@ -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);