Deinit devmode more cleanly

This commit is contained in:
Mitchell Hashimoto
2022-11-06 17:26:01 -08:00
parent 135b859b8f
commit fd304c9338
4 changed files with 45 additions and 34 deletions

View File

@ -32,6 +32,9 @@ config: *const Config,
/// this is a blocking queue so if it is full you will get errors (or block). /// this is a blocking queue so if it is full you will get errors (or block).
mailbox: *Mailbox, mailbox: *Mailbox,
/// Set to true once we're quitting. This never goes false again.
quit: bool,
/// Initialize the main app instance. This creates the main window, sets /// Initialize the main app instance. This creates the main window, sets
/// up the renderer state, compiles the shaders, etc. This is the primary /// up the renderer state, compiles the shaders, etc. This is the primary
/// "startup" logic. /// "startup" logic.
@ -47,6 +50,7 @@ pub fn create(alloc: Allocator, config: *const Config) !*App {
.windows = .{}, .windows = .{},
.config = config, .config = config,
.mailbox = mailbox, .mailbox = mailbox,
.quit = false,
}; };
errdefer app.windows.deinit(alloc); errdefer app.windows.deinit(alloc);
@ -74,8 +78,7 @@ pub fn wakeup(self: App) void {
/// Run the main event loop for the application. This blocks until the /// Run the main event loop for the application. This blocks until the
/// application quits or every window is closed. /// application quits or every window is closed.
pub fn run(self: *App) !void { pub fn run(self: *App) !void {
var quit: bool = false; while (!self.quit and self.windows.items.len > 0) {
while (!quit and self.windows.items.len > 0) {
// Block for any glfw events. // Block for any glfw events.
try glfw.waitEvents(); try glfw.waitEvents();
@ -87,11 +90,6 @@ pub fn run(self: *App) !void {
while (i < self.windows.items.len) { while (i < self.windows.items.len) {
const window = self.windows.items[i]; const window = self.windows.items[i];
if (window.shouldClose()) { if (window.shouldClose()) {
// If this was our final window, deinitialize the renderer
if (self.windows.items.len == 1) {
renderer.Renderer.lastWindowDeinit();
}
window.destroy(); window.destroy();
_ = self.windows.swapRemove(i); _ = self.windows.swapRemove(i);
continue; continue;
@ -100,13 +98,13 @@ pub fn run(self: *App) !void {
i += 1; i += 1;
} }
// Drain our mailbox // Drain our mailbox only if we're not quitting.
try self.drainMailbox(&quit); if (!self.quit) try self.drainMailbox();
} }
} }
/// Drain the mailbox. /// Drain the mailbox.
fn drainMailbox(self: *App, quit: *bool) !void { fn drainMailbox(self: *App) !void {
var drain = self.mailbox.drain(); var drain = self.mailbox.drain();
defer drain.deinit(); defer drain.deinit();
@ -114,7 +112,7 @@ fn drainMailbox(self: *App, quit: *bool) !void {
log.debug("mailbox message={}", .{message}); log.debug("mailbox message={}", .{message});
switch (message) { switch (message) {
.new_window => try self.newWindow(), .new_window => try self.newWindow(),
.quit => quit.* = true, .quit => try self.setQuit(),
} }
} }
} }
@ -125,10 +123,16 @@ fn newWindow(self: *App) !void {
errdefer window.destroy(); errdefer window.destroy();
try self.windows.append(self.alloc, window); try self.windows.append(self.alloc, window);
errdefer _ = self.windows.pop(); errdefer _ = self.windows.pop();
}
// This was the first window, so we need to initialize our renderer. /// Start quitting
if (self.windows.items.len == 1) { fn setQuit(self: *App) !void {
try window.renderer.firstWindowInit(window.window); if (self.quit) return;
self.quit = true;
// Mark that all our windows should close
for (self.windows.items) |window| {
window.window.setShouldClose(true);
} }
} }

View File

@ -393,6 +393,9 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
// Add our window to the instance if it isn't set. // Add our window to the instance if it isn't set.
DevMode.instance.window = self; DevMode.instance.window = self;
// Let our renderer setup
try renderer_impl.initDevMode(window);
} }
// Give the renderer one more opportunity to finalize any window // Give the renderer one more opportunity to finalize any window
@ -427,11 +430,11 @@ pub fn destroy(self: *Window) void {
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 // If we are devmode-owning, clean that up.
self.renderer.deinit();
}
if (DevMode.enabled and DevMode.instance.window == self) { if (DevMode.enabled and DevMode.instance.window == self) {
// Let our renderer clean up
self.renderer.deinitDevMode();
// Clear the window // Clear the window
DevMode.instance.window = null; DevMode.instance.window = null;
@ -439,6 +442,10 @@ pub fn destroy(self: *Window) void {
self.imgui_ctx.destroy(); self.imgui_ctx.destroy();
} }
// Deinit our renderer
self.renderer.deinit();
}
{ {
// Stop our IO thread // Stop our IO thread
self.io_thread.stop.send() catch |err| self.io_thread.stop.send() catch |err|

View File

@ -265,10 +265,8 @@ pub fn finalizeWindowInit(self: *const Metal, window: glfw.Window) !void {
layer.setProperty("contentsScale", scaleFactor); layer.setProperty("contentsScale", scaleFactor);
} }
/// This is called only after the first window is opened. This may be /// This is called if this renderer runs DevMode.
/// called multiple times if all windows are closed and a new one is pub fn initDevMode(self: *const Metal, window: glfw.Window) !void {
/// reopened.
pub fn firstWindowInit(self: *const Metal, window: glfw.Window) !void {
if (DevMode.enabled) { if (DevMode.enabled) {
// Initialize for our window // Initialize for our window
assert(imgui.ImplGlfw.initForOther( assert(imgui.ImplGlfw.initForOther(
@ -279,8 +277,10 @@ pub fn firstWindowInit(self: *const Metal, window: glfw.Window) !void {
} }
} }
/// This is called only when the last window is destroyed. /// This is called if this renderer runs DevMode.
pub fn lastWindowDeinit() void { pub fn deinitDevMode(self: *const Metal) void {
_ = self;
if (DevMode.enabled) { if (DevMode.enabled) {
imgui.ImplMetal.shutdown(); imgui.ImplMetal.shutdown();
imgui.ImplGlfw.shutdown(); imgui.ImplGlfw.shutdown();

View File

@ -387,10 +387,8 @@ pub fn finalizeWindowInit(self: *const OpenGL, window: glfw.Window) !void {
_ = window; _ = window;
} }
/// This is called only after the first window is opened. This may be /// This is called if this renderer runs DevMode.
/// called multiple times if all windows are closed and a new one is pub fn initDevMode(self: *const OpenGL, window: glfw.Window) !void {
/// reopened.
pub fn firstWindowInit(self: *const OpenGL, window: glfw.Window) !void {
_ = self; _ = self;
if (DevMode.enabled) { if (DevMode.enabled) {
@ -403,8 +401,10 @@ pub fn firstWindowInit(self: *const OpenGL, window: glfw.Window) !void {
} }
} }
/// This is called only when the last window is destroyed. /// This is called if this renderer runs DevMode.
pub fn lastWindowDeinit() void { pub fn deinitDevMode(self: *const OpenGL) void {
_ = self;
if (DevMode.enabled) { if (DevMode.enabled) {
imgui.ImplOpenGL3.shutdown(); imgui.ImplOpenGL3.shutdown();
imgui.ImplGlfw.shutdown(); imgui.ImplGlfw.shutdown();