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

View file

@ -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{.{
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,