Rework semaphores & fences

This commit is contained in:
Przemyslaw Gasinski 2024-07-09 23:39:25 +02:00
parent 059fa90096
commit c4193db891
2 changed files with 48 additions and 19 deletions

11
README.md Normal file
View file

@ -0,0 +1,11 @@
# Vulkan renderer in Zig & SDL2
This is just a project to learn Vulkan using the Zig programming language.
## Dependencies
TODO
## Build
TODO

View file

@ -12,6 +12,8 @@ const SwapchainImage = Utilities.SwapchainImage;
const enable_validation_layers = builtin.mode == .Debug; const enable_validation_layers = builtin.mode == .Debug;
const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
const MAX_FRAME_DRAWS: u32 = 2;
const apis: []const vk.ApiInfo = &.{ const apis: []const vk.ApiInfo = &.{
vk.features.version_1_0, vk.features.version_1_0,
vk.features.version_1_1, vk.features.version_1_1,
@ -40,6 +42,8 @@ pub const VulkanRenderer = struct {
window: sdl.Window, window: sdl.Window,
current_frame: u32 = 0,
// Main // Main
instance: Instance, instance: Instance,
physical_device: vk.PhysicalDevice, physical_device: vk.PhysicalDevice,
@ -68,9 +72,9 @@ pub const VulkanRenderer = struct {
extent: vk.Extent2D, extent: vk.Extent2D,
// Synchronisation // Synchronisation
image_available: vk.Semaphore, image_available: [MAX_FRAME_DRAWS]vk.Semaphore,
render_finished: vk.Semaphore, render_finished: [MAX_FRAME_DRAWS]vk.Semaphore,
frame_fence: vk.Fence, draw_fences: [MAX_FRAME_DRAWS]vk.Fence,
debug_utils: ?vk.DebugUtilsMessengerEXT, debug_utils: ?vk.DebugUtilsMessengerEXT,
@ -78,6 +82,7 @@ pub const VulkanRenderer = struct {
var self: Self = undefined; var self: Self = undefined;
self.window = window; self.window = window;
self.current_frame = 0;
self.allocator = allocator; self.allocator = allocator;
self.vkb = try BaseDispatch.load(try sdl.vulkan.getVkGetInstanceProcAddr()); self.vkb = try BaseDispatch.load(try sdl.vulkan.getVkGetInstanceProcAddr());
@ -103,14 +108,17 @@ pub const VulkanRenderer = struct {
} }
pub fn draw(self: *Self) !void { pub fn draw(self: *Self) !void {
_ = try self.device.waitForFences(1, @ptrCast(&self.frame_fence), vk.TRUE, std.math.maxInt(u64)); // Wait for given fence to signal (open) from last draw before continuing
_ = try self.device.resetFences(1, @ptrCast(&self.frame_fence)); _ = try self.device.waitForFences(1, @ptrCast(&self.draw_fences[self.current_frame]), vk.TRUE, std.math.maxInt(u64));
// Manually reset (close) fences
try self.device.resetFences(1, @ptrCast(&self.draw_fences[self.current_frame]));
// -- Get next image // -- Get next image
// Get index of next image to be drawn to, and signal semaphore when ready to be drawn to // Get index of next image to be drawn to, and signal semaphore when ready to be drawn to
const image_index_result = try self.device.acquireNextImageKHR( const image_index_result = try self.device.acquireNextImageKHR(
self.swapchain, self.swapchain,
std.math.maxInt(u64), std.math.maxInt(u64),
self.image_available, self.image_available[self.current_frame],
.null_handle, .null_handle,
); );
@ -120,21 +128,22 @@ pub const VulkanRenderer = struct {
const submit_info: vk.SubmitInfo = .{ const submit_info: vk.SubmitInfo = .{
.wait_semaphore_count = 1, // Number of semaphores to wait on .wait_semaphore_count = 1, // Number of semaphores to wait on
.p_wait_semaphores = @ptrCast(&self.image_available), // List of semaphores to wait on .p_wait_semaphores = @ptrCast(&self.image_available[self.current_frame]), // List of semaphores to wait on
.p_wait_dst_stage_mask = &wait_stages, // Stages to check semaphores at .p_wait_dst_stage_mask = &wait_stages, // Stages to check semaphores at
.command_buffer_count = 1, // Number of command buffers to submit .command_buffer_count = 1, // Number of command buffers to submit
.p_command_buffers = @ptrCast(&self.command_buffers[image_index_result.image_index]), // Command buffer to submit .p_command_buffers = @ptrCast(&self.command_buffers[image_index_result.image_index]), // Command buffer to submit
.signal_semaphore_count = 1, // Number of semaphores to signal .signal_semaphore_count = 1, // Number of semaphores to signal
.p_signal_semaphores = @ptrCast(&self.render_finished), // List of semaphores to signal when command buffer finishes .p_signal_semaphores = @ptrCast(&self.render_finished[self.current_frame]), // List of semaphores to signal when command buffer finishes
}; };
// Submit command buffer to queue // Submit command buffer to queue
try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), self.frame_fence); try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), self.draw_fences[self.current_frame]);
// try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), self.frame_fence);
// -- Present rendered image to screen // -- Present rendered image to screen
const present_info: vk.PresentInfoKHR = .{ const present_info: vk.PresentInfoKHR = .{
.wait_semaphore_count = 1, // Number of semaphores to wait on .wait_semaphore_count = 1, // Number of semaphores to wait on
.p_wait_semaphores = @ptrCast(&self.render_finished), // Semaphores to wait on .p_wait_semaphores = @ptrCast(&self.render_finished[self.current_frame]), // Semaphores to wait on
.swapchain_count = 1, // Number of swapchains to present to .swapchain_count = 1, // Number of swapchains to present to
.p_swapchains = @ptrCast(&self.swapchain), // Swapchains to present images to .p_swapchains = @ptrCast(&self.swapchain), // Swapchains to present images to
.p_image_indices = @ptrCast(&image_index_result.image_index), // Index of images in swapchains to present .p_image_indices = @ptrCast(&image_index_result.image_index), // Index of images in swapchains to present
@ -142,6 +151,9 @@ pub const VulkanRenderer = struct {
// Present image // Present image
_ = try self.device.queuePresentKHR(self.presentation_queue.handle, &present_info); _ = try self.device.queuePresentKHR(self.presentation_queue.handle, &present_info);
// Get next frame (use % to keep the current frame below MAX_FRAME_DRAWS)
self.current_frame = (self.current_frame + 1) % MAX_FRAME_DRAWS;
} }
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
@ -149,10 +161,13 @@ pub const VulkanRenderer = struct {
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null); self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
} }
_ = self.device.waitForFences(1, @ptrCast(&self.frame_fence), vk.TRUE, std.math.maxInt(u64)) catch undefined; self.device.deviceWaitIdle() catch undefined;
self.device.destroyFence(self.frame_fence, null);
self.device.destroySemaphore(self.render_finished, null); for (0..MAX_FRAME_DRAWS) |i| {
self.device.destroySemaphore(self.image_available, null); self.device.destroySemaphore(self.render_finished[i], null);
self.device.destroySemaphore(self.image_available[i], null);
self.device.destroyFence(self.draw_fences[i], null);
}
self.allocator.free(self.command_buffers); self.allocator.free(self.command_buffers);
self.device.destroyCommandPool(self.graphics_command_pool, null); self.device.destroyCommandPool(self.graphics_command_pool, null);
@ -638,12 +653,15 @@ pub const VulkanRenderer = struct {
} }
fn createSynchronisation(self: *Self) !void { fn createSynchronisation(self: *Self) !void {
// Semaphore creation information // Fence create information
self.image_available = try self.device.createSemaphore(&.{}, null);
self.render_finished = try self.device.createSemaphore(&.{}, null);
const fence_create_info: vk.FenceCreateInfo = .{ .flags = .{ .signaled_bit = true } }; const fence_create_info: vk.FenceCreateInfo = .{ .flags = .{ .signaled_bit = true } };
self.frame_fence = try self.device.createFence(&fence_create_info, null);
// Semaphore creation information
for (0..MAX_FRAME_DRAWS) |i| {
self.image_available[i] = try self.device.createSemaphore(&.{}, null);
self.render_finished[i] = try self.device.createSemaphore(&.{}, null);
self.draw_fences[i] = try self.device.createFence(&fence_create_info, null);
}
} }
fn recordCommands(self: *Self) !void { fn recordCommands(self: *Self) !void {