From fd304c93386d5cfb732983ecd2511d72d251f45f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 6 Nov 2022 17:26:01 -0800 Subject: [PATCH] Deinit devmode more cleanly --- src/App.zig | 32 ++++++++++++++++++-------------- src/Window.zig | 23 +++++++++++++++-------- src/renderer/Metal.zig | 12 ++++++------ src/renderer/OpenGL.zig | 12 ++++++------ 4 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/App.zig b/src/App.zig index 00187bdcd..b0dc4fdfb 100644 --- a/src/App.zig +++ b/src/App.zig @@ -32,6 +32,9 @@ config: *const Config, /// this is a blocking queue so if it is full you will get errors (or block). 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 /// up the renderer state, compiles the shaders, etc. This is the primary /// "startup" logic. @@ -47,6 +50,7 @@ pub fn create(alloc: Allocator, config: *const Config) !*App { .windows = .{}, .config = config, .mailbox = mailbox, + .quit = false, }; 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 /// application quits or every window is closed. pub fn run(self: *App) !void { - var quit: bool = false; - while (!quit and self.windows.items.len > 0) { + while (!self.quit and self.windows.items.len > 0) { // Block for any glfw events. try glfw.waitEvents(); @@ -87,11 +90,6 @@ pub fn run(self: *App) !void { while (i < self.windows.items.len) { const window = self.windows.items[i]; if (window.shouldClose()) { - // If this was our final window, deinitialize the renderer - if (self.windows.items.len == 1) { - renderer.Renderer.lastWindowDeinit(); - } - window.destroy(); _ = self.windows.swapRemove(i); continue; @@ -100,13 +98,13 @@ pub fn run(self: *App) !void { i += 1; } - // Drain our mailbox - try self.drainMailbox(&quit); + // Drain our mailbox only if we're not quitting. + if (!self.quit) try self.drainMailbox(); } } /// Drain the mailbox. -fn drainMailbox(self: *App, quit: *bool) !void { +fn drainMailbox(self: *App) !void { var drain = self.mailbox.drain(); defer drain.deinit(); @@ -114,7 +112,7 @@ fn drainMailbox(self: *App, quit: *bool) !void { log.debug("mailbox message={}", .{message}); switch (message) { .new_window => try self.newWindow(), - .quit => quit.* = true, + .quit => try self.setQuit(), } } } @@ -125,10 +123,16 @@ fn newWindow(self: *App) !void { errdefer window.destroy(); try self.windows.append(self.alloc, window); errdefer _ = self.windows.pop(); +} - // This was the first window, so we need to initialize our renderer. - if (self.windows.items.len == 1) { - try window.renderer.firstWindowInit(window.window); +/// Start quitting +fn setQuit(self: *App) !void { + if (self.quit) return; + self.quit = true; + + // Mark that all our windows should close + for (self.windows.items) |window| { + window.window.setShouldClose(true); } } diff --git a/src/Window.zig b/src/Window.zig index 20546b5e9..62960f9b0 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -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. DevMode.instance.window = self; + + // Let our renderer setup + try renderer_impl.initDevMode(window); } // Give the renderer one more opportunity to finalize any window @@ -427,18 +430,22 @@ pub fn destroy(self: *Window) void { self.renderer.threadEnter(self.window) catch unreachable; self.renderer_thread.deinit(); + // If we are devmode-owning, clean that up. + if (DevMode.enabled and DevMode.instance.window == self) { + // Let our renderer clean up + self.renderer.deinitDevMode(); + + // Clear the window + DevMode.instance.window = null; + + // Uninitialize imgui + self.imgui_ctx.destroy(); + } + // Deinit our renderer self.renderer.deinit(); } - if (DevMode.enabled and DevMode.instance.window == self) { - // Clear the window - DevMode.instance.window = null; - - // Uninitialize imgui - self.imgui_ctx.destroy(); - } - { // Stop our IO thread self.io_thread.stop.send() catch |err| diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 489826ebd..65e8b0d9d 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -265,10 +265,8 @@ pub fn finalizeWindowInit(self: *const Metal, window: glfw.Window) !void { layer.setProperty("contentsScale", scaleFactor); } -/// This is called only after the first window is opened. This may be -/// called multiple times if all windows are closed and a new one is -/// reopened. -pub fn firstWindowInit(self: *const Metal, window: glfw.Window) !void { +/// This is called if this renderer runs DevMode. +pub fn initDevMode(self: *const Metal, window: glfw.Window) !void { if (DevMode.enabled) { // Initialize for our window 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. -pub fn lastWindowDeinit() void { +/// This is called if this renderer runs DevMode. +pub fn deinitDevMode(self: *const Metal) void { + _ = self; + if (DevMode.enabled) { imgui.ImplMetal.shutdown(); imgui.ImplGlfw.shutdown(); diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index efa1f3a1e..b574a8a42 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -387,10 +387,8 @@ pub fn finalizeWindowInit(self: *const OpenGL, window: glfw.Window) !void { _ = window; } -/// This is called only after the first window is opened. This may be -/// called multiple times if all windows are closed and a new one is -/// reopened. -pub fn firstWindowInit(self: *const OpenGL, window: glfw.Window) !void { +/// This is called if this renderer runs DevMode. +pub fn initDevMode(self: *const OpenGL, window: glfw.Window) !void { _ = self; 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. -pub fn lastWindowDeinit() void { +/// This is called if this renderer runs DevMode. +pub fn deinitDevMode(self: *const OpenGL) void { + _ = self; + if (DevMode.enabled) { imgui.ImplOpenGL3.shutdown(); imgui.ImplGlfw.shutdown();