From 8c82294c9190463a2fe19de485ff706ae21ef758 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Wed, 26 Feb 2025 17:24:06 -0500 Subject: [PATCH] restructure --- src/{core.zig => Core.zig} | 116 ++++++++++++++++++++----------------- src/main.zig | 8 +-- src/swapchain.zig | 92 +++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 58 deletions(-) rename src/{core.zig => Core.zig} (81%) create mode 100644 src/swapchain.zig diff --git a/src/core.zig b/src/Core.zig similarity index 81% rename from src/core.zig rename to src/Core.zig index adf99d1..cea9876 100644 --- a/src/core.zig +++ b/src/Core.zig @@ -8,8 +8,6 @@ const glfw = @cImport({ @cInclude("GLFW/glfw3.h"); }); -const Self = @This(); - const apis: []const vk.ApiInfo = &(.{ vk.features.version_1_0, vk.features.version_1_1, @@ -31,13 +29,17 @@ const Instance = vk.InstanceProxy(apis); const Device = vk.DeviceProxy(apis); const Queue = vk.QueueProxy(apis); +const Core = @This(); + alloc: std.mem.Allocator, -win: *glfw.GLFWwindow, -bw: *const Base, +b: *Base, i: Instance, d: Device, q: Queue, -dm: switch (builtin.mode) { +window: *glfw.GLFWwindow, +pdev: vk.PhysicalDevice, +surface: vk.SurfaceKHR, +msg: switch (builtin.mode) { .Debug, .ReleaseSafe => vk.DebugUtilsMessengerEXT, else => void, }, @@ -49,7 +51,10 @@ pub fn init( height: u32 = 720, title: []const u8 = "Hello World", }, -) !Self { +) !Core { + var self: Core = undefined; + self.alloc = alloc; + var arena = std.heap.ArenaAllocator.init(alloc); defer arena.deinit(); const ialloc = arena.allocator(); @@ -64,7 +69,7 @@ pub fn init( glfw.glfwWindowHint(glfw.GLFW_CLIENT_API, glfw.GLFW_NO_API); glfw.glfwWindowHintString(glfw.GLFW_X11_CLASS_NAME, "floating_window"); glfw.glfwWindowHintString(glfw.GLFW_X11_INSTANCE_NAME, "floating_window"); - const win = glfw.glfwCreateWindow( + self.window = glfw.glfwCreateWindow( @intCast(options.width), @intCast(options.height), titlez, @@ -73,9 +78,10 @@ pub fn init( ) orelse return error.GLFWWindowFailed; - var bw = try alloc.create(vk.BaseWrapper(apis)); + const bw = try alloc.create(vk.BaseWrapper(apis)); errdefer alloc.destroy(bw); bw.* = try vk.BaseWrapper(apis).load(glfwGetInstanceProcAddress); + self.b = bw; var iexts = std.ArrayList([*:0]const u8).init(ialloc); var ilyrs = std.ArrayList([*:0]const u8).init(ialloc); @@ -139,28 +145,37 @@ pub fn init( else => {}, } - const instance = try bw.createInstance( - &ici, - null, - ); - var iw = try alloc.create(vk.InstanceWrapper(apis)); + self.i.handle = try self.b.createInstance(&ici, null); + const iw = try alloc.create(vk.InstanceWrapper(apis)); errdefer alloc.destroy(iw); - iw.* = try vk.InstanceWrapper(apis).load(instance, bw.dispatch.vkGetInstanceProcAddr); - errdefer iw.destroyInstance(instance, null); + iw.* = try vk.InstanceWrapper(apis).load(self.i.handle, bw.dispatch.vkGetInstanceProcAddr); + self.i.wrapper = iw; + errdefer self.i.destroyInstance(null); - const dm = switch (builtin.mode) { - .Debug, .ReleaseSafe => try iw.createDebugUtilsMessengerEXT(instance, &dmci, null), + self.msg = switch (builtin.mode) { + .Debug, .ReleaseSafe => try self.i.createDebugUtilsMessengerEXT(&dmci, null), else => {}, }; errdefer switch (builtin.mode) { - .Debug, .ReleaseSafe => iw.destroyDebugUtilsMessengerEXT(instance, dm, null), + .Debug, .ReleaseSafe => self.i.destroyDebugUtilsMessengerEXT(self.msg, null), else => {}, }; // Device selection. Just use the first one. - const pdevs: []vk.PhysicalDevice = try iw.enumeratePhysicalDevicesAlloc(instance, ialloc); + const pdevs: []vk.PhysicalDevice = try self.i.enumeratePhysicalDevicesAlloc(ialloc); std.debug.assert(pdevs.len >= 1); - const pdev = pdevs[0]; + self.pdev = pdevs[0]; + + switch (glfwCreateWindowSurface( + self.i.handle, + self.window, + null, + &self.surface, + )) { + .success => {}, + else => return error.GLFWWindowSurfaceFailed, + } + errdefer self.i.destroySurfaceKHR(self.surface, null); // Queue selection. Just use the first one. const qci: []const vk.DeviceQueueCreateInfo = &.{ @@ -182,7 +197,7 @@ pub fn init( vk.extensions.khr_timeline_semaphore.name, }); - const device = try iw.createDevice(pdev, &.{ + self.d.handle = try self.i.createDevice(self.pdev, &.{ .enabled_extension_count = @intCast(dexts.items.len), .pp_enabled_extension_names = dexts.items.ptr, .enabled_layer_count = @intCast(dlyrs.items.len), @@ -193,36 +208,33 @@ pub fn init( .dynamic_rendering = vk.TRUE, }, }, null); - var dw = try alloc.create(vk.DeviceWrapper(apis)); - errdefer alloc.destroy(dw); - dw.* = try vk.DeviceWrapper(apis).load(device, iw.dispatch.vkGetDeviceProcAddr); - errdefer dw.destroyDevice(device, null); + const dw = try alloc.create(vk.DeviceWrapper(apis)); + dw.* = try vk.DeviceWrapper(apis).load(self.d.handle, iw.dispatch.vkGetDeviceProcAddr); + self.d.wrapper = dw; + errdefer self.d.destroyDevice(null); - const queue = dw.getDeviceQueue(device, 0, 0); + self.q.handle = self.d.getDeviceQueue(0, 0); + self.q.wrapper = dw; - return Self{ - .alloc = alloc, - .win = win, - .bw = bw, - .i = .{ .handle = instance, .wrapper = iw }, - .d = .{ .handle = device, .wrapper = dw }, - .q = .{ .handle = queue, .wrapper = dw }, - .dm = dm, - }; + return self; } -pub fn deinit(self: Self) void { +pub fn deinit(self: Core) void { self.d.destroyDevice(null); - self.alloc.destroy(self.d.wrapper); + + self.i.destroySurfaceKHR(self.surface, null); switch (builtin.mode) { - .Debug, .ReleaseSafe => self.i.destroyDebugUtilsMessengerEXT(self.dm, null), + .Debug, .ReleaseSafe => self.i.destroyDebugUtilsMessengerEXT(self.msg, null), else => {}, } + self.i.destroyInstance(null); + self.alloc.destroy(self.d.wrapper); self.alloc.destroy(self.i.wrapper); - self.alloc.destroy(self.bw); + self.alloc.destroy(self.b); + glfw.glfwTerminate(); } @@ -231,19 +243,6 @@ extern fn glfwGetInstanceProcAddress( procname: [*:0]const u8, ) vk.PfnVoidFunction; -extern fn glfwGetPhysicalDevicePresentationSupport( - instance: vk.Instance, - pdev: vk.PhysicalDevice, - queuefamily: u32, -) c_int; - -extern fn glfwCreateWindowSurface( - instance: vk.Instance, - window: *glfw.GLFWwindow, - allocation_callbacks: ?*const vk.AllocationCallbacks, - surface: *vk.SurfaceKHR, -) vk.Result; - extern fn glfwGetRequiredInstanceExtensions( count: *u32, ) [*][*:0]const u8; @@ -294,3 +293,16 @@ fn debug_callback( return vk.FALSE; } + +extern fn glfwCreateWindowSurface( + instance: vk.Instance, + window: *glfw.GLFWwindow, + allocation_callbacks: ?*const vk.AllocationCallbacks, + surface: *vk.SurfaceKHR, +) vk.Result; + +extern fn glfwGetPhysicalDevicePresentationSupport( + instance: vk.Instance, + pdev: vk.PhysicalDevice, + queuefamily: u32, +) c_int; diff --git a/src/main.zig b/src/main.zig index 8263ec6..1f85a61 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,7 +2,7 @@ const std = @import("std"); const lib = @import("zig-shape-lib"); const builtin = @import("builtin"); -const Core = @import("core.zig"); +const Core = @import("Core.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -15,11 +15,7 @@ pub fn main() !void { std.log.debug("Created instance: {any}", .{core.i.handle}); std.log.debug("Created device: {any}", .{core.d.handle}); std.log.debug("Created queue: {any}", .{core.q.handle}); - - // var surface: vk.SurfaceKHR = undefined; - // if (glfwCreateWindowSurface(instance, window, null, &surface) != vk.Result.success) { - // return error.SurfaceCreateFailed; - // } + std.log.debug("Created surface: {any}", .{core.surface}); // var caps = try I.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface); // const format = search: { diff --git a/src/swapchain.zig b/src/swapchain.zig new file mode 100644 index 0000000..cf25ada --- /dev/null +++ b/src/swapchain.zig @@ -0,0 +1,92 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +const Core = @import("Core.zig"); + +const vk = @import("vk"); + +const I = &Core.I; +const D = &Core.D; +const pdev = &Core.pdev; +const surface = &Core.surface; + +pub fn SwapChain(Flight: type, N: u3) type { + return struct { + handle: vk.SwapchainKHR = .null_handle, + cinfo: vk.SwapchainCreateInfoKHR, + + // todo populate and use this. + flights: std.MultiArrayList(struct{ + fence: vk.Fence, + acquired: vk.Semaphore, + complete: vk.Semaphore, + }), + + pub fn init(alloc: std.mem.Allocator) !SwapChain { + var arena = std.heap.ArenaAllocator.init(alloc); + defer arena.deinit(); + const ialloc = arena.allocator(); + + const caps = try I.getPhysicalDeviceSurfaceCapabilitiesKHR( + pdev, + surface, + ); + + const formats = try I.getPhysicalDeviceSurfaceFormatsAllocKHR( + pdev, + surface, + ialloc, + ); + const format: vk.SurfaceFormatKHR = formats[0]; + const mode: vk.PresentModeKHR = .fifo_khr; + + return .{ + .cinfo = vk.SwapchainCreateInfoKHR{ + .surface = surface, + .min_image_count = std.math.clamp( + @min(3, caps.min_image_count + 1), + caps.min_image_count, + if (caps.max_image_count > 0) caps.max_image_count else 127, + ), + .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 = mode, + .clipped = vk.TRUE, + .old_swapchain = .null_handle, + }, + }; + } + + fn build(self: *SwapChain) !void { + if (self.handle != .null_handle) return; + + const caps = try I.getPhysicalDeviceSurfaceCapabilitiesKHR( + pdev, + surface, + ); + self.cinfo.image_extent = caps.current_extent; + + self.handle = try D.createSwapchainKHR(&self.cinfo, null); + D.destroySwapchainKHR(self.cinfo.old_swapchain, null); + self.cinfo.old_swapchain = self.handle; + } + + pub fn acquire(self: *SwapChain) !void { + D.acquireNextImageKHR(self.handle, std.math.maxInt(u64), semaphore: Semaphore, fence: Fence) + } + + pub fn invalidate(self: *SwapChain) void { + self.handle = .null_handle; + } + + pub fn deinit(self: SwapChain) void { + D.destroySwapchainKHR(self.cinfo.old_swapchain, null); + } + }; +}