mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
window no longer makes any OpenGL calls
This commit is contained in:
102
src/Window.zig
102
src/Window.zig
@ -10,8 +10,8 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const renderer = @import("renderer.zig");
|
const renderer = @import("renderer.zig");
|
||||||
|
const objc = @import("objc");
|
||||||
const glfw = @import("glfw");
|
const glfw = @import("glfw");
|
||||||
const gl = @import("opengl.zig");
|
|
||||||
const imgui = @import("imgui");
|
const imgui = @import("imgui");
|
||||||
const libuv = @import("libuv");
|
const libuv = @import("libuv");
|
||||||
const Pty = @import("Pty.zig");
|
const Pty = @import("Pty.zig");
|
||||||
@ -30,6 +30,9 @@ const log = std.log.scoped(.window);
|
|||||||
// enough to satisfy most write requests. It must be a power of 2.
|
// enough to satisfy most write requests. It must be a power of 2.
|
||||||
const WRITE_REQ_PREALLOC = std.math.pow(usize, 2, 5);
|
const WRITE_REQ_PREALLOC = std.math.pow(usize, 2, 5);
|
||||||
|
|
||||||
|
// The renderer implementation to use.
|
||||||
|
const Renderer = renderer.OpenGL;
|
||||||
|
|
||||||
/// Allocator
|
/// Allocator
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
alloc_io_arena: std.heap.ArenaAllocator,
|
alloc_io_arena: std.heap.ArenaAllocator,
|
||||||
@ -48,7 +51,7 @@ cursor: glfw.Cursor,
|
|||||||
imgui_ctx: if (DevMode.enabled) *imgui.Context else void,
|
imgui_ctx: if (DevMode.enabled) *imgui.Context else void,
|
||||||
|
|
||||||
/// The renderer for this window.
|
/// The renderer for this window.
|
||||||
renderer: renderer.OpenGL,
|
renderer: Renderer,
|
||||||
|
|
||||||
/// The render state
|
/// The render state
|
||||||
renderer_state: renderer.State,
|
renderer_state: renderer.State,
|
||||||
@ -166,59 +169,9 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
errdefer alloc.destroy(self);
|
errdefer alloc.destroy(self);
|
||||||
|
|
||||||
// Create our window
|
// Create our window
|
||||||
const window = try glfw.Window.create(640, 480, "ghostty", null, null, .{
|
const window = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
||||||
.context_version_major = 3,
|
|
||||||
.context_version_minor = 3,
|
|
||||||
.opengl_profile = .opengl_core_profile,
|
|
||||||
.opengl_forward_compat = true,
|
|
||||||
.cocoa_graphics_switching = builtin.os.tag == .macos,
|
|
||||||
.cocoa_retina_framebuffer = true,
|
|
||||||
});
|
|
||||||
errdefer window.destroy();
|
errdefer window.destroy();
|
||||||
|
try Renderer.windowInit(window);
|
||||||
// NOTE(multi-window): We'll need to extract all the below into a
|
|
||||||
// dedicated renderer and consider the multi-threading (or at the very
|
|
||||||
// least: multi-OpenGL-context) implications. Since we don't support
|
|
||||||
// multiple windows right now, we just do it all here.
|
|
||||||
|
|
||||||
// Setup OpenGL
|
|
||||||
try glfw.makeContextCurrent(window);
|
|
||||||
try glfw.swapInterval(1);
|
|
||||||
|
|
||||||
// Load OpenGL bindings
|
|
||||||
const version = try gl.glad.load(switch (builtin.zig_backend) {
|
|
||||||
.stage1 => glfw.getProcAddress,
|
|
||||||
else => &glfw.getProcAddress,
|
|
||||||
});
|
|
||||||
log.info("loaded OpenGL {}.{}", .{
|
|
||||||
gl.glad.versionMajor(version),
|
|
||||||
gl.glad.versionMinor(version),
|
|
||||||
});
|
|
||||||
// These are very noisy so this is commented, but easy to uncomment
|
|
||||||
// whenever we need to check the OpenGL extension list
|
|
||||||
// if (builtin.mode == .Debug) {
|
|
||||||
// var ext_iter = try gl.ext.iterator();
|
|
||||||
// while (try ext_iter.next()) |ext| {
|
|
||||||
// log.debug("OpenGL extension available name={s}", .{ext});
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (builtin.mode == .Debug) {
|
|
||||||
// Get our physical DPI - debug only because we don't have a use for
|
|
||||||
// this but the logging of it may be useful
|
|
||||||
const monitor = window.getMonitor() orelse monitor: {
|
|
||||||
log.warn("window had null monitor, getting primary monitor", .{});
|
|
||||||
break :monitor glfw.Monitor.getPrimary().?;
|
|
||||||
};
|
|
||||||
const physical_size = monitor.getPhysicalSize();
|
|
||||||
const video_mode = try monitor.getVideoMode();
|
|
||||||
const physical_x_dpi = @intToFloat(f32, video_mode.getWidth()) / (@intToFloat(f32, physical_size.width_mm) / 25.4);
|
|
||||||
const physical_y_dpi = @intToFloat(f32, video_mode.getHeight()) / (@intToFloat(f32, physical_size.height_mm) / 25.4);
|
|
||||||
log.debug("physical dpi x={} y={}", .{
|
|
||||||
physical_x_dpi,
|
|
||||||
physical_y_dpi,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine our DPI configurations so we can properly configure
|
// Determine our DPI configurations so we can properly configure
|
||||||
// font points to pixels and handle other high-DPI scaling factors.
|
// font points to pixels and handle other high-DPI scaling factors.
|
||||||
@ -232,15 +185,6 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
y_dpi,
|
y_dpi,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Culling, probably not necessary. We have to change the winding
|
|
||||||
// order since our 0,0 is top-left.
|
|
||||||
try gl.enable(gl.c.GL_CULL_FACE);
|
|
||||||
try gl.frontFace(gl.c.GL_CW);
|
|
||||||
|
|
||||||
// Blending for text
|
|
||||||
try gl.enable(gl.c.GL_BLEND);
|
|
||||||
try gl.blendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
// The font size we desire along with the DPI determiend for the window
|
// The font size we desire along with the DPI determiend for the window
|
||||||
const font_size: font.face.DesiredSize = .{
|
const font_size: font.face.DesiredSize = .{
|
||||||
.points = config.@"font-size",
|
.points = config.@"font-size",
|
||||||
@ -359,12 +303,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
errdefer font_group.deinit(alloc);
|
errdefer font_group.deinit(alloc);
|
||||||
|
|
||||||
// Create our terminal grid with the initial window size
|
// Create our terminal grid with the initial window size
|
||||||
const window_size = try window.getSize();
|
var renderer_impl = try Renderer.init(alloc, font_group);
|
||||||
const screen_size: renderer.ScreenSize = .{
|
|
||||||
.width = window_size.width,
|
|
||||||
.height = window_size.height,
|
|
||||||
};
|
|
||||||
var renderer_impl = try renderer.OpenGL.init(alloc, font_group);
|
|
||||||
renderer_impl.background = .{
|
renderer_impl.background = .{
|
||||||
.r = config.background.r,
|
.r = config.background.r,
|
||||||
.g = config.background.g,
|
.g = config.background.g,
|
||||||
@ -377,6 +316,11 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Calculate our grid size based on known dimensions.
|
// Calculate our grid size based on known dimensions.
|
||||||
|
const window_size = try window.getSize();
|
||||||
|
const screen_size: renderer.ScreenSize = .{
|
||||||
|
.width = window_size.width,
|
||||||
|
.height = window_size.height,
|
||||||
|
};
|
||||||
const grid_size = renderer.GridSize.init(screen_size, renderer_impl.cell_size);
|
const grid_size = renderer.GridSize.init(screen_size, renderer_impl.cell_size);
|
||||||
|
|
||||||
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
||||||
@ -546,21 +490,13 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
const style = try imgui.Style.get();
|
const style = try imgui.Style.get();
|
||||||
style.colorsDark();
|
style.colorsDark();
|
||||||
|
|
||||||
// Initialize for our window
|
|
||||||
assert(imgui.ImplGlfw.initForOpenGL(
|
|
||||||
@ptrCast(*imgui.ImplGlfw.GLFWWindow, window.handle),
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
assert(imgui.ImplOpenGL3.init("#version 330 core"));
|
|
||||||
|
|
||||||
// Add our window to the instance
|
// Add our window to the instance
|
||||||
DevMode.instance.window = self;
|
DevMode.instance.window = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload our context prior to switching over to the renderer thread
|
// Give the renderer one more opportunity to finalize any window
|
||||||
// because OpenGL requires it to be unloaded.
|
// setup on the main thread prior to spinning up the rendering thread.
|
||||||
gl.glad.unload();
|
try renderer_impl.finalizeInit(window);
|
||||||
try glfw.makeContextCurrent(null);
|
|
||||||
|
|
||||||
// Start our renderer thread
|
// Start our renderer thread
|
||||||
self.renderer_thr = try std.Thread.spawn(
|
self.renderer_thr = try std.Thread.spawn(
|
||||||
@ -582,6 +518,9 @@ pub fn destroy(self: *Window) void {
|
|||||||
// We need to become the active rendering thread again
|
// We need to become the active rendering thread again
|
||||||
self.renderer.threadEnter(self.window) catch unreachable;
|
self.renderer.threadEnter(self.window) catch unreachable;
|
||||||
self.renderer_thread.deinit();
|
self.renderer_thread.deinit();
|
||||||
|
|
||||||
|
// Deinit our renderer
|
||||||
|
self.renderer.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DevMode.enabled) {
|
if (DevMode.enabled) {
|
||||||
@ -589,8 +528,6 @@ pub fn destroy(self: *Window) void {
|
|||||||
DevMode.instance.window = null;
|
DevMode.instance.window = null;
|
||||||
|
|
||||||
// Uninitialize imgui
|
// Uninitialize imgui
|
||||||
imgui.ImplOpenGL3.shutdown();
|
|
||||||
imgui.ImplGlfw.shutdown();
|
|
||||||
self.imgui_ctx.destroy();
|
self.imgui_ctx.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +538,6 @@ pub fn destroy(self: *Window) void {
|
|||||||
log.err("error waiting for command to exit: {}", .{err});
|
log.err("error waiting for command to exit: {}", .{err});
|
||||||
|
|
||||||
self.terminal.deinit(self.alloc);
|
self.terminal.deinit(self.alloc);
|
||||||
self.renderer.deinit();
|
|
||||||
self.window.destroy();
|
self.window.destroy();
|
||||||
|
|
||||||
self.terminal_cursor.timer.close((struct {
|
self.terminal_cursor.timer.close((struct {
|
||||||
|
@ -17,6 +17,7 @@ const gl = @import("../opengl.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 lru = @import("../lru.zig");
|
||||||
|
const DevMode = @import("../DevMode.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.grid);
|
const log = std.log.scoped(.grid);
|
||||||
|
|
||||||
@ -306,6 +307,11 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *OpenGL) void {
|
pub fn deinit(self: *OpenGL) void {
|
||||||
|
if (DevMode.enabled) {
|
||||||
|
imgui.ImplOpenGL3.shutdown();
|
||||||
|
imgui.ImplGlfw.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
self.font_shaper.deinit();
|
self.font_shaper.deinit();
|
||||||
self.alloc.free(self.font_shaper.cell_buf);
|
self.alloc.free(self.font_shaper.cell_buf);
|
||||||
|
|
||||||
@ -331,6 +337,77 @@ pub fn deinit(self: *OpenGL) void {
|
|||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the hints that we want for this
|
||||||
|
pub fn windowHints() glfw.Window.Hints {
|
||||||
|
return .{
|
||||||
|
.context_version_major = 3,
|
||||||
|
.context_version_minor = 3,
|
||||||
|
.opengl_profile = .opengl_core_profile,
|
||||||
|
.opengl_forward_compat = true,
|
||||||
|
.cocoa_graphics_switching = builtin.os.tag == .macos,
|
||||||
|
.cocoa_retina_framebuffer = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is called early right after window creation to setup our
|
||||||
|
/// window surface as necessary.
|
||||||
|
pub fn windowInit(window: glfw.Window) !void {
|
||||||
|
// Treat this like a thread entry
|
||||||
|
const self: OpenGL = undefined;
|
||||||
|
try self.threadEnter(window);
|
||||||
|
|
||||||
|
// Culling, probably not necessary. We have to change the winding
|
||||||
|
// order since our 0,0 is top-left.
|
||||||
|
try gl.enable(gl.c.GL_CULL_FACE);
|
||||||
|
try gl.frontFace(gl.c.GL_CW);
|
||||||
|
|
||||||
|
// Blending for text
|
||||||
|
try gl.enable(gl.c.GL_BLEND);
|
||||||
|
try gl.blendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// These are very noisy so this is commented, but easy to uncomment
|
||||||
|
// whenever we need to check the OpenGL extension list
|
||||||
|
// if (builtin.mode == .Debug) {
|
||||||
|
// var ext_iter = try gl.ext.iterator();
|
||||||
|
// while (try ext_iter.next()) |ext| {
|
||||||
|
// log.debug("OpenGL extension available name={s}", .{ext});
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (builtin.mode == .Debug) {
|
||||||
|
// Get our physical DPI - debug only because we don't have a use for
|
||||||
|
// this but the logging of it may be useful
|
||||||
|
const monitor = window.getMonitor() orelse monitor: {
|
||||||
|
log.warn("window had null monitor, getting primary monitor", .{});
|
||||||
|
break :monitor glfw.Monitor.getPrimary().?;
|
||||||
|
};
|
||||||
|
const physical_size = monitor.getPhysicalSize();
|
||||||
|
const video_mode = try monitor.getVideoMode();
|
||||||
|
const physical_x_dpi = @intToFloat(f32, video_mode.getWidth()) / (@intToFloat(f32, physical_size.width_mm) / 25.4);
|
||||||
|
const physical_y_dpi = @intToFloat(f32, video_mode.getHeight()) / (@intToFloat(f32, physical_size.height_mm) / 25.4);
|
||||||
|
log.debug("physical dpi x={} y={}", .{
|
||||||
|
physical_x_dpi,
|
||||||
|
physical_y_dpi,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is called just prior to spinning up the renderer thread for
|
||||||
|
/// final main thread setup requirements.
|
||||||
|
pub fn finalizeInit(self: *const OpenGL, window: glfw.Window) !void {
|
||||||
|
if (DevMode.enabled) {
|
||||||
|
// Initialize for our window
|
||||||
|
assert(imgui.ImplGlfw.initForOpenGL(
|
||||||
|
@ptrCast(*imgui.ImplGlfw.GLFWWindow, window.handle),
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
assert(imgui.ImplOpenGL3.init("#version 330 core"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call thread exit to clean up our context
|
||||||
|
self.threadExit();
|
||||||
|
}
|
||||||
|
|
||||||
/// Callback called by renderer.Thread when it begins.
|
/// Callback called by renderer.Thread when it begins.
|
||||||
pub fn threadEnter(self: *const OpenGL, window: glfw.Window) !void {
|
pub fn threadEnter(self: *const OpenGL, window: glfw.Window) !void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
Reference in New Issue
Block a user