mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +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 Allocator = std.mem.Allocator;
|
||||
const renderer = @import("renderer.zig");
|
||||
const objc = @import("objc");
|
||||
const glfw = @import("glfw");
|
||||
const gl = @import("opengl.zig");
|
||||
const imgui = @import("imgui");
|
||||
const libuv = @import("libuv");
|
||||
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.
|
||||
const WRITE_REQ_PREALLOC = std.math.pow(usize, 2, 5);
|
||||
|
||||
// The renderer implementation to use.
|
||||
const Renderer = renderer.OpenGL;
|
||||
|
||||
/// Allocator
|
||||
alloc: Allocator,
|
||||
alloc_io_arena: std.heap.ArenaAllocator,
|
||||
@ -48,7 +51,7 @@ cursor: glfw.Cursor,
|
||||
imgui_ctx: if (DevMode.enabled) *imgui.Context else void,
|
||||
|
||||
/// The renderer for this window.
|
||||
renderer: renderer.OpenGL,
|
||||
renderer: Renderer,
|
||||
|
||||
/// The render 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);
|
||||
|
||||
// Create our window
|
||||
const window = try glfw.Window.create(640, 480, "ghostty", null, null, .{
|
||||
.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,
|
||||
});
|
||||
const window = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
||||
errdefer window.destroy();
|
||||
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
try Renderer.windowInit(window);
|
||||
|
||||
// Determine our DPI configurations so we can properly configure
|
||||
// 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,
|
||||
});
|
||||
|
||||
// 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
|
||||
const font_size: font.face.DesiredSize = .{
|
||||
.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);
|
||||
|
||||
// Create our terminal grid with the initial window size
|
||||
const window_size = try window.getSize();
|
||||
const screen_size: renderer.ScreenSize = .{
|
||||
.width = window_size.width,
|
||||
.height = window_size.height,
|
||||
};
|
||||
var renderer_impl = try renderer.OpenGL.init(alloc, font_group);
|
||||
var renderer_impl = try Renderer.init(alloc, font_group);
|
||||
renderer_impl.background = .{
|
||||
.r = config.background.r,
|
||||
.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.
|
||||
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);
|
||||
|
||||
// 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();
|
||||
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
|
||||
DevMode.instance.window = self;
|
||||
}
|
||||
|
||||
// Unload our context prior to switching over to the renderer thread
|
||||
// because OpenGL requires it to be unloaded.
|
||||
gl.glad.unload();
|
||||
try glfw.makeContextCurrent(null);
|
||||
// Give the renderer one more opportunity to finalize any window
|
||||
// setup on the main thread prior to spinning up the rendering thread.
|
||||
try renderer_impl.finalizeInit(window);
|
||||
|
||||
// Start our renderer thread
|
||||
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
|
||||
self.renderer.threadEnter(self.window) catch unreachable;
|
||||
self.renderer_thread.deinit();
|
||||
|
||||
// Deinit our renderer
|
||||
self.renderer.deinit();
|
||||
}
|
||||
|
||||
if (DevMode.enabled) {
|
||||
@ -589,8 +528,6 @@ pub fn destroy(self: *Window) void {
|
||||
DevMode.instance.window = null;
|
||||
|
||||
// Uninitialize imgui
|
||||
imgui.ImplOpenGL3.shutdown();
|
||||
imgui.ImplGlfw.shutdown();
|
||||
self.imgui_ctx.destroy();
|
||||
}
|
||||
|
||||
@ -601,7 +538,6 @@ pub fn destroy(self: *Window) void {
|
||||
log.err("error waiting for command to exit: {}", .{err});
|
||||
|
||||
self.terminal.deinit(self.alloc);
|
||||
self.renderer.deinit();
|
||||
self.window.destroy();
|
||||
|
||||
self.terminal_cursor.timer.close((struct {
|
||||
|
@ -17,6 +17,7 @@ const gl = @import("../opengl.zig");
|
||||
const trace = @import("tracy").trace;
|
||||
const math = @import("../math.zig");
|
||||
const lru = @import("../lru.zig");
|
||||
const DevMode = @import("../DevMode.zig");
|
||||
|
||||
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 {
|
||||
if (DevMode.enabled) {
|
||||
imgui.ImplOpenGL3.shutdown();
|
||||
imgui.ImplGlfw.shutdown();
|
||||
}
|
||||
|
||||
self.font_shaper.deinit();
|
||||
self.alloc.free(self.font_shaper.cell_buf);
|
||||
|
||||
@ -331,6 +337,77 @@ pub fn deinit(self: *OpenGL) void {
|
||||
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.
|
||||
pub fn threadEnter(self: *const OpenGL, window: glfw.Window) !void {
|
||||
_ = self;
|
||||
|
Reference in New Issue
Block a user