From 1f82923f59570fc569b56e6b350fdac690e1a36d Mon Sep 17 00:00:00 2001 From: David Allemang Date: Thu, 27 Jun 2024 14:17:06 -0400 Subject: [PATCH] starting to test swapchain --- src/au.zig | 3 +- src/au/Bus.zig | 11 +++--- src/au/SwapChain.zig | 68 ++++++++++++++++++++++++++++++++++++++ src/main.zig | 79 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 src/au/SwapChain.zig diff --git a/src/au.zig b/src/au.zig index 168926f..2fb76af 100644 --- a/src/au.zig +++ b/src/au.zig @@ -4,7 +4,8 @@ const builtin = @import("builtin"); const vk = @import("vk"); const c = @import("c.zig"); -const Bus = @import("au/Bus.zig"); +pub const Bus = @import("au/Bus.zig"); +pub const SwapChain = @import("au/SwapChain.zig"); pub const use_debug_messenger = switch (builtin.mode) { .Debug, .ReleaseSafe => true, diff --git a/src/au/Bus.zig b/src/au/Bus.zig index a996dc4..117a3e4 100644 --- a/src/au/Bus.zig +++ b/src/au/Bus.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const vk = @import("vk"); const c = @import("../c.zig"); const Window = @import("../au.zig").Window; const Self = @This(); @@ -86,7 +87,7 @@ pub const Event = union(enum) { const WindowFocus = struct { focused: bool }; const WindowIconify = struct { iconified: bool }; const WindowMaximize = struct { maximized: bool }; - const FramebufferSize = struct { x: i32, y: i32 }; + const FramebufferSize = struct { extent: vk.Extent2D }; const WindowContentScale = struct { x: f32, y: f32 }; const MouseButton = struct { button: c_int, // todo enum @@ -193,12 +194,14 @@ fn onWindowMaximize(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void }) catch unreachable; // todo circular queue; warn } -fn onFramebufferSize(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void { +fn onFramebufferSize(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .framebufferSize = .{ - .x = @intCast(x), - .y = @intCast(y), + .extent = .{ + .width = @intCast(width), + .height = @intCast(height), + }, }, }) catch unreachable; // todo circular queue; warn } diff --git a/src/au/SwapChain.zig b/src/au/SwapChain.zig new file mode 100644 index 0000000..7773ac1 --- /dev/null +++ b/src/au/SwapChain.zig @@ -0,0 +1,68 @@ +const std = @import("std"); +const au = @import("../au.zig"); +const vk = @import("vk"); + +const Self = @This(); + +alloc: std.mem.Allocator, +cinfo: vk.SwapchainCreateInfoKHR, +handle: vk.SwapchainKHR, + +pub fn init(alloc: std.mem.Allocator) !Self { + const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, au.W.surface); + + var min_image_count = @max(3, caps.min_image_count + 1); // todo magic numbers + if (caps.max_image_count > 0) { + min_image_count = @min(min_image_count, caps.max_image_count); + } + + // determine format + const format = au.device_config.format; + + return .{ + .alloc = alloc, + .cinfo = .{ + .surface = au.W.surface, + .min_image_count = min_image_count, + .image_format = format.format, + .image_color_space = format.color_space, + .image_extent = undefined, // set in rebuild + .image_array_layers = 1, + .image_usage = .{ .color_attachment_bit = true }, + .image_sharing_mode = .exclusive, + .pre_transform = .{ .identity_bit_khr = true }, + .composite_alpha = .{ .opaque_bit_khr = true }, + .present_mode = au.device_config.mode, + .clipped = vk.TRUE, + .old_swapchain = .null_handle, + }, + .handle = .null_handle, + }; +} + +pub fn deinit(self: *Self) void { + au.D.destroySwapchainKHR(self.handle, null); +} + +/// mark that the swapchain _should_ be rebuilt with the given extent +/// this function is reentrant, so the swapchain can be marked multiple times +/// and only one rebuild occur +pub fn mark(self: *Self) void { + self.handle = .null_handle; +} + +/// rebuild the swapchain only if it is marked. return true if the swapchain was rebuilt. +pub fn rebuild(self: *Self) !bool { + if (self.handle != .null_handle) return false; + + const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, self.cinfo.surface); + self.cinfo.image_extent = caps.current_extent; + + self.handle = try au.D.createSwapchainKHR(&self.cinfo, null); + au.D.destroySwapchainKHR(self.cinfo.old_swapchain, null); + self.cinfo.old_swapchain = self.handle; + + // todo repopulate images and synchronization + + return true; +} diff --git a/src/main.zig b/src/main.zig index 40fb247..7cdfae4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -99,19 +99,86 @@ pub fn main() !void { try au.init(alloc); defer au.deinit(); + var sc = try au.SwapChain.init(alloc); + defer sc.deinit(); + + const pool = try au.D.createCommandPool(&.{ .queue_family_index = au.device_config.family }, null); + defer au.D.destroyCommandPool(pool, null); + + const fence: vk.Fence = try au.D.createFence(&.{ .flags = .{ .signaled_bit = true } }, null); + defer au.D.destroyFence(fence, null); + + const sem_ready: vk.Semaphore = try au.D.createSemaphore(&.{}, null); + defer au.D.destroySemaphore(sem_ready, null); + + const sem_done: vk.Semaphore = try au.D.createSemaphore(&.{}, null); + defer au.D.destroySemaphore(sem_done, null); + + const cmdbufs: [1]vk.CommandBuffer = undefined; + try au.D.allocateCommandBuffers( + &.{ .command_pool = pool, .command_buffer_count = @intCast(cmdbufs.len), .level = .primary }, + cmdbufs.ptr, + ); + defer au.D.freeCommandBuffers(pool, @intCast(cmdbufs.len), cmdbufs.ptr); + + { + const cmd = au.CommandBufferProxy.init(cmdbufs[0], au.D); + const clear = vk.ClearValue{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } }; + const viewport = vk.Viewport{ + .x = 0, + .y = 0, + .width = sc.cinfo.image_extent.width, + .height = sc.cinfo.image_extent.height, + .min_depth = 0, + .max_depth = 1, + }; + const scissor = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = sc.cinfo.image_extent }; + + try cmd.beginCommandBuffer(&.{}); + cmd.pipelineBarrier( + .{ .top_of_pipe_bit = true }, + .{ .color_attachment_output_bit = true }, + .{}, + 0, + null, + 0, + null, + 1, + @ptrCast(&vk.ImageMemoryBarrier{ + .src_access_mask = .{}, + .dst_access_mask = .{ .color_attachment_write_bit = true }, + .old_layout = .undefined, + .new_layout = .color_attachment_optimal, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = .null_handle, // todo this needs to point to the swapchain image, so I can't get away from recording a command buffer for each one. + }), + ); + } + while (!au.W.should_close()) { // todo switch mode depending on if window is focused const events = au.wait_events_timeout(0.10); for (events) |u| switch (u) { - .cursorPos, - .windowPos, - .windowSize, - .framebufferSize, - .windowRefresh, - => {}, + .framebufferSize => sc.mark(), + .cursorPos, .windowPos, .windowSize, .windowRefresh => {}, else => |e| std.debug.print("{any}\n", .{e}), }; + + _ = try sc.rebuild(); + + const acq = try au.D.acquireNextImageKHR(sc.handle, std.math.maxInt(u64), sem_ready, .null_handle); + + const pre = try au.Q.presentKHR(&vk.PresentInfoKHR{ + .wait_semaphore_count = 1, + .p_wait_semaphores = &.{sem_done}, + .swapchain_count = 1, + .p_swapchains = &.{sc.handle}, + .p_image_indices = &.{acq.image_index}, + .p_results = null, + }); + std.debug.print("present result: {}\n", .{pre}); } try au.D.deviceWaitIdle();