support screen size, rip out shared state

This commit is contained in:
Mitchell Hashimoto
2022-10-24 09:52:08 -07:00
parent 45ff936ddf
commit dc908cb73d
4 changed files with 67 additions and 35 deletions

View File

@ -367,8 +367,11 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
// Create our terminal grid with the initial window size // Create our terminal grid with the initial window size
const window_size = try window.getSize(); 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.OpenGL.init(alloc, font_group);
try renderer_impl.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
renderer_impl.background = .{ renderer_impl.background = .{
.r = config.background.r, .r = config.background.r,
.g = config.background.g, .g = config.background.g,
@ -381,10 +384,7 @@ 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 grid_size = renderer.GridSize.init( const grid_size = renderer.GridSize.init(screen_size, renderer_impl.cell_size);
.{ .width = window_size.width, .height = window_size.height },
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
// but is otherwise somewhat arbitrary. // but is otherwise somewhat arbitrary.
@ -486,6 +486,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.renderer_thread = render_thread, .renderer_thread = render_thread,
.renderer_state = .{ .renderer_state = .{
.mutex = mutex, .mutex = mutex,
.resize_screen = screen_size,
.cursor = .{ .cursor = .{
.style = .blinking_block, .style = .blinking_block,
.visible = true, .visible = true,
@ -516,7 +517,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
// Setup our callbacks and user data // Setup our callbacks and user data
window.setUserPointer(self); window.setUserPointer(self);
//window.setSizeCallback(sizeCallback); window.setSizeCallback(sizeCallback);
window.setCharCallback(charCallback); window.setCharCallback(charCallback);
window.setKeyCallback(keyCallback); window.setKeyCallback(keyCallback);
window.setFocusCallback(focusCallback); window.setFocusCallback(focusCallback);
@ -718,18 +719,15 @@ fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
.height = px_size.height, .height = px_size.height,
}; };
// Update our grid so that the projections on render are correct.
const win = window.getUserPointer(Window) orelse return; const win = window.getUserPointer(Window) orelse return;
win.renderer.setScreenSize(screen_size) catch |err|
log.err("error updating grid screen size err={}", .{err}); // Resize usually forces a redraw
win.render_timer.schedule() catch |err|
log.err("error scheduling render timer in sizeCallback err={}", .{err});
// Recalculate our grid size // Recalculate our grid size
win.grid_size.update(screen_size, win.renderer.cell_size); win.grid_size.update(screen_size, win.renderer.cell_size);
// Update the size of our terminal state
win.terminal.resize(win.alloc, win.grid_size.columns, win.grid_size.rows) catch |err|
log.err("error updating terminal size: {}", .{err});
// Update the size of our pty // Update the size of our pty
win.pty.setSize(.{ win.pty.setSize(.{
.ws_row = @intCast(u16, win.grid_size.rows), .ws_row = @intCast(u16, win.grid_size.rows),
@ -738,14 +736,18 @@ fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
.ws_ypixel = @intCast(u16, height), .ws_ypixel = @intCast(u16, height),
}) catch |err| log.err("error updating pty screen size err={}", .{err}); }) catch |err| log.err("error updating pty screen size err={}", .{err});
// Update our viewport for this context to be the entire window. // Enter the critical area that we want to keep small
// OpenGL works in pixels, so we have to use the pixel size. {
gl.viewport(0, 0, @intCast(i32, px_size.width), @intCast(i32, px_size.height)) catch |err| win.renderer_state.mutex.lock();
log.err("error updating OpenGL viewport err={}", .{err}); defer win.renderer_state.mutex.unlock();
// Draw // We need to setup our render state to store our new pending size
win.render_timer.schedule() catch |err| win.renderer_state.resize_screen = screen_size;
log.err("error scheduling render timer in sizeCallback err={}", .{err});
// Update the size of our terminal state
win.terminal.resize(win.alloc, win.grid_size.columns, win.grid_size.rows) catch |err|
log.err("error updating terminal size: {}", .{err});
}
} }
fn charCallback(window: glfw.Window, codepoint: u21) void { fn charCallback(window: glfw.Window, codepoint: u21) void {

View File

@ -359,14 +359,24 @@ pub fn threadExit(self: *const OpenGL) void {
pub fn render( pub fn render(
self: *OpenGL, self: *OpenGL,
window: glfw.Window, window: glfw.Window,
state: renderer.State, state: *renderer.State,
) !void { ) !void {
// Data we extract out of the critical area.
const Critical = struct {
devmode_data: ?*imgui.DrawData,
screen_size: ?renderer.ScreenSize,
};
// Update all our data as tightly as possible within the mutex. // Update all our data as tightly as possible within the mutex.
var gl_bg = self.background; var gl_bg = self.background;
{ const critical: Critical = critical: {
state.mutex.lock(); state.mutex.lock();
defer state.mutex.unlock(); defer state.mutex.unlock();
// If we're resizing, then handle that now.
if (state.resize_screen) |size| try self.setScreenSize(size);
defer state.resize_screen = null;
// Setup our cursor state // Setup our cursor state
self.cursor_visible = state.cursor.visible and !state.cursor.blink; self.cursor_visible = state.cursor.visible and !state.cursor.blink;
self.cursor_style = CursorStyle.fromTerminal(state.cursor.style) orelse .box; self.cursor_style = CursorStyle.fromTerminal(state.cursor.style) orelse .box;
@ -384,9 +394,33 @@ pub fn render(
self.foreground = bg; self.foreground = bg;
} }
// Build our GPU cells
try self.rebuildCells(state.terminal); try self.rebuildCells(state.terminal);
try self.finalizeCells(state.terminal); try self.finalizeCells(state.terminal);
if (state.devmode) |dm| if (dm.visible) try dm.update();
// Build our devmode draw data
const devmode_data = devmode_data: {
if (state.devmode) |dm| {
if (dm.visible) {
try dm.update();
break :devmode_data try dm.render();
}
}
break :devmode_data null;
};
break :critical .{
.devmode_data = devmode_data,
.screen_size = state.resize_screen,
};
};
// If we are resizing we need to update the viewport
if (critical.screen_size) |size| {
// 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, size.width), @intCast(i32, size.height));
} }
// Clear the surface // Clear the surface
@ -402,11 +436,8 @@ pub fn render(
try self.draw(); try self.draw();
// If we have devmode, then render that // If we have devmode, then render that
if (state.devmode) |dm| { if (critical.devmode_data) |data| {
if (dm.visible) { imgui.ImplOpenGL3.renderDrawData(data);
const data = try dm.render();
imgui.ImplOpenGL3.renderDrawData(data);
}
} }
// Swap our window buffers // Swap our window buffers
@ -783,7 +814,7 @@ pub fn updateCell(
/// Set the screen size for rendering. This will update the projection /// Set the screen size for rendering. This will update the projection
/// used for the shader so that the scaling of the grid is correct. /// used for the shader so that the scaling of the grid is correct.
pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void { fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
// Update the projection uniform within our shader // Update the projection uniform within our shader
const bind = try self.program.use(); const bind = try self.program.use();
defer bind.unbind(); defer bind.unbind();

View File

@ -3,6 +3,7 @@
const std = @import("std"); const std = @import("std");
const DevMode = @import("../DevMode.zig"); const DevMode = @import("../DevMode.zig");
const terminal = @import("../terminal/main.zig"); const terminal = @import("../terminal/main.zig");
const renderer = @import("../renderer.zig");
/// The mutex that must be held while reading any of the data in the /// The mutex that must be held while reading any of the data in the
/// members of this state. Note that the state itself is NOT protected /// members of this state. Note that the state itself is NOT protected
@ -11,7 +12,7 @@ const terminal = @import("../terminal/main.zig");
mutex: *std.Thread.Mutex, mutex: *std.Thread.Mutex,
/// A new screen size if the screen was resized. /// A new screen size if the screen was resized.
resize: ?Resize = null, resize_screen: ?renderer.ScreenSize,
/// Cursor configuration for rendering /// Cursor configuration for rendering
cursor: Cursor, cursor: Cursor,
@ -36,5 +37,3 @@ pub const Cursor = struct {
/// the cursor will not be rendered. /// the cursor will not be rendered.
blink: bool = false, blink: bool = false,
}; };
pub const Resize = struct {};

View File

@ -31,7 +31,7 @@ window: glfw.Window,
renderer: *renderer.OpenGL, renderer: *renderer.OpenGL,
/// Pointer to the shared state that is used to generate the final render. /// Pointer to the shared state that is used to generate the final render.
state: *const renderer.State, state: *renderer.State,
/// Initialize the thread. This does not START the thread. This only sets /// Initialize the thread. This does not START the thread. This only sets
/// up all the internal state necessary prior to starting the thread. It /// up all the internal state necessary prior to starting the thread. It
@ -40,7 +40,7 @@ pub fn init(
alloc: Allocator, alloc: Allocator,
window: glfw.Window, window: glfw.Window,
renderer_impl: *renderer.OpenGL, renderer_impl: *renderer.OpenGL,
state: *const renderer.State, state: *renderer.State,
) !Thread { ) !Thread {
// We always store allocator pointer on the loop data so that // We always store allocator pointer on the loop data so that
// handles can use our global allocator. // handles can use our global allocator.
@ -148,7 +148,7 @@ fn renderCallback(h: *libuv.Async) void {
return; return;
}; };
t.renderer.render(t.window, t.state.*) catch |err| t.renderer.render(t.window, t.state) catch |err|
log.warn("error rendering err={}", .{err}); log.warn("error rendering err={}", .{err});
} }