mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
opengl: move screen size GL context changes into draw path
This commit is contained in:
@ -89,7 +89,7 @@ pub const App = struct {
|
|||||||
c.g_object_unref(self.app);
|
c.g_object_unref(self.app);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wakeup(self: App) !void {
|
pub fn wakeup(self: App) void {
|
||||||
_ = self;
|
_ = self;
|
||||||
c.g_main_context_wakeup(null);
|
c.g_main_context_wakeup(null);
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ pub const Surface = struct {
|
|||||||
opts.gl_area,
|
opts.gl_area,
|
||||||
"realize",
|
"realize",
|
||||||
c.G_CALLBACK(>kRealize),
|
c.G_CALLBACK(>kRealize),
|
||||||
null,
|
self,
|
||||||
null,
|
null,
|
||||||
c.G_CONNECT_DEFAULT,
|
c.G_CONNECT_DEFAULT,
|
||||||
);
|
);
|
||||||
@ -201,28 +201,36 @@ pub const Surface = struct {
|
|||||||
null,
|
null,
|
||||||
c.G_CONNECT_DEFAULT,
|
c.G_CONNECT_DEFAULT,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// // Add ourselves to the list of surfaces on the app.
|
fn realize(self: *Surface) !void {
|
||||||
// try app.app.addSurface(self);
|
// Add ourselves to the list of surfaces on the app.
|
||||||
// errdefer app.app.deleteSurface(self);
|
try self.app.core_app.addSurface(self);
|
||||||
//
|
errdefer self.app.core_app.deleteSurface(self);
|
||||||
// // Initialize our surface now that we have the stable pointer.
|
|
||||||
// try self.core_surface.init(
|
// Initialize our surface now that we have the stable pointer.
|
||||||
// app.app.alloc,
|
try self.core_surface.init(
|
||||||
// app.app.config,
|
self.app.core_app.alloc,
|
||||||
// .{ .rt_app = app, .mailbox = &app.app.mailbox },
|
self.app.core_app.config,
|
||||||
// self,
|
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
|
||||||
// );
|
self,
|
||||||
// errdefer self.core_surface.deinit();
|
);
|
||||||
|
errdefer self.core_surface.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
||||||
_ = area;
|
_ = area;
|
||||||
_ = ud;
|
|
||||||
|
|
||||||
log.debug("gl surface realized", .{});
|
log.debug("gl surface realized", .{});
|
||||||
const opengl = @import("../renderer/opengl/main.zig");
|
|
||||||
log.warn("foo: {}", .{opengl.glad.load(null) catch 0});
|
// realize means that our OpenGL context is ready, so we can now
|
||||||
|
// initialize the core surface which will setup the renderer.
|
||||||
|
const self = userdataSelf(ud orelse return);
|
||||||
|
self.realize() catch |err| {
|
||||||
|
// TODO: we need to destroy the GL area here.
|
||||||
|
log.err("surface failed to realize: {}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) c.gboolean {
|
fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) c.gboolean {
|
||||||
|
@ -91,6 +91,55 @@ padding: renderer.Options.Padding,
|
|||||||
/// The mailbox for communicating with the window.
|
/// The mailbox for communicating with the window.
|
||||||
surface_mailbox: apprt.surface.Mailbox,
|
surface_mailbox: apprt.surface.Mailbox,
|
||||||
|
|
||||||
|
/// Deferred operations. This is used to apply changes to the OpenGL context.
|
||||||
|
/// Some runtimes (GTK) do not support multi-threading so to keep our logic
|
||||||
|
/// simple we apply all OpenGL context changes in the render() call.
|
||||||
|
deferred_screen_size: ?SetScreenSize = null,
|
||||||
|
|
||||||
|
/// Defererred OpenGL operation to update the screen size.
|
||||||
|
const SetScreenSize = struct {
|
||||||
|
size: renderer.ScreenSize,
|
||||||
|
|
||||||
|
fn apply(self: SetScreenSize, r: *const OpenGL) !void {
|
||||||
|
// Apply our padding
|
||||||
|
const padding = r.padding.explicit.add(if (r.padding.balance)
|
||||||
|
renderer.Padding.balanced(self.size, r.gridSize(self.size), r.cell_size)
|
||||||
|
else
|
||||||
|
.{});
|
||||||
|
const padded_size = self.size.subPadding(padding);
|
||||||
|
|
||||||
|
log.debug("GL api: screen size padded={} screen={} grid={} cell={} padding={}", .{
|
||||||
|
padded_size,
|
||||||
|
self.size,
|
||||||
|
r.gridSize(self.size),
|
||||||
|
r.cell_size,
|
||||||
|
r.padding.explicit,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update our viewport for this context to be the entire window.
|
||||||
|
// OpenGL works in pixels, so we have to use the pixel size.
|
||||||
|
try gl.viewport(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
@intCast(i32, self.size.width),
|
||||||
|
@intCast(i32, self.size.height),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the projection uniform within our shader
|
||||||
|
try r.program.setUniform(
|
||||||
|
"projection",
|
||||||
|
|
||||||
|
// 2D orthographic projection with the full w/h
|
||||||
|
math.ortho2d(
|
||||||
|
-1 * padding.left,
|
||||||
|
@intToFloat(f32, padded_size.width) + padding.right,
|
||||||
|
@intToFloat(f32, padded_size.height) + padding.bottom,
|
||||||
|
-1 * padding.top,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -366,7 +415,22 @@ pub fn glfwWindowHints() glfw.Window.Hints {
|
|||||||
pub fn surfaceInit(surface: *apprt.Surface) !void {
|
pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||||
// Treat this like a thread entry
|
// Treat this like a thread entry
|
||||||
const self: OpenGL = undefined;
|
const self: OpenGL = undefined;
|
||||||
try self.threadEnter(surface);
|
|
||||||
|
switch (apprt.runtime) {
|
||||||
|
else => @compileError("unsupported app runtime for OpenGL"),
|
||||||
|
|
||||||
|
apprt.gtk => {
|
||||||
|
// GTK uses global OpenGL context so we load from null.
|
||||||
|
const version = try gl.glad.load(null);
|
||||||
|
errdefer gl.glad.unload();
|
||||||
|
log.info("loaded OpenGL {}.{}", .{
|
||||||
|
gl.glad.versionMajor(@intCast(c_uint, version)),
|
||||||
|
gl.glad.versionMinor(@intCast(c_uint, version)),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
apprt.glfw => try self.threadEnter(surface),
|
||||||
|
}
|
||||||
|
|
||||||
// Blending for text. We use GL_ONE here because we should be using
|
// Blending for text. We use GL_ONE here because we should be using
|
||||||
// premultiplied alpha for all our colors in our fragment shaders.
|
// premultiplied alpha for all our colors in our fragment shaders.
|
||||||
@ -459,7 +523,10 @@ pub fn threadExit(self: *const OpenGL) void {
|
|||||||
switch (apprt.runtime) {
|
switch (apprt.runtime) {
|
||||||
else => @compileError("unsupported app runtime for OpenGL"),
|
else => @compileError("unsupported app runtime for OpenGL"),
|
||||||
|
|
||||||
apprt.gtk => {},
|
apprt.gtk => {
|
||||||
|
// We don't need to do any unloading for GTK because we may
|
||||||
|
// be sharing the global bindings with other windows.
|
||||||
|
},
|
||||||
|
|
||||||
apprt.glfw => {
|
apprt.glfw => {
|
||||||
gl.glad.unload();
|
gl.glad.unload();
|
||||||
@ -550,6 +617,7 @@ pub fn render(
|
|||||||
surface: *apprt.Surface,
|
surface: *apprt.Surface,
|
||||||
state: *renderer.State,
|
state: *renderer.State,
|
||||||
) !void {
|
) !void {
|
||||||
|
log.warn("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,
|
||||||
@ -1075,7 +1143,7 @@ pub fn updateCell(
|
|||||||
|
|
||||||
/// Returns the grid size for a given screen size. This is safe to call
|
/// Returns the grid size for a given screen size. This is safe to call
|
||||||
/// on any thread.
|
/// on any thread.
|
||||||
fn gridSize(self: *OpenGL, screen_size: renderer.ScreenSize) renderer.GridSize {
|
fn gridSize(self: *const OpenGL, screen_size: renderer.ScreenSize) renderer.GridSize {
|
||||||
return renderer.GridSize.init(
|
return renderer.GridSize.init(
|
||||||
screen_size.subPadding(self.padding.explicit),
|
screen_size.subPadding(self.padding.explicit),
|
||||||
self.cell_size,
|
self.cell_size,
|
||||||
@ -1088,15 +1156,7 @@ pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
|
|||||||
// Recalculate the rows/columns.
|
// Recalculate the rows/columns.
|
||||||
const grid_size = self.gridSize(dim);
|
const grid_size = self.gridSize(dim);
|
||||||
|
|
||||||
// Apply our padding
|
log.debug("screen size screen={} grid={} cell={} padding={}", .{
|
||||||
const padding = self.padding.explicit.add(if (self.padding.balance)
|
|
||||||
renderer.Padding.balanced(dim, grid_size, self.cell_size)
|
|
||||||
else
|
|
||||||
.{});
|
|
||||||
const padded_dim = dim.subPadding(padding);
|
|
||||||
|
|
||||||
log.debug("screen size padded={} screen={} grid={} cell={} padding={}", .{
|
|
||||||
padded_dim,
|
|
||||||
dim,
|
dim,
|
||||||
grid_size,
|
grid_size,
|
||||||
self.cell_size,
|
self.cell_size,
|
||||||
@ -1118,31 +1178,8 @@ pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
|
|||||||
self.alloc.free(self.font_shaper.cell_buf);
|
self.alloc.free(self.font_shaper.cell_buf);
|
||||||
self.font_shaper.cell_buf = shape_buf;
|
self.font_shaper.cell_buf = shape_buf;
|
||||||
|
|
||||||
// Update our viewport for this context to be the entire window.
|
// Defer our OpenGL updates
|
||||||
// OpenGL works in pixels, so we have to use the pixel size.
|
self.deferred_screen_size = .{ .size = dim };
|
||||||
try gl.viewport(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
@intCast(i32, dim.width),
|
|
||||||
@intCast(i32, dim.height),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the projection uniform within our shader
|
|
||||||
{
|
|
||||||
const bind = try self.program.use();
|
|
||||||
defer bind.unbind();
|
|
||||||
try self.program.setUniform(
|
|
||||||
"projection",
|
|
||||||
|
|
||||||
// 2D orthographic projection with the full w/h
|
|
||||||
math.ortho2d(
|
|
||||||
-1 * padding.left,
|
|
||||||
@intToFloat(f32, padded_dim.width) + padding.right,
|
|
||||||
@intToFloat(f32, padded_dim.height) + padding.bottom,
|
|
||||||
-1 * padding.top,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the font texture atlas if it is dirty.
|
/// Updates the font texture atlas if it is dirty.
|
||||||
@ -1250,6 +1287,12 @@ pub fn draw(self: *OpenGL) !void {
|
|||||||
const pbind = try self.program.use();
|
const pbind = try self.program.use();
|
||||||
defer pbind.unbind();
|
defer pbind.unbind();
|
||||||
|
|
||||||
|
// If we have deferred operations, run them.
|
||||||
|
if (self.deferred_screen_size) |v| {
|
||||||
|
try v.apply(self);
|
||||||
|
self.deferred_screen_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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user