diff --git a/src/utilities.zig b/src/utilities.zig index c73d2db..79d9519 100644 --- a/src/utilities.zig +++ b/src/utilities.zig @@ -1,10 +1,13 @@ const std = @import("std"); const vk = @import("vulkan"); +pub const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name}; + pub const QueueFamilyIndices = struct { - graphics_family: ?u32, + graphics_family: ?u32 = null, + presentation_family: ?u32 = null, pub fn isValid(self: QueueFamilyIndices) bool { - return self.graphics_family != null; + return self.graphics_family != null and self.presentation_family != null; } }; diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index 9cc490c..ca2de66 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -1,26 +1,27 @@ const std = @import("std"); const sdl = @import("sdl2"); const vk = @import("vulkan"); -const QueueFamilyIndices = @import("utilities.zig").QueueFamilyIndices; +const Utilities = @import("utilities.zig"); +const QueueFamilyIndices = Utilities.QueueFamilyIndices; const enable_validation_layers = true; const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; const apis: []const vk.ApiInfo = &.{ - .{ - .base_commands = .{ - .createInstance = true, - }, - .instance_commands = .{ - .createDevice = true, - }, - }, + // .{ + // .base_commands = .{ + // .createInstance = true, + // }, + // .instance_commands = .{ + // .createDevice = true, + // }, + // }, vk.features.version_1_0, vk.features.version_1_1, 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, }; @@ -44,7 +45,10 @@ pub const VulkanRenderer = struct { instance: Instance, physical_device: vk.PhysicalDevice, device: Device, + graphics_queue: Queue, + presentation_queue: Queue, + surface: vk.SurfaceKHR, debug_utils: ?vk.DebugUtilsMessengerEXT, @@ -64,12 +68,12 @@ pub const VulkanRenderer = struct { self.instance = Instance.init(instance, vki); 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(); } + self.physical_device = try self.getPhysicalDevice(); const device = try self.createLogicalDevice(); const vkd = try allocator.create(DeviceDispatch); @@ -77,9 +81,10 @@ pub const VulkanRenderer = struct { vkd.* = try DeviceDispatch.load(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); self.device = Device.init(device, vkd); - const queue = try self.getDeviceQueues(); + const queues = try self.getDeviceQueues(); - self.graphics_queue = Queue.init(queue, vkd); + self.graphics_queue = Queue.init(queues[0], vkd); + self.presentation_queue = Queue.init(queues[1], vkd); return self; } @@ -97,7 +102,7 @@ pub const VulkanRenderer = struct { std.debug.print("\t- {s}\n", .{ext}); } - if (!try self.checkExtensions(&extensions)) { + if (!try self.checkInstanceExtensions(&extensions)) { return error.ExtensionNotPresent; } @@ -116,8 +121,11 @@ pub const VulkanRenderer = struct { }; if (enable_validation_layers) { + const debug_create_info = getDebugUtilsCreateInfo(); + instance_create_info.enabled_layer_count = @intCast(validation_layers.len); instance_create_info.pp_enabled_layer_names = &validation_layers; + instance_create_info.p_next = &debug_create_info; } return try self.vkb.createInstance(&instance_create_info, null); @@ -140,7 +148,7 @@ pub const VulkanRenderer = struct { return extensions; } - fn checkExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool { + fn checkInstanceExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool { var prop_count: u32 = 0; _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null); @@ -150,15 +158,39 @@ pub const VulkanRenderer = struct { _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, props.ptr); for (required_extensions.*) |required_extension| { - var found = false; - for (props) |prop| { if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(required_extension))) { - found = true; + break; } + } else { + return false; } + } - if (!found) { + return true; + } + + fn checkDeviceExtensions(self: Self, pdev: vk.PhysicalDevice) !bool { + var prop_count: u32 = 0; + _ = try self.instance.enumerateDeviceExtensionProperties(pdev, null, &prop_count, null); + + if (prop_count == 0) { + return false; + } + + std.debug.print("Ext count: {d}\n", .{prop_count}); + const props = try self.allocator.alloc(vk.ExtensionProperties, prop_count); + defer self.allocator.free(props); + + _ = try self.vkb.enumerateDeviceExtensionProperties(null, &prop_count, props.ptr); + + for (Utilities.device_extensions) |device_extension| { + for (props) |prop| { + // std.debug.print("Ext: {s}\n", .{&prop.extension_name}); + if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(device_extension))) { + break; + } + } else { return false; } } @@ -196,7 +228,9 @@ pub const VulkanRenderer = struct { return false; }; - return queue_family_indices.isValid(); + const extension_support = self.checkDeviceExtensions(pdev) catch false; + + return queue_family_indices.isValid() and extension_support; } fn getQueueFamilies(self: Self, pdev: vk.PhysicalDevice) !QueueFamilyIndices { @@ -215,6 +249,11 @@ pub const VulkanRenderer = struct { indices.graphics_family = @intCast(i); } + const presentation_support = try self.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), self.surface); + if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) { + indices.presentation_family = @intCast(i); + } + if (indices.isValid()) { return indices; } @@ -228,25 +267,40 @@ pub const VulkanRenderer = struct { // 1 is the highest priority const priority = [_]f32{1}; - const queue_create_info = [_]vk.DeviceQueueCreateInfo{.{ - .queue_family_index = indices.graphics_family.?, - .queue_count = 1, - .p_queue_priorities = &priority, - }}; + const qci = [_]vk.DeviceQueueCreateInfo{ + .{ + .queue_family_index = indices.graphics_family.?, + .queue_count = 1, + .p_queue_priorities = &priority, + }, + .{ + .queue_family_index = indices.presentation_family.?, + .queue_count = 1, + .p_queue_priorities = &priority, + }, + }; + + const queue_count: u32 = if (indices.graphics_family.? == indices.presentation_family.?) + 1 + else + 2; const device_create_info: vk.DeviceCreateInfo = .{ - .queue_create_info_count = 1, - .p_queue_create_infos = &queue_create_info, - .enabled_extension_count = 0, + .queue_create_info_count = queue_count, + .p_queue_create_infos = &qci, + .pp_enabled_extension_names = &Utilities.device_extensions, + .enabled_extension_count = @intCast(Utilities.device_extensions.len), }; return try self.instance.createDevice(self.physical_device, &device_create_info, null); } - fn getDeviceQueues(self: Self) !vk.Queue { + fn getDeviceQueues(self: Self) ![2]vk.Queue { const indices = try self.getQueueFamilies(self.physical_device); - return self.device.getDeviceQueue(indices.graphics_family.?, 0); + const graphics_queue = self.device.getDeviceQueue(indices.graphics_family.?, 0); + const presentation_queue = self.device.getDeviceQueue(indices.presentation_family.?, 0); + return .{ graphics_queue, presentation_queue }; } fn checkValidationLayersSupport(self: Self) bool { @@ -274,11 +328,7 @@ pub const VulkanRenderer = struct { } 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, - }; + const debug_create_info = getDebugUtilsCreateInfo(); return try self.instance.createDebugUtilsMessengerEXT(&debug_create_info, null); } @@ -296,6 +346,14 @@ pub const VulkanRenderer = struct { } }; +fn getDebugUtilsCreateInfo() vk.DebugUtilsMessengerCreateInfoEXT { + return 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, + }; +} + // message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, // message_types: vk.DebugUtilsMessageTypeFlagsEXT, // p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT,