easy comptime hooks

This commit is contained in:
2024-07-09 23:35:40 -04:00
parent cb8684cbf3
commit cc1a9fdabc
5 changed files with 69 additions and 68 deletions

View File

@@ -1,8 +1,24 @@
const std = @import("std"); const std = @import("std");
const nu = @import("nu.zig"); const nu = @import("nu.zig");
const Bus = @import("nu/Bus.zig");
const Render = @import("nu/Render.zig");
const ImGui = @import("nu/ImGui.zig");
pub fn init(alloc: std.mem.Allocator) !void { pub fn init(alloc: std.mem.Allocator) !void {
_ = alloc; _ = alloc;
} }
pub fn deinit() void {} pub fn deinit() void {}
pub fn nu_frame() void {}
// pub fn nu_events(events: []const Bus.Event) void {
// std.debug.print("{any}\n", .{events});
// }
// pub fn nu_render_present(_: Render.au.CommandBufferProxy) void {}
pub fn nu_imgui_frame() void {
ImGui.igShowMetricsWindow(null);
}

View File

@@ -11,8 +11,17 @@ pub const nu_options: nu.Options = .{
}, },
}; };
pub const nu_driver = nu.Window; // todo declare or infer module dependencies, topological sort for init order. clean up "init" lines in main.
//
// problem: where should gpa go? probably some "Engine" structure in nu.zig
//
// don't necessarily need to declare topological sort - depth-first traversal
// of each module's dependencies without repeats would do.
//
// idea - use a structure like std.Build.Step where the polymorphic part is a
// component of the larger structure.
pub const nu_driver = nu.Window;
pub const nu_modules = .{ pub const nu_modules = .{
App, App,
nu.ImGui, nu.ImGui,
@@ -24,15 +33,6 @@ pub fn main() !void {
defer _ = gpa.detectLeaks(); defer _ = gpa.detectLeaks();
const alloc = gpa.allocator(); const alloc = gpa.allocator();
// todo declare or infer module dependencies, topological sort for init order
// problem: where should gpa go? probably some "Engine" structure in nu.zig
// don't necessarily need to declare topological sort - depth-first traversal
// of each module's dependencies without repeats would do.
// idea - use a structure like std.Build.Step where the polymorphic part is a
// component of the larger structure.
try nu.Window.init(alloc); try nu.Window.init(alloc);
defer nu.Window.deinit(); defer nu.Window.deinit();

View File

@@ -8,13 +8,30 @@ pub const ImGui = @import("nu/ImGui.zig");
pub const Options = struct { pub const Options = struct {
window: Window.Options = .{}, window: Window.Options = .{},
render: Render.Options = .{}, render: Render.Options = .{},
// imgui: ImGui.Options = .{}, imgui: ImGui.Options = .{},
}; };
pub const options: Options = if (@hasDecl(root, "nu_options")) root.nu_options else .{}; pub const options: Options = if (@hasDecl(root, "nu_options")) root.nu_options else .{};
pub const modules = root.nu_modules; pub const modules = root.nu_modules;
pub const driver = root.nu_driver; pub const driver = root.nu_driver;
pub fn run() !void {
try invoke_hook("nu_enter", .{});
while (driver.next()) |events| {
if (events.len > 0) {
try invoke_hook("nu_events", .{events});
}
// todo frame timer
try invoke_hook("nu_frame", .{});
// todo fixed timestep
}
try invoke_hook("nu_close", .{});
}
fn invoke(func: anytype, args: anytype) !void { fn invoke(func: anytype, args: anytype) !void {
if (@typeInfo(@TypeOf(func)).Fn.return_type) |R| { if (@typeInfo(@TypeOf(func)).Fn.return_type) |R| {
switch (@typeInfo(R)) { switch (@typeInfo(R)) {
@@ -28,6 +45,10 @@ fn invoke(func: anytype, args: anytype) !void {
} }
} }
// todo specify hook type.
// - special handling for error unions
// - allow per-hook state somehow declared in the handler
pub fn invoke_hook(comptime name: []const u8, args: anytype) !void { pub fn invoke_hook(comptime name: []const u8, args: anytype) !void {
inline for (modules) |module| { inline for (modules) |module| {
if (@hasDecl(module, name)) { if (@hasDecl(module, name)) {
@@ -35,14 +56,3 @@ pub fn invoke_hook(comptime name: []const u8, args: anytype) !void {
} }
} }
} }
pub fn run() !void {
while (driver.next()) |events| {
// todo event handler
_ = events;
try invoke_hook("frame", .{});
// todo fixed timestep
}
}

View File

@@ -12,6 +12,8 @@ const Window = @import("Window.zig");
const im = @import("cimgui"); const im = @import("cimgui");
pub usingnamespace im; pub usingnamespace im;
pub const Options = struct {};
pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction { pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction {
return au.glfwGetInstanceProcAddress(au.I.handle, procname); return au.glfwGetInstanceProcAddress(au.I.handle, procname);
} }
@@ -75,34 +77,30 @@ pub fn init() !void {
if (!im.impl.ImGui_ImplVulkan_CreateFontsTexture()) { if (!im.impl.ImGui_ImplVulkan_CreateFontsTexture()) {
return error.igVulkanFontTextureFailed; return error.igVulkanFontTextureFailed;
} }
try Render.add_present_callback(present);
errdefer Render.remove_present_callback(present);
} }
pub fn frame() void { pub fn nu_frame() !void {
im.impl.ImGui_ImplGlfw_NewFrame(); im.impl.ImGui_ImplGlfw_NewFrame();
im.impl.ImGui_ImplVulkan_NewFrame(); im.impl.ImGui_ImplVulkan_NewFrame();
im.igNewFrame(); im.igNewFrame();
im.igShowDemoWindow(null); try nu.invoke_hook("nu_imgui_frame", .{});
im.igEndFrame(); im.igEndFrame();
im.igRender(); im.igRender();
} }
pub fn deinit() void { pub fn nu_render_present(cmd: au.CommandBufferProxy) void {
Render.remove_present_callback(present);
im.impl.ImGui_ImplVulkan_Shutdown();
au.D.destroyDescriptorPool(descriptor_pool, null);
im.impl.ImGui_ImplGlfw_Shutdown();
im.igDestroyContext(ctx);
}
pub fn present(cmd: au.CommandBufferProxy) void {
im.impl.ImGui_ImplVulkan_RenderDrawData( im.impl.ImGui_ImplVulkan_RenderDrawData(
@ptrCast(im.igGetDrawData()), @ptrCast(im.igGetDrawData()),
@ptrFromInt(@intFromEnum(cmd.handle)), @ptrFromInt(@intFromEnum(cmd.handle)),
null, null,
); );
} }
pub fn deinit() void {
im.impl.ImGui_ImplVulkan_Shutdown();
au.D.destroyDescriptorPool(descriptor_pool, null);
im.impl.ImGui_ImplGlfw_Shutdown();
im.igDestroyContext(ctx);
}

View File

@@ -30,33 +30,11 @@ pub const Options = struct {
var sc: au.SwapChain = undefined; var sc: au.SwapChain = undefined;
var flights: au.Flights = undefined; var flights: au.Flights = undefined;
const PresentCallback = *const fn (au.CommandBufferProxy) void;
var present_callbacks: std.ArrayList(PresentCallback) = undefined;
pub fn add_present_callback(cb: PresentCallback) !void {
if (std.mem.indexOfScalar(PresentCallback, present_callbacks.items, cb)) |_| {
return;
} else {
try present_callbacks.append(cb);
}
}
pub fn remove_present_callback(cb: PresentCallback) void {
if (std.mem.indexOfScalar(PresentCallback, present_callbacks.items, cb)) |idx| {
_ = present_callbacks.orderedRemove(idx);
} else {
return;
}
}
pub fn init(alloc: std.mem.Allocator) !void { pub fn init(alloc: std.mem.Allocator) !void {
// todo pick apart au into helpers; not a sub-module filled with its own globals. // todo pick apart au into helpers; not a sub-module filled with its own globals.
try au.init(alloc); try au.init(alloc);
errdefer au.deinit(); errdefer au.deinit();
present_callbacks = std.ArrayList(PresentCallback).init(alloc);
errdefer present_callbacks.deinit();
sc = try au.SwapChain.init(alloc); sc = try au.SwapChain.init(alloc);
errdefer sc.deinit(); errdefer sc.deinit();
@@ -64,7 +42,7 @@ pub fn init(alloc: std.mem.Allocator) !void {
errdefer flights.deinit(); errdefer flights.deinit();
} }
pub fn frame() !void { pub fn nu_frame() !void {
const flight: au.Flights.Flight = flights.next(); const flight: au.Flights.Flight = flights.next();
try flight.wait(); try flight.wait();
@@ -89,14 +67,11 @@ pub fn frame() !void {
try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
target.begin_rendering(cmd, render_area); target.begin_rendering(cmd, render_area);
for (present_callbacks.items) |cb| {
cb(cmd);
}
// todo really don't like this. // todo manage frame in flight state for each hook; pass the current flight in as context.
// there should be some comptime means for a module to invoke hooks on other modules. eg there should be some // will need some comptime -> anytype mapping.
// "record" hook that for each module that gets called here; but if the render module is never added then that try nu.invoke_hook("nu_render_present", .{cmd});
// hook never gets called
target.end_rendering(cmd); target.end_rendering(cmd);
try cmd.endCommandBuffer(); try cmd.endCommandBuffer();
@@ -127,9 +102,11 @@ pub fn frame() !void {
} }
} }
pub fn nu_close() !void {
try au.D.deviceWaitIdle();
}
pub fn deinit() void { pub fn deinit() void {
present_callbacks.deinit();
au.D.deviceWaitIdle() catch {};
flights.deinit(); flights.deinit();
sc.deinit(); sc.deinit();
au.deinit(); au.deinit();