renderer: separate update frame data from draw

This commit is contained in:
Mitchell Hashimoto
2023-11-14 14:13:39 -08:00
parent 0230222c0d
commit 0e92f68228
2 changed files with 39 additions and 22 deletions

View File

@ -76,6 +76,10 @@ background_color: terminal.color.RGB,
/// by a terminal application
cursor_color: ?terminal.color.RGB,
/// The current frame background color. This is only updated during
/// the updateFrame method.
current_background_color: terminal.color.RGB,
/// The current set of cells to render. This is rebuilt on every frame
/// but we keep this around so that we don't reallocate. Each set of
/// cells goes into a separate shader.
@ -271,6 +275,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
.foreground_color = options.config.foreground,
.background_color = options.config.background,
.cursor_color = options.config.cursor_color,
.current_background_color = options.config.background,
// Render state
.cells_bg = .{},
@ -448,8 +453,8 @@ pub fn setFontSize(self: *Metal, size: font.face.DesiredSize) !void {
}, .{ .forever = {} });
}
/// The primary render callback that is completely thread-safe.
pub fn render(
/// Update the frame data.
pub fn updateFrame(
self: *Metal,
surface: *apprt.Surface,
state: *renderer.State,
@ -535,10 +540,6 @@ pub fn render(
};
defer critical.screen.deinit();
// @autoreleasepool {}
const pool = objc.AutoreleasePool.init();
defer pool.deinit();
// Build our GPU cells
try self.rebuildCells(
critical.selection,
@ -547,18 +548,8 @@ pub fn render(
critical.cursor_style,
);
// Get our drawable (CAMetalDrawable)
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
// If our font atlas changed, sync the texture data
if (self.font_group.atlas_greyscale.modified) {
try syncAtlasTexture(self.device, &self.font_group.atlas_greyscale, &self.texture_greyscale);
self.font_group.atlas_greyscale.modified = false;
}
if (self.font_group.atlas_color.modified) {
try syncAtlasTexture(self.device, &self.font_group.atlas_color, &self.texture_color);
self.font_group.atlas_color.modified = false;
}
// Update our background color
self.current_background_color = critical.bg;
// Go through our images and see if we need to setup any textures.
{
@ -580,6 +571,26 @@ pub fn render(
}
}
}
}
/// Draw the frame to the screen.
pub fn drawFrame(self: *Metal) !void {
// @autoreleasepool {}
const pool = objc.AutoreleasePool.init();
defer pool.deinit();
// Get our drawable (CAMetalDrawable)
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
// If our font atlas changed, sync the texture data
if (self.font_group.atlas_greyscale.modified) {
try syncAtlasTexture(self.device, &self.font_group.atlas_greyscale, &self.texture_greyscale);
self.font_group.atlas_greyscale.modified = false;
}
if (self.font_group.atlas_color.modified) {
try syncAtlasTexture(self.device, &self.font_group.atlas_color, &self.texture_color);
self.font_group.atlas_color.modified = false;
}
// Command buffer (MTLCommandBuffer)
const buffer = self.queue.msgSend(objc.Object, objc.sel("commandBuffer"), .{});
@ -612,9 +623,9 @@ pub fn render(
attachment.setProperty("storeAction", @intFromEnum(mtl.MTLStoreAction.store));
attachment.setProperty("texture", texture);
attachment.setProperty("clearColor", mtl.MTLClearColor{
.red = @as(f32, @floatFromInt(critical.bg.r)) / 255,
.green = @as(f32, @floatFromInt(critical.bg.g)) / 255,
.blue = @as(f32, @floatFromInt(critical.bg.b)) / 255,
.red = @as(f32, @floatFromInt(self.current_background_color.r)) / 255,
.green = @as(f32, @floatFromInt(self.current_background_color.g)) / 255,
.blue = @as(f32, @floatFromInt(self.current_background_color.b)) / 255,
.alpha = self.config.background_opacity,
});
}

View File

@ -346,7 +346,8 @@ fn renderCallback(
_ = t.app_mailbox.push(.{ .redraw_inspector = t.surface }, .{ .instant = {} });
}
t.renderer.render(
// Update our frame data
t.renderer.updateFrame(
t.surface,
t.state,
t.flags.cursor_blink_visible,
@ -359,8 +360,13 @@ fn renderCallback(
renderer.OpenGL.single_threaded_draw)
{
_ = t.app_mailbox.push(.{ .redraw_surface = t.surface }, .{ .instant = {} });
return .disarm;
}
// Draw
t.renderer.drawFrame() catch |err|
log.warn("error drawing err={}", .{err});
return .disarm;
}