From 5c50f5eb7c6957a6cc573e438c19d3f7b35d7b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Gasi=C7=B9ski?= Date: Sun, 23 Jun 2024 19:49:05 +0200 Subject: [PATCH] Begin implementing validation layers --- src/vulkan_renderer.zig | 105 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 9 deletions(-) diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index 83065a6..9cc490c 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -3,6 +3,9 @@ const sdl = @import("sdl2"); const vk = @import("vulkan"); const QueueFamilyIndices = @import("utilities.zig").QueueFamilyIndices; +const enable_validation_layers = true; +const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; + const apis: []const vk.ApiInfo = &.{ .{ .base_commands = .{ @@ -10,7 +13,6 @@ const apis: []const vk.ApiInfo = &.{ }, .instance_commands = .{ .createDevice = true, - // .getDeviceProcAddr = true, }, }, vk.features.version_1_0, @@ -18,7 +20,8 @@ const apis: []const vk.ApiInfo = &.{ vk.features.version_1_2, vk.features.version_1_3, vk.extensions.khr_surface, - vk.extensions.khr_swapchain, + // vk.extensions.khr_swapchain, + vk.extensions.ext_debug_utils, }; const BaseDispatch = vk.BaseWrapper(apis); @@ -44,6 +47,8 @@ pub const VulkanRenderer = struct { graphics_queue: Queue, surface: vk.SurfaceKHR, + debug_utils: ?vk.DebugUtilsMessengerEXT, + pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self { var self: Self = undefined; self.window = window; @@ -58,15 +63,18 @@ pub const VulkanRenderer = struct { vki.* = try InstanceDispatch.load(instance, self.vkb.dispatch.vkGetInstanceProcAddr); self.instance = Instance.init(instance, vki); - // self.surface = try sdl.vulkan.createSurface(self.window, self.instance.handle); + self.surface = try sdl.vulkan.createSurface(self.window, self.instance.handle); self.physical_device = try self.getPhysicalDevice(); + if (enable_validation_layers) { + self.debug_utils = try self.createDebugMessenger(); + } + const device = try self.createLogicalDevice(); const vkd = try allocator.create(DeviceDispatch); errdefer allocator.destroy(vkd); - // FIXME Why does it only work with no fail? - vkd.* = DeviceDispatch.loadNoFail(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); + vkd.* = try DeviceDispatch.load(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); self.device = Device.init(device, vkd); const queue = try self.getDeviceQueues(); @@ -77,7 +85,11 @@ pub const VulkanRenderer = struct { } fn createInstance(self: Self) !vk.Instance { - const extensions = try sdl.vulkan.getInstanceExtensionsAlloc(self.window, self.allocator); + if (enable_validation_layers and !self.checkValidationLayersSupport()) { + return error.LayerNotPresent; + } + + const extensions = try self.getRequiredExtensions(); defer self.allocator.free(extensions); std.debug.print("[Required instance extensions]\n", .{}); @@ -97,11 +109,35 @@ pub const VulkanRenderer = struct { .api_version = vk.API_VERSION_1_3, }; - return try self.vkb.createInstance(&.{ + var instance_create_info: vk.InstanceCreateInfo = .{ .p_application_info = &app_info, .enabled_extension_count = @intCast(extensions.len), .pp_enabled_extension_names = @ptrCast(extensions), - }, null); + }; + + if (enable_validation_layers) { + instance_create_info.enabled_layer_count = @intCast(validation_layers.len); + instance_create_info.pp_enabled_layer_names = &validation_layers; + } + + return try self.vkb.createInstance(&instance_create_info, null); + } + + fn getRequiredExtensions(self: Self) ![][*:0]const u8 { + var ext_count = sdl.vulkan.getInstanceExtensionsCount(self.window); + + if (enable_validation_layers) { + ext_count += 1; + } + + var extensions = try self.allocator.alloc([*:0]const u8, ext_count); + _ = try sdl.vulkan.getInstanceExtensions(self.window, extensions); + + if (enable_validation_layers) { + extensions[extensions.len - 1] = vk.extensions.ext_debug_utils.name; + } + + return extensions; } fn checkExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool { @@ -213,12 +249,63 @@ pub const VulkanRenderer = struct { return self.device.getDeviceQueue(indices.graphics_family.?, 0); } + fn checkValidationLayersSupport(self: Self) bool { + var layer_count: u32 = undefined; + _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, null) catch { + return false; + }; + + const available_layers = self.allocator.alloc(vk.LayerProperties, layer_count) catch unreachable; + defer self.allocator.free(available_layers); + + _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, available_layers.ptr) catch { + return false; + }; + + for (validation_layers) |validation_layer| { + for (available_layers) |available_layer| { + if (std.mem.eql(u8, std.mem.span(validation_layer), std.mem.sliceTo(&available_layer.layer_name, 0))) { + return true; + } + } + } + + return false; + } + + fn createDebugMessenger(self: Self) !vk.DebugUtilsMessengerEXT { + const debug_create_info: vk.DebugUtilsMessengerCreateInfoEXT = .{ + .message_severity = .{ .verbose_bit_ext = true, .warning_bit_ext = true, .error_bit_ext = true }, + .message_type = .{ .general_bit_ext = true, .validation_bit_ext = true, .performance_bit_ext = true }, + .pfn_user_callback = debugCallback, + }; + + return try self.instance.createDebugUtilsMessengerEXT(&debug_create_info, null); + } + pub fn deinit(self: *Self) void { + if (enable_validation_layers) { + self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null); + } self.device.destroyDevice(null); - // self.instance.destroySurfaceKHR(self.surface, null); + self.instance.destroySurfaceKHR(self.surface, null); self.instance.destroyInstance(null); self.allocator.destroy(self.device.wrapper); self.allocator.destroy(self.instance.wrapper); } }; + +// message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, +// message_types: vk.DebugUtilsMessageTypeFlagsEXT, +// p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, +// p_user_data: ?*anyopaque, +fn debugCallback( + _: vk.DebugUtilsMessageSeverityFlagsEXT, + _: vk.DebugUtilsMessageTypeFlagsEXT, + p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, + _: ?*anyopaque, +) callconv(vk.vulkan_call_conv) vk.Bool32 { + std.debug.print("Validation layers: {s}\n", .{p_callback_data.?.p_message.?}); + return vk.TRUE; +}