Begin implementing validation layers
This commit is contained in:
parent
a08065fbdf
commit
5c50f5eb7c
1 changed files with 96 additions and 9 deletions
|
@ -3,6 +3,9 @@ const sdl = @import("sdl2");
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
const QueueFamilyIndices = @import("utilities.zig").QueueFamilyIndices;
|
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 = &.{
|
const apis: []const vk.ApiInfo = &.{
|
||||||
.{
|
.{
|
||||||
.base_commands = .{
|
.base_commands = .{
|
||||||
|
@ -10,7 +13,6 @@ const apis: []const vk.ApiInfo = &.{
|
||||||
},
|
},
|
||||||
.instance_commands = .{
|
.instance_commands = .{
|
||||||
.createDevice = true,
|
.createDevice = true,
|
||||||
// .getDeviceProcAddr = true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
vk.features.version_1_0,
|
vk.features.version_1_0,
|
||||||
|
@ -18,7 +20,8 @@ const apis: []const vk.ApiInfo = &.{
|
||||||
vk.features.version_1_2,
|
vk.features.version_1_2,
|
||||||
vk.features.version_1_3,
|
vk.features.version_1_3,
|
||||||
vk.extensions.khr_surface,
|
vk.extensions.khr_surface,
|
||||||
vk.extensions.khr_swapchain,
|
// vk.extensions.khr_swapchain,
|
||||||
|
vk.extensions.ext_debug_utils,
|
||||||
};
|
};
|
||||||
|
|
||||||
const BaseDispatch = vk.BaseWrapper(apis);
|
const BaseDispatch = vk.BaseWrapper(apis);
|
||||||
|
@ -44,6 +47,8 @@ pub const VulkanRenderer = struct {
|
||||||
graphics_queue: Queue,
|
graphics_queue: Queue,
|
||||||
surface: vk.SurfaceKHR,
|
surface: vk.SurfaceKHR,
|
||||||
|
|
||||||
|
debug_utils: ?vk.DebugUtilsMessengerEXT,
|
||||||
|
|
||||||
pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self {
|
pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self {
|
||||||
var self: Self = undefined;
|
var self: Self = undefined;
|
||||||
self.window = window;
|
self.window = window;
|
||||||
|
@ -58,15 +63,18 @@ pub const VulkanRenderer = struct {
|
||||||
vki.* = try InstanceDispatch.load(instance, self.vkb.dispatch.vkGetInstanceProcAddr);
|
vki.* = try InstanceDispatch.load(instance, self.vkb.dispatch.vkGetInstanceProcAddr);
|
||||||
|
|
||||||
self.instance = Instance.init(instance, vki);
|
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();
|
self.physical_device = try self.getPhysicalDevice();
|
||||||
|
|
||||||
|
if (enable_validation_layers) {
|
||||||
|
self.debug_utils = try self.createDebugMessenger();
|
||||||
|
}
|
||||||
|
|
||||||
const device = try self.createLogicalDevice();
|
const device = try self.createLogicalDevice();
|
||||||
|
|
||||||
const vkd = try allocator.create(DeviceDispatch);
|
const vkd = try allocator.create(DeviceDispatch);
|
||||||
errdefer allocator.destroy(vkd);
|
errdefer allocator.destroy(vkd);
|
||||||
// FIXME Why does it only work with no fail?
|
vkd.* = try DeviceDispatch.load(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr);
|
||||||
vkd.* = DeviceDispatch.loadNoFail(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr);
|
|
||||||
|
|
||||||
self.device = Device.init(device, vkd);
|
self.device = Device.init(device, vkd);
|
||||||
const queue = try self.getDeviceQueues();
|
const queue = try self.getDeviceQueues();
|
||||||
|
@ -77,7 +85,11 @@ pub const VulkanRenderer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createInstance(self: Self) !vk.Instance {
|
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);
|
defer self.allocator.free(extensions);
|
||||||
|
|
||||||
std.debug.print("[Required instance extensions]\n", .{});
|
std.debug.print("[Required instance extensions]\n", .{});
|
||||||
|
@ -97,11 +109,35 @@ pub const VulkanRenderer = struct {
|
||||||
.api_version = vk.API_VERSION_1_3,
|
.api_version = vk.API_VERSION_1_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
return try self.vkb.createInstance(&.{
|
var instance_create_info: vk.InstanceCreateInfo = .{
|
||||||
.p_application_info = &app_info,
|
.p_application_info = &app_info,
|
||||||
.enabled_extension_count = @intCast(extensions.len),
|
.enabled_extension_count = @intCast(extensions.len),
|
||||||
.pp_enabled_extension_names = @ptrCast(extensions),
|
.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 {
|
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);
|
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 {
|
pub fn deinit(self: *Self) void {
|
||||||
|
if (enable_validation_layers) {
|
||||||
|
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
|
||||||
|
}
|
||||||
self.device.destroyDevice(null);
|
self.device.destroyDevice(null);
|
||||||
// self.instance.destroySurfaceKHR(self.surface, null);
|
self.instance.destroySurfaceKHR(self.surface, null);
|
||||||
self.instance.destroyInstance(null);
|
self.instance.destroyInstance(null);
|
||||||
|
|
||||||
self.allocator.destroy(self.device.wrapper);
|
self.allocator.destroy(self.device.wrapper);
|
||||||
self.allocator.destroy(self.instance.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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue