diff --git a/src/nu.zig b/src/nu.zig index 759e098..26be0d6 100644 --- a/src/nu.zig +++ b/src/nu.zig @@ -22,8 +22,16 @@ pub fn run( _ = events; inline for (modules) |module| { - if (@hasDecl(module, "frame")) - module.frame(); + if (@hasDecl(module, "frame")) { + if (@typeInfo(@TypeOf(module.frame)).Fn.return_type) |R| { + switch (@typeInfo(R)) { + .ErrorUnion => try module.frame(), + else => @compileError("frame must be void or !void."), + } + } else { + module.frame(); + } + } } // todo fixed timestep diff --git a/src/nu/Render.zig b/src/nu/Render.zig index 972f4e8..43dc9f0 100644 --- a/src/nu/Render.zig +++ b/src/nu/Render.zig @@ -6,6 +6,7 @@ const std = @import("std"); const builtin = @import("builtin"); const vk = @import("vk"); +const nu = @import("../nu.zig"); const au = @import("Render/au.zig"); pub const Options = struct { @@ -26,15 +27,79 @@ pub const Options = struct { frames_in_flight: u8 = 3, }; -pub fn init(alloc: std.mem.Allocator) !void { - // todo make ctx not globals +var sc: au.SwapChain = undefined; +var flights: au.Flights = undefined; +pub fn init(alloc: std.mem.Allocator) !void { + // todo pick apart au into helpers; not a sub-module filled with its own globals. try au.init(alloc); errdefer au.deinit(); + + sc = try au.SwapChain.init(alloc); + errdefer sc.deinit(); + + flights = try au.Flights.init(alloc, nu.options.render.frames_in_flight); + errdefer flights.deinit(); } -pub fn frame() void {} +pub fn frame() !void { + const flight: au.Flights.Flight = flights.next(); + try flight.wait(); + + while (true) { + _ = try sc.rebuild(); + + const target = sc.acquire(flight.acquire, .null_handle) catch |err| switch (err) { + error.OutOfDateKHR => { + sc.mark(); + continue; + }, + else => return err, + }; + + const render_area: vk.Rect2D = .{ + .offset = .{ .x = 0, .y = 0 }, + .extent = sc.cinfo.image_extent, + }; + + try au.D.resetCommandPool(flight.pool, .{}); + var cmd = au.CommandBufferProxy.init(flight.cmd, au.D.wrapper); + + try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); + target.begin_rendering(cmd, render_area); + target.end_rendering(cmd); + try cmd.endCommandBuffer(); + + try au.Q.submit(1, &.{ + vk.SubmitInfo{ + .wait_semaphore_count = 1, + .p_wait_semaphores = &.{flight.acquire}, + .p_wait_dst_stage_mask = &.{ + vk.PipelineStageFlags{ .color_attachment_output_bit = true }, + }, + .command_buffer_count = 1, + .p_command_buffers = &.{cmd.handle}, + .signal_semaphore_count = 1, + .p_signal_semaphores = &.{flight.complete}, + }, + }, flight.fence); + + if (sc.present(&.{flight.complete}, target)) |_| { + return; + } else |err| switch (err) { + error.OutOfDateKHR => { + try flight.wait(); + sc.mark(); + continue; + }, + else => return err, + } + } +} pub fn deinit() void { + au.D.deviceWaitIdle() catch {}; + flights.deinit(); + sc.deinit(); au.deinit(); } diff --git a/src/nu/Render/au/Flights.zig b/src/nu/Render/au/Flights.zig index d758170..4662e08 100644 --- a/src/nu/Render/au/Flights.zig +++ b/src/nu/Render/au/Flights.zig @@ -4,12 +4,17 @@ const au = @import("../au.zig"); const Self = @This(); -const Flight = struct { +pub const Flight = struct { acquire: vk.Semaphore = .null_handle, complete: vk.Semaphore = .null_handle, fence: vk.Fence = .null_handle, pool: vk.CommandPool = .null_handle, cmd: vk.CommandBuffer = .null_handle, + + pub fn wait(self: Flight) !void { + _ = try au.D.waitForFences(1, &.{self.fence}, vk.TRUE, std.math.maxInt(u64)); + try au.D.resetFences(1, &.{self.fence}); + } }; alloc: std.mem.Allocator, diff --git a/src/nu/Render/au/SwapChain.zig b/src/nu/Render/au/SwapChain.zig index 77a28a9..204316d 100644 --- a/src/nu/Render/au/SwapChain.zig +++ b/src/nu/Render/au/SwapChain.zig @@ -11,7 +11,7 @@ images: std.ArrayListUnmanaged(vk.Image) = .{}, views: std.ArrayListUnmanaged(vk.ImageView) = .{}, pub fn init(alloc: std.mem.Allocator) !Self { - const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, au.W.surface); + const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, au.S.*); var min_image_count = @max(3, caps.min_image_count + 1); // todo magic numbers if (caps.max_image_count > 0) { @@ -24,7 +24,7 @@ pub fn init(alloc: std.mem.Allocator) !Self { return .{ .alloc = alloc, .cinfo = .{ - .surface = au.W.surface, + .surface = au.S.*, .min_image_count = min_image_count, .image_format = format.format, .image_color_space = format.color_space,