Start implementing the swapchain

This commit is contained in:
Przemyslaw Gasinski 2024-06-25 12:44:15 +02:00
parent 5c50f5eb7c
commit 73a30b9d03
2 changed files with 98 additions and 37 deletions

View file

@ -1,10 +1,13 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
pub const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
pub const QueueFamilyIndices = struct { pub const QueueFamilyIndices = struct {
graphics_family: ?u32, graphics_family: ?u32 = null,
presentation_family: ?u32 = null,
pub fn isValid(self: QueueFamilyIndices) bool { pub fn isValid(self: QueueFamilyIndices) bool {
return self.graphics_family != null; return self.graphics_family != null and self.presentation_family != null;
} }
}; };

View file

@ -1,26 +1,27 @@
const std = @import("std"); const std = @import("std");
const sdl = @import("sdl2"); const sdl = @import("sdl2");
const vk = @import("vulkan"); 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 enable_validation_layers = true;
const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
const apis: []const vk.ApiInfo = &.{ const apis: []const vk.ApiInfo = &.{
.{ // .{
.base_commands = .{ // .base_commands = .{
.createInstance = true, // .createInstance = true,
}, // },
.instance_commands = .{ // .instance_commands = .{
.createDevice = true, // .createDevice = true,
}, // },
}, // },
vk.features.version_1_0, vk.features.version_1_0,
vk.features.version_1_1, vk.features.version_1_1,
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, vk.extensions.ext_debug_utils,
}; };
@ -44,7 +45,10 @@ pub const VulkanRenderer = struct {
instance: Instance, instance: Instance,
physical_device: vk.PhysicalDevice, physical_device: vk.PhysicalDevice,
device: Device, device: Device,
graphics_queue: Queue, graphics_queue: Queue,
presentation_queue: Queue,
surface: vk.SurfaceKHR, surface: vk.SurfaceKHR,
debug_utils: ?vk.DebugUtilsMessengerEXT, debug_utils: ?vk.DebugUtilsMessengerEXT,
@ -64,12 +68,12 @@ pub const VulkanRenderer = struct {
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();
if (enable_validation_layers) { if (enable_validation_layers) {
self.debug_utils = try self.createDebugMessenger(); self.debug_utils = try self.createDebugMessenger();
} }
self.physical_device = try self.getPhysicalDevice();
const device = try self.createLogicalDevice(); const device = try self.createLogicalDevice();
const vkd = try allocator.create(DeviceDispatch); const vkd = try allocator.create(DeviceDispatch);
@ -77,9 +81,10 @@ pub const VulkanRenderer = struct {
vkd.* = try DeviceDispatch.load(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); vkd.* = try DeviceDispatch.load(device, self.instance.wrapper.dispatch.vkGetDeviceProcAddr);
self.device = Device.init(device, vkd); 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; return self;
} }
@ -97,7 +102,7 @@ pub const VulkanRenderer = struct {
std.debug.print("\t- {s}\n", .{ext}); std.debug.print("\t- {s}\n", .{ext});
} }
if (!try self.checkExtensions(&extensions)) { if (!try self.checkInstanceExtensions(&extensions)) {
return error.ExtensionNotPresent; return error.ExtensionNotPresent;
} }
@ -116,8 +121,11 @@ pub const VulkanRenderer = struct {
}; };
if (enable_validation_layers) { if (enable_validation_layers) {
const debug_create_info = getDebugUtilsCreateInfo();
instance_create_info.enabled_layer_count = @intCast(validation_layers.len); instance_create_info.enabled_layer_count = @intCast(validation_layers.len);
instance_create_info.pp_enabled_layer_names = &validation_layers; 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); return try self.vkb.createInstance(&instance_create_info, null);
@ -140,7 +148,7 @@ pub const VulkanRenderer = struct {
return extensions; 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; var prop_count: u32 = 0;
_ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null); _ = 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); _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, props.ptr);
for (required_extensions.*) |required_extension| { for (required_extensions.*) |required_extension| {
var found = false;
for (props) |prop| { for (props) |prop| {
if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(required_extension))) { 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; return false;
} }
} }
@ -196,7 +228,9 @@ pub const VulkanRenderer = struct {
return false; 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 { fn getQueueFamilies(self: Self, pdev: vk.PhysicalDevice) !QueueFamilyIndices {
@ -215,6 +249,11 @@ pub const VulkanRenderer = struct {
indices.graphics_family = @intCast(i); 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()) { if (indices.isValid()) {
return indices; return indices;
} }
@ -228,25 +267,40 @@ pub const VulkanRenderer = struct {
// 1 is the highest priority // 1 is the highest priority
const priority = [_]f32{1}; const priority = [_]f32{1};
const queue_create_info = [_]vk.DeviceQueueCreateInfo{.{ const qci = [_]vk.DeviceQueueCreateInfo{
.queue_family_index = indices.graphics_family.?, .{
.queue_count = 1, .queue_family_index = indices.graphics_family.?,
.p_queue_priorities = &priority, .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 = .{ const device_create_info: vk.DeviceCreateInfo = .{
.queue_create_info_count = 1, .queue_create_info_count = queue_count,
.p_queue_create_infos = &queue_create_info, .p_queue_create_infos = &qci,
.enabled_extension_count = 0, .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); 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); 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 { fn checkValidationLayersSupport(self: Self) bool {
@ -274,11 +328,7 @@ pub const VulkanRenderer = struct {
} }
fn createDebugMessenger(self: Self) !vk.DebugUtilsMessengerEXT { fn createDebugMessenger(self: Self) !vk.DebugUtilsMessengerEXT {
const debug_create_info: vk.DebugUtilsMessengerCreateInfoEXT = .{ const debug_create_info = getDebugUtilsCreateInfo();
.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); 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_severity: vk.DebugUtilsMessageSeverityFlagsEXT,
// message_types: vk.DebugUtilsMessageTypeFlagsEXT, // message_types: vk.DebugUtilsMessageTypeFlagsEXT,
// p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, // p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT,