Implement drawing

This commit is contained in:
Przemyslaw Gasinski 2024-07-04 14:41:13 +02:00
parent 6a85e4ce51
commit 656406f121
2 changed files with 95 additions and 36 deletions

View file

@ -28,6 +28,8 @@ pub fn main() !void {
else => {},
}
}
try vulkan_renderer.draw();
}
}

View file

@ -48,6 +48,8 @@ pub const VulkanRenderer = struct {
presentation_queue: Queue,
surface: vk.SurfaceKHR,
swapchain: vk.SwapchainKHR,
viewport: vk.Viewport,
scissor: vk.Rect2D,
swapchain_images: []SwapchainImage,
swapchain_framebuffers: []vk.Framebuffer,
@ -65,6 +67,10 @@ pub const VulkanRenderer = struct {
swapchain_image_format: vk.Format,
extent: vk.Extent2D,
// Synchronisation
image_available: vk.Semaphore,
render_finished: vk.Semaphore,
debug_utils: ?vk.DebugUtilsMessengerEXT,
pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self {
@ -89,10 +95,82 @@ pub const VulkanRenderer = struct {
try self.createFramebuffers();
try self.createCommandPool();
try self.createCommandBuffers();
try self.recordCommands();
try self.createSynchronisation();
return self;
}
pub fn draw(self: *Self) !void {
// -- Get next image
// 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(self.swapchain, std.math.maxInt(u64), self.image_available, .null_handle);
// -- Submit command buffer to render
// Queue submission information
const wait_stages = [_]vk.PipelineStageFlags{.{ .color_attachment_output_bit = true }};
const submit_info: vk.SubmitInfo = .{
.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_dst_stage_mask = &wait_stages, // Stages to check semaphores at
.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
.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
};
// Submit command buffer to queue
try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), .null_handle);
// -- Present rendered image to screen
const present_info: vk.PresentInfoKHR = .{
.wait_semaphore_count = 1, // Number of semaphores to wait on
.p_wait_semaphores = @ptrCast(&self.render_finished), // Semaphores to wait on
.swapchain_count = 1, // Number of swapchains to present 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
};
// Present image
_ = try self.device.queuePresentKHR(self.presentation_queue.handle, &present_info);
}
pub fn deinit(self: *Self) void {
if (enable_validation_layers) {
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
}
self.device.destroySemaphore(self.render_finished, null);
self.device.destroySemaphore(self.image_available, null);
self.allocator.free(self.command_buffers);
self.device.destroyCommandPool(self.graphics_command_pool, null);
for (self.swapchain_framebuffers) |framebuffer| {
self.device.destroyFramebuffer(framebuffer, null);
}
self.allocator.free(self.swapchain_framebuffers);
self.device.destroyPipeline(self.graphics_pipeline, null);
self.device.destroyPipelineLayout(self.pipeline_layout, null);
self.device.destroyRenderPass(self.render_pass, null);
for (self.swapchain_images) |swapchain_image| {
self.device.destroyImageView(swapchain_image.image_view, null);
}
self.allocator.free(self.swapchain_images);
self.device.destroySwapchainKHR(self.swapchain, null);
self.device.destroyDevice(null);
self.instance.destroySurfaceKHR(self.surface, null);
self.instance.destroyInstance(null);
self.allocator.destroy(self.device.wrapper);
self.allocator.destroy(self.instance.wrapper);
}
fn createInstance(self: *Self) !void {
if (enable_validation_layers and !self.checkValidationLayersSupport()) {
// TODO Better error
@ -380,7 +458,7 @@ pub const VulkanRenderer = struct {
};
// -- Viewport & scissor --
const viewport: vk.Viewport = .{
self.viewport = .{
.x = 0.0,
.y = 0.0,
.width = @floatFromInt(self.extent.width),
@ -389,16 +467,16 @@ pub const VulkanRenderer = struct {
.max_depth = 1.0,
};
const scissor: vk.Rect2D = .{
self.scissor = .{
.offset = .{ .x = 0, .y = 0 },
.extent = self.extent,
};
const viewport_state_create_info: vk.PipelineViewportStateCreateInfo = .{
.viewport_count = 1,
.p_viewports = @ptrCast(&viewport),
.p_viewports = @ptrCast(&self.viewport),
.scissor_count = 1,
.p_scissors = @ptrCast(&scissor),
.p_scissors = @ptrCast(&self.scissor),
};
// -- Dynamic states --
@ -549,6 +627,12 @@ pub const VulkanRenderer = struct {
}
}
fn createSynchronisation(self: *Self) !void {
// Semaphore creation information
self.image_available = try self.device.createSemaphore(&.{}, null);
self.render_finished = try self.device.createSemaphore(&.{}, null);
}
fn recordCommands(self: *Self) !void {
// Information about how to begin each command
const buffer_begin_info: vk.CommandBufferBeginInfo = .{
@ -569,6 +653,7 @@ pub const VulkanRenderer = struct {
},
.p_clear_values = &clear_values, // List of clear values (TODO: Depth attachment clear value)
.clear_value_count = 1,
.framebuffer = undefined,
};
for (self.command_buffers, 0..) |command_buffer, i| {
@ -584,6 +669,10 @@ pub const VulkanRenderer = struct {
// Bind pipeline to be used in render pass
command_buffer.bindPipeline(.graphics, self.graphics_pipeline);
// Needed when using dynamic state
command_buffer.setViewport(0, 1, @ptrCast(&self.viewport));
command_buffer.setScissor(0, 1, @ptrCast(&self.scissor));
// Execute a pipeline
command_buffer.draw(3, 1, 0, 0);
@ -806,38 +895,6 @@ pub const VulkanRenderer = struct {
return try self.device.createImageView(&image_view_create_info, null);
}
pub fn deinit(self: *Self) void {
if (enable_validation_layers) {
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
}
self.allocator.free(self.command_buffers);
self.device.destroyCommandPool(self.graphics_command_pool, null);
for (self.swapchain_framebuffers) |framebuffer| {
self.device.destroyFramebuffer(framebuffer, null);
}
self.allocator.free(self.swapchain_framebuffers);
self.device.destroyPipeline(self.graphics_pipeline, null);
self.device.destroyPipelineLayout(self.pipeline_layout, null);
self.device.destroyRenderPass(self.render_pass, null);
for (self.swapchain_images) |swapchain_image| {
self.device.destroyImageView(swapchain_image.image_view, null);
}
self.allocator.free(self.swapchain_images);
self.device.destroySwapchainKHR(self.swapchain, null);
self.device.destroyDevice(null);
self.instance.destroySurfaceKHR(self.surface, null);
self.instance.destroyInstance(null);
self.allocator.destroy(self.device.wrapper);
self.allocator.destroy(self.instance.wrapper);
}
};
// Format: VK_FORMAT_R8G8B8A8_UNORM (VK_FORMAT_B8G8R8A8_UNORM as backup)