Begin implementing validation layers

This commit is contained in:
Przemyslaw Gasinski 2024-06-23 19:49:05 +02:00
parent a08065fbdf
commit 5c50f5eb7c

View file

@ -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;
}