mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-29 11:57:57 +00:00
renderer: big rework, graphics API abstraction layers, unified logic
This commit is very large, representing about a month of work with many interdependent changes that don't separate cleanly in to atomic commits. The main change here is unifying the renderer logic to a single generic renderer, implemented on top of an abstraction layer over OpenGL/Metal. I'll write a more complete summary of the changes in the description of the PR.
This commit is contained in:
@@ -20,6 +20,16 @@ const log = std.log.scoped(.renderer_thread);
|
||||
const DRAW_INTERVAL = 8; // 120 FPS
|
||||
const CURSOR_BLINK_INTERVAL = 600;
|
||||
|
||||
/// Whether calls to `drawFrame` must be done from the app thread.
|
||||
///
|
||||
/// If this is `true` then we send a `redraw_surface` message to the apprt
|
||||
/// whenever we need to draw instead of calling `drawFrame` directly.
|
||||
const must_draw_from_app_thread =
|
||||
if (@hasDecl(apprt.App, "must_draw_from_app_thread"))
|
||||
apprt.App.must_draw_from_app_thread
|
||||
else
|
||||
false;
|
||||
|
||||
/// The type used for sending messages to the IO thread. For now this is
|
||||
/// hardcoded with a capacity. We can make this a comptime parameter in
|
||||
/// the future if we want it configurable.
|
||||
@@ -314,6 +324,16 @@ fn stopDrawTimer(self: *Thread) void {
|
||||
|
||||
/// Drain the mailbox.
|
||||
fn drainMailbox(self: *Thread) !void {
|
||||
// There's probably a more elegant way to do this...
|
||||
//
|
||||
// This is effectively an @autoreleasepool{} block, which we need in
|
||||
// order to ensure that autoreleased objects are properly released.
|
||||
const pool = if (builtin.os.tag.isDarwin())
|
||||
@import("objc").AutoreleasePool.init()
|
||||
else
|
||||
void;
|
||||
defer if (builtin.os.tag.isDarwin()) pool.deinit();
|
||||
|
||||
while (self.mailbox.pop()) |message| {
|
||||
log.debug("mailbox message={}", .{message});
|
||||
switch (message) {
|
||||
@@ -432,7 +452,7 @@ fn drainMailbox(self: *Thread) !void {
|
||||
self.renderer.markDirty();
|
||||
},
|
||||
|
||||
.resize => |v| try self.renderer.setScreenSize(v),
|
||||
.resize => {}, //|v| try self.renderer.setScreenSize(v),
|
||||
|
||||
.change_config => |config| {
|
||||
defer config.alloc.destroy(config.thread);
|
||||
@@ -468,20 +488,16 @@ fn drawFrame(self: *Thread, now: bool) void {
|
||||
if (!self.flags.visible) return;
|
||||
|
||||
// If the renderer is managing a vsync on its own, we only draw
|
||||
// when we're forced to via now.
|
||||
// when we're forced to via `now`.
|
||||
if (!now and self.renderer.hasVsync()) return;
|
||||
|
||||
// If we're doing single-threaded GPU calls then we just wake up the
|
||||
// app thread to redraw at this point.
|
||||
if (rendererpkg.Renderer == rendererpkg.OpenGL and
|
||||
rendererpkg.OpenGL.single_threaded_draw)
|
||||
{
|
||||
if (must_draw_from_app_thread) {
|
||||
_ = self.app_mailbox.push(
|
||||
.{ .redraw_surface = self.surface },
|
||||
.{ .instant = {} },
|
||||
);
|
||||
} else {
|
||||
self.renderer.drawFrame(self.surface) catch |err|
|
||||
self.renderer.drawFrame(false) catch |err|
|
||||
log.warn("error drawing err={}", .{err});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user