From e5cc05e2b8e9f21475425f13f1ee6748d61a5e3a Mon Sep 17 00:00:00 2001 From: David Allemang Date: Thu, 21 Mar 2024 12:58:28 -0400 Subject: [PATCH] separate Window.zig and Context.zig --- src/Context.zig | 208 ++++++++++++++++++++++++++++++++++++++++++++ src/Window.zig | 226 +++--------------------------------------------- src/main.zig | 74 +++------------- 3 files changed, 232 insertions(+), 276 deletions(-) create mode 100644 src/Context.zig diff --git a/src/Context.zig b/src/Context.zig new file mode 100644 index 0000000..68fbc5e --- /dev/null +++ b/src/Context.zig @@ -0,0 +1,208 @@ +const Self = @This(); + +const std = @import("std"); +const c = @import("c.zig"); +const vk = @import("vk"); +const builtin = @import("builtin"); + +const USE_DEBUG_LAYERS = switch (builtin.mode) { + .ReleaseSafe, .Debug => true, + .ReleaseSmall, .ReleaseFast => false, +}; + +allocator: std.mem.Allocator, + +vkb: BaseDispatch, +vki: InstanceDispatch, +vkd: DeviceDispatch, + +instance: vk.Instance, +messenger: if (USE_DEBUG_LAYERS) vk.DebugUtilsMessengerEXT else void, + +pub fn init(allocator: std.mem.Allocator) !Self { + var self: Self = undefined; + self.allocator = allocator; + + self.vkb = try BaseDispatch.load(&c.glfwGetInstanceProcAddress); + + var exts = std.ArrayList([*:0]const u8).init(allocator); + defer exts.deinit(); + + var layers = std.ArrayList([*:0]const u8).init(allocator); + defer layers.deinit(); + + if (USE_DEBUG_LAYERS) { + try layers.append("VK_LAYER_KHRONOS_validation"); + try exts.append("VK_EXT_debug_utils"); + } + + var glfw_ext_count: u32 = 0; + const glfw_exts: [*][*:0]const u8 = @ptrCast(c.glfwGetRequiredInstanceExtensions(&glfw_ext_count)); + try exts.appendSlice(glfw_exts[0..glfw_ext_count]); + + std.log.debug("requesting extensions: {s}", .{exts.items}); + std.log.debug("requesting layers: {s}", .{layers.items}); + + var available_ext_count: u32 = 0; + _ = try self.vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, null); + const available_exts = try allocator.alloc(vk.ExtensionProperties, available_ext_count); + defer allocator.free(available_exts); + _ = try self.vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, available_exts.ptr); + + var available_layer_count: u32 = 0; + _ = try self.vkb.enumerateInstanceLayerProperties(&available_layer_count, null); + const available_layers = try allocator.alloc(vk.LayerProperties, available_layer_count); + defer allocator.free(available_layers); + _ = try self.vkb.enumerateInstanceLayerProperties(&available_layer_count, available_layers.ptr); + + for (exts.items) |name| { + const required_name = std.mem.sliceTo(name, 0); + for (available_exts) |prop| { + const available_name = std.mem.sliceTo(&prop.extension_name, 0); + if (std.mem.eql(u8, required_name, available_name)) break; + } else { + return error.ExtensionNotPresent; + } + } + + for (layers.items) |name| { + const required_name = std.mem.sliceTo(name, 0); + for (available_layers) |prop| { + const available_name = std.mem.sliceTo(&prop.layer_name, 0); + if (std.mem.eql(u8, required_name, available_name)) break; + } else { + return error.LayerNotPresent; + } + } + + const debug_create_info = vk.DebugUtilsMessengerCreateInfoEXT{ + .message_severity = vk.DebugUtilsMessageSeverityFlagsEXT{ + .verbose_bit_ext = false, + .warning_bit_ext = true, + .error_bit_ext = true, + .info_bit_ext = false, + }, + .message_type = vk.DebugUtilsMessageTypeFlagsEXT{ + .general_bit_ext = true, + .validation_bit_ext = true, + .performance_bit_ext = true, + .device_address_binding_bit_ext = false, + }, + .pfn_user_callback = &debug_callback, + .p_user_data = null, + }; + + const app_info = vk.ApplicationInfo{ + .p_application_name = "Hello World", + .application_version = vk.makeApiVersion(0, 0, 0, 0), + .p_engine_name = "No Engine", + .engine_version = vk.makeApiVersion(0, 0, 0, 0), + .api_version = vk.API_VERSION_1_3, + }; + + const create_info = vk.InstanceCreateInfo{ + .p_application_info = &app_info, + .enabled_extension_count = @intCast(exts.items.len), + .pp_enabled_extension_names = exts.items.ptr, + .enabled_layer_count = @intCast(layers.items.len), + .pp_enabled_layer_names = layers.items.ptr, + .p_next = if (USE_DEBUG_LAYERS) &debug_create_info else null, + }; + + self.instance = try self.vkb.createInstance(&create_info, null); + self.vki = try InstanceDispatch.load(self.instance, self.vkb.dispatch.vkGetInstanceProcAddr); + errdefer self.vki.destroyInstance(self.instance, null); + + if (USE_DEBUG_LAYERS) self.messenger = try self.vki.createDebugUtilsMessengerEXT( + self.instance, + &debug_create_info, + null, + ); + errdefer if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT( + self.instance, + self.messenger, + null, + ); + + return self; +} + +pub fn deinit(self: Self) void { + if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT( + self.instance, + self.messenger, + null, + ); + self.vki.destroyInstance(self.instance, null); +} + +export fn debug_callback( + message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, + message_type: vk.DebugUtilsMessageTypeFlagsEXT, + p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, + _: ?*anyopaque, +) callconv(.C) vk.Bool32 { + if (p_callback_data == null) return vk.FALSE; + if (p_callback_data.?.p_message == null) return vk.FALSE; + const msg = p_callback_data.?.p_message.?; + + const scopes = .{ + "validation", + "performance", + "device_address_binding", + "general", + }; + + const scope: []const u8 = inline for (scopes) |tag| { + if (@field(message_type, tag ++ "_bit_ext")) { + break tag; + } + } else { + return vk.FALSE; + }; + + const levels = .{ + "error", + "info", + "warning", + "verbose", + }; + + const level: []const u8 = inline for (levels) |tag| { + if (@field(message_severity, tag ++ "_bit_ext")) { + break tag; + } + } else { + return vk.FALSE; + }; + + // ripped from std.log, but with my own levels and scope. + const stderr = std.io.getStdErr().writer(); + var bw = std.io.bufferedWriter(stderr); + const writer = bw.writer(); + + std.debug.getStderrMutex().lock(); + defer std.debug.getStderrMutex().unlock(); + nosuspend { + writer.print("vk-{s}({s}): {s}\n", .{ level, scope, msg }) catch return vk.FALSE; + bw.flush() catch return vk.FALSE; + } + + return vk.FALSE; +} + +const BaseDispatch = vk.BaseWrapper(.{ + .createInstance = true, + .getInstanceProcAddr = true, + .enumerateInstanceExtensionProperties = true, + .enumerateInstanceLayerProperties = true, +}); + +const InstanceDispatch = vk.InstanceWrapper(.{ + .destroyInstance = true, + .createDebugUtilsMessengerEXT = USE_DEBUG_LAYERS, + .destroyDebugUtilsMessengerEXT = USE_DEBUG_LAYERS, + .submitDebugUtilsMessageEXT = USE_DEBUG_LAYERS, +}); + +const DeviceDispatch = vk.DeviceWrapper(.{}); diff --git a/src/Window.zig b/src/Window.zig index f4d6039..d792468 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -5,238 +5,38 @@ const c = @import("c.zig"); const vk = @import("vk"); const builtin = @import("builtin"); -const USE_DEBUG_LAYERS = switch (builtin.mode) { - .ReleaseSafe, .Debug => true, - .ReleaseSmall, .ReleaseFast => false, -}; - -const BaseDispatch = vk.BaseWrapper(.{ - .createInstance = true, - .getInstanceProcAddr = true, - .enumerateInstanceExtensionProperties = true, - .enumerateInstanceLayerProperties = true, -}); -const InstanceDispatch = vk.InstanceWrapper(.{ - .destroyInstance = true, - .createDebugUtilsMessengerEXT = USE_DEBUG_LAYERS, - .destroyDebugUtilsMessengerEXT = USE_DEBUG_LAYERS, - .submitDebugUtilsMessageEXT = USE_DEBUG_LAYERS, -}); -const DeviceDispatch = vk.DeviceWrapper(.{}); - allocator: std.mem.Allocator, -vkb: BaseDispatch, -vki: InstanceDispatch, -vkd: DeviceDispatch, - window: *c.GLFWwindow, -instance: vk.Instance, -messenger: if (USE_DEBUG_LAYERS) vk.DebugUtilsMessengerEXT else void, - pub fn mainLoop(self: Self) void { while (c.glfwWindowShouldClose(self.window) == 0) : (c.glfwPollEvents()) { c.glfwSwapBuffers(self.window); } } -fn initWindow(self: *Self) !void { +pub fn init( + allocator: std.mem.Allocator, + width: u32, + height: u32, + title: []const u8, +) !Self { + var self: Self = undefined; + self.allocator = allocator; + c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API); self.window = c.glfwCreateWindow( - 1280, - 720, - "Hello World", + @intCast(width), + @intCast(height), + title.ptr, null, null, ) orelse return error.glfwCreateWindowFailed; errdefer c.glfwDestroyWindow(self.window); -} - -fn deinitWindow(self: Self) void { - c.glfwDestroyWindow(self.window); -} - -export fn debug_callback( - message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, - message_type: vk.DebugUtilsMessageTypeFlagsEXT, - p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, - _: ?*anyopaque, -) callconv(.C) vk.Bool32 { - if (p_callback_data == null) return vk.FALSE; - if (p_callback_data.?.p_message == null) return vk.FALSE; - const msg = p_callback_data.?.p_message.?; - - const scopes = .{ - "validation", - "performance", - "device_address_binding", - "general", - }; - - const scope: []const u8 = inline for (scopes) |tag| { - if (@field(message_type, tag ++ "_bit_ext")) { - break tag; - } - } else { - return vk.FALSE; - }; - - const levels = .{ - "error", - "info", - "warning", - "verbose", - }; - - const level: []const u8 = inline for (levels) |tag| { - if (@field(message_severity, tag ++ "_bit_ext")) { - break tag; - } - } else { - return vk.FALSE; - }; - - // ripped from std.log, but with my own levels and scope. - const stderr = std.io.getStdErr().writer(); - var bw = std.io.bufferedWriter(stderr); - const writer = bw.writer(); - - std.debug.getStderrMutex().lock(); - defer std.debug.getStderrMutex().unlock(); - nosuspend { - writer.print("vk-{s}({s}): {s}\n", .{ level, scope, msg }) catch return vk.FALSE; - bw.flush() catch return vk.FALSE; - } - - return vk.FALSE; -} - -fn initVulkan(self: *Self) !void { - self.vkb = try BaseDispatch.load(&c.glfwGetInstanceProcAddress); - - var exts = std.ArrayList([*:0]const u8).init(self.allocator); - defer exts.deinit(); - - var layers = std.ArrayList([*:0]const u8).init(self.allocator); - defer layers.deinit(); - - if (USE_DEBUG_LAYERS) { - try layers.append("VK_LAYER_KHRONOS_validation"); - try exts.append("VK_EXT_debug_utils"); - } - - var glfw_ext_count: u32 = 0; - const glfw_exts: [*][*:0]const u8 = @ptrCast(c.glfwGetRequiredInstanceExtensions(&glfw_ext_count)); - try exts.appendSlice(glfw_exts[0..glfw_ext_count]); - - std.log.debug("requesting extensions: {s}", .{exts.items}); - std.log.debug("requesting layers: {s}", .{layers.items}); - - var available_ext_count: u32 = 0; - _ = try self.vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, null); - const available_exts = try self.allocator.alloc(vk.ExtensionProperties, available_ext_count); - defer self.allocator.free(available_exts); - _ = try self.vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, available_exts.ptr); - - var available_layer_count: u32 = 0; - _ = try self.vkb.enumerateInstanceLayerProperties(&available_layer_count, null); - const available_layers = try self.allocator.alloc(vk.LayerProperties, available_layer_count); - defer self.allocator.free(available_layers); - _ = try self.vkb.enumerateInstanceLayerProperties(&available_layer_count, available_layers.ptr); - - for (exts.items) |name| { - const required_name = std.mem.sliceTo(name, 0); - for (available_exts) |prop| { - const available_name = std.mem.sliceTo(&prop.extension_name, 0); - if (std.mem.eql(u8, required_name, available_name)) break; - } else { - return error.ExtensionNotPresent; - } - } - - for (layers.items) |name| { - const required_name = std.mem.sliceTo(name, 0); - for (available_layers) |prop| { - const available_name = std.mem.sliceTo(&prop.layer_name, 0); - if (std.mem.eql(u8, required_name, available_name)) break; - } else { - return error.LayerNotPresent; - } - } - - const debug_create_info = vk.DebugUtilsMessengerCreateInfoEXT{ - .message_severity = vk.DebugUtilsMessageSeverityFlagsEXT{ - .verbose_bit_ext = false, - .warning_bit_ext = true, - .error_bit_ext = true, - .info_bit_ext = false, - }, - .message_type = vk.DebugUtilsMessageTypeFlagsEXT{ - .general_bit_ext = true, - .validation_bit_ext = true, - .performance_bit_ext = true, - .device_address_binding_bit_ext = false, - }, - .pfn_user_callback = &debug_callback, - .p_user_data = null, - }; - - const app_info = vk.ApplicationInfo{ - .p_application_name = "Hello World", - .application_version = vk.makeApiVersion(0, 0, 0, 0), - .p_engine_name = "No Engine", - .engine_version = vk.makeApiVersion(0, 0, 0, 0), - .api_version = vk.API_VERSION_1_3, - }; - - const create_info = vk.InstanceCreateInfo{ - .p_application_info = &app_info, - .enabled_extension_count = @intCast(exts.items.len), - .pp_enabled_extension_names = exts.items.ptr, - .enabled_layer_count = @intCast(layers.items.len), - .pp_enabled_layer_names = layers.items.ptr, - .p_next = if (USE_DEBUG_LAYERS) &debug_create_info else null, - }; - - self.instance = try self.vkb.createInstance(&create_info, null); - self.vki = try InstanceDispatch.load(self.instance, self.vkb.dispatch.vkGetInstanceProcAddr); - errdefer self.vki.destroyInstance(self.instance, null); - - if (USE_DEBUG_LAYERS) self.messenger = try self.vki.createDebugUtilsMessengerEXT( - self.instance, - &debug_create_info, - null, - ); - errdefer if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT( - self.instance, - self.messenger, - null, - ); -} - -fn deinitVulkan(self: Self) void { - if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT( - self.instance, - self.messenger, - null, - ); - self.vki.destroyInstance(self.instance, null); -} - -pub fn init(allocator: std.mem.Allocator) !Self { - var self: Self = undefined; - self.allocator = allocator; - - try self.initWindow(); - errdefer self.deinitWindow(); - try self.initVulkan(); - errdefer self.deinitVulkan(); return self; } pub fn deinit(self: Self) void { - self.deinitWindow(); - self.deinitVulkan(); + c.glfwDestroyWindow(self.window); } diff --git a/src/main.zig b/src/main.zig index 9234539..fdf0ba4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,56 +3,7 @@ const c = @import("c.zig"); const vk = @import("vk"); const Window = @import("Window.zig"); - -// const BaseDispatch = vk.BaseWrapper(.{ -// .createInstance = true, -// .getInstanceProcAddr = true, -// }); -// -// const InstanceDispatch = vk.InstanceWrapper(.{ -// .destroyInstance = true, -// }); -// -// const Context = struct { -// vkb: BaseDispatch, -// vki: InstanceDispatch, -// -// instance: vk.Instance, -// -// pub fn init(allocator: std.mem.Allocator, app_name: [*:0]const u8, window: *c.GLFWwindow) !Context { -// _ = allocator; -// _ = window; -// -// var self: Context = undefined; -// self.vkb = try BaseDispatch.load(c.glfwGetInstanceProcAddress); -// -// var glfw_exts_count: u32 = 0; -// const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count); -// -// const app_info = vk.ApplicationInfo{ -// .p_application_name = app_name, -// .application_version = vk.makeApiVersion(0, 0, 0, 0), -// .p_engine_name = app_name, -// .engine_version = vk.makeApiVersion(0, 0, 0, 0), -// .api_version = vk.API_VERSION_1_2, -// }; -// -// self.instance = try self.vkb.createInstance(&.{ -// .p_application_info = &app_info, -// .enabled_extension_count = glfw_exts_count, -// .pp_enabled_extension_names = @as([*]const [*:0]const u8, @ptrCast(glfw_exts)), -// }, null); -// -// self.vki = try InstanceDispatch.load(self.instance, self.vkb.dispatch.vkGetInstanceProcAddr); -// errdefer self.vki.destroyInstance(self.instance, null); -// -// return self; -// } -// -// pub fn deinit(self: Context) void { -// self.vki.destroyInstance(self.instance, null); -// } -// }; +const Context = @import("Context.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -64,19 +15,16 @@ pub fn main() !void { } defer c.glfwTerminate(); - const window = try Window.init(allocator); + const ctx = try Context.init(allocator); + defer ctx.deinit(); + + const window = try Window.init( + allocator, + 1280, + 720, + "Hello World", + ); defer window.deinit(); - // window.mainLoop(); - - // c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API); - // const window: *c.GLFWwindow = c.glfwCreateWindow(1280, 720, "Hello World!", null, null) orelse return error.GlfwWindowFailed; - // defer c.glfwDestroyWindow(window); - - // const ctx = try Context.init(allocator, "content", window); - // defer ctx.deinit(); - - // while (c.glfwWindowShouldClose(window) == 0) : (c.glfwPollEvents()) { - // c.glfwSwapBuffers(window); - // } + window.mainLoop(); }