opengl: make setting font size thread safe

This commit is contained in:
Mitchell Hashimoto
2023-02-23 18:53:06 -08:00
parent da64fff110
commit aa49cceb49

View File

@ -105,6 +105,7 @@ surface_mailbox: apprt.surface.Mailbox,
/// Some runtimes (GTK) do not support multi-threading so to keep our logic /// Some runtimes (GTK) do not support multi-threading so to keep our logic
/// simple we apply all OpenGL context changes in the render() call. /// simple we apply all OpenGL context changes in the render() call.
deferred_screen_size: ?SetScreenSize = null, deferred_screen_size: ?SetScreenSize = null,
deferred_font_size: ?SetFontSize = null,
/// If we're drawing with single threaded operations /// If we're drawing with single threaded operations
draw_mutex: DrawMutex = drawMutexZero, draw_mutex: DrawMutex = drawMutexZero,
@ -157,6 +158,19 @@ const SetScreenSize = struct {
} }
}; };
const SetFontSize = struct {
metrics: font.face.Metrics,
fn apply(self: SetFontSize, r: *const OpenGL) !void {
try r.program.setUniform(
"cell_size",
@Vector(2, f32){ self.metrics.cell_width, self.metrics.cell_height },
);
try r.program.setUniform("strikethrough_position", self.metrics.strikethrough_position);
try r.program.setUniform("strikethrough_thickness", self.metrics.strikethrough_thickness);
}
};
/// The raw structure that maps directly to the buffer sent to the vertex shader. /// The raw structure that maps directly to the buffer sent to the vertex shader.
/// This must be "extern" so that the field order is not reordered by the /// This must be "extern" so that the field order is not reordered by the
/// Zig compiler. /// Zig compiler.
@ -239,14 +253,11 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
); );
// Setup our font metrics uniform // Setup our font metrics uniform
const metrics = try resetFontMetrics(alloc, program, options.font_group); const metrics = try resetFontMetrics(alloc, options.font_group);
// Set our cell dimensions // Set our cell dimensions
const pbind = try program.use(); const pbind = try program.use();
defer pbind.unbind(); defer pbind.unbind();
try program.setUniform("cell_size", @Vector(2, f32){ metrics.cell_width, metrics.cell_height });
try program.setUniform("strikethrough_position", metrics.strikethrough_position);
try program.setUniform("strikethrough_thickness", metrics.strikethrough_thickness);
// Set all of our texture indexes // Set all of our texture indexes
try program.setUniform("text", 0); try program.setUniform("text", 0);
@ -379,6 +390,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
.focused = true, .focused = true,
.padding = options.padding, .padding = options.padding,
.surface_mailbox = options.surface_mailbox, .surface_mailbox = options.surface_mailbox,
.deferred_font_size = .{ .metrics = metrics },
}; };
} }
@ -571,8 +583,10 @@ pub fn blinkCursor(self: *OpenGL, reset: bool) void {
/// ///
/// Must be called on the render thread. /// Must be called on the render thread.
pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void { pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void {
if (single_threaded_draw) self.draw_mutex.lock();
defer if (single_threaded_draw) self.draw_mutex.unlock();
log.info("set font size={}", .{size}); log.info("set font size={}", .{size});
if (apprt.runtime == apprt.gtk) @panic("TODO: make thread safe");
// 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);
@ -581,7 +595,10 @@ pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void {
self.resetCellsLRU(); self.resetCellsLRU();
// Reset our GPU uniforms // Reset our GPU uniforms
const metrics = try resetFontMetrics(self.alloc, self.program, self.font_group); const metrics = try resetFontMetrics(self.alloc, self.font_group);
// Defer our GPU updates
self.deferred_font_size = .{ .metrics = metrics };
// Recalculate our cell size. If it is the same as before, then we do // Recalculate our cell size. If it is the same as before, then we do
// nothing since the grid size couldn't have possibly changed. // nothing since the grid size couldn't have possibly changed.
@ -599,7 +616,6 @@ pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void {
/// down to the GPU. /// down to the GPU.
fn resetFontMetrics( fn resetFontMetrics(
alloc: Allocator, alloc: Allocator,
program: gl.Program,
font_group: *font.GroupCache, font_group: *font.GroupCache,
) !font.face.Metrics { ) !font.face.Metrics {
// Get our cell metrics based on a regular font ascii 'M'. Why 'M'? // Get our cell metrics based on a regular font ascii 'M'. Why 'M'?
@ -620,13 +636,6 @@ fn resetFontMetrics(
.underline_position = @floatToInt(u32, metrics.underline_position), .underline_position = @floatToInt(u32, metrics.underline_position),
}; };
// Set our uniforms that rely on metrics
const pbind = try program.use();
defer pbind.unbind();
try program.setUniform("cell_size", @Vector(2, f32){ metrics.cell_width, metrics.cell_height });
try program.setUniform("strikethrough_position", metrics.strikethrough_position);
try program.setUniform("strikethrough_thickness", metrics.strikethrough_thickness);
return metrics; return metrics;
} }
@ -1173,6 +1182,9 @@ fn gridSize(self: *const OpenGL, screen_size: renderer.ScreenSize) renderer.Grid
/// Set the screen size for rendering. This will update the projection /// Set the screen size for rendering. This will update the projection
/// used for the shader so that the scaling of the grid is correct. /// used for the shader so that the scaling of the grid is correct.
pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void { pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
if (single_threaded_draw) self.draw_mutex.lock();
defer if (single_threaded_draw) self.draw_mutex.unlock();
// Recalculate the rows/columns. // Recalculate the rows/columns.
const grid_size = self.gridSize(dim); const grid_size = self.gridSize(dim);
@ -1329,6 +1341,10 @@ pub fn draw(self: *OpenGL) !void {
try v.apply(self); try v.apply(self);
self.deferred_screen_size = null; self.deferred_screen_size = null;
} }
if (self.deferred_font_size) |v| {
try v.apply(self);
self.deferred_font_size = null;
}
try self.drawCells(binding, self.cells_bg); try self.drawCells(binding, self.cells_bg);
try self.drawCells(binding, self.cells); try self.drawCells(binding, self.cells);