From 6a85e4ce51d5478ffdb70b426952b98ccd3de7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Gasi=C7=B9ski?= Date: Wed, 3 Jul 2024 23:33:16 +0200 Subject: [PATCH] Create command buffers --- src/vulkan_renderer.zig | 118 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index f9bc3a4..593aec5 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -29,6 +29,7 @@ const DeviceDispatch = vk.DeviceWrapper(apis); const Instance = vk.InstanceProxy(apis); const Device = vk.DeviceProxy(apis); const Queue = vk.QueueProxy(apis); +const CommandBuffer = vk.CommandBufferProxy(apis); pub const VulkanRenderer = struct { const Self = @This(); @@ -47,13 +48,19 @@ pub const VulkanRenderer = struct { presentation_queue: Queue, surface: vk.SurfaceKHR, swapchain: vk.SwapchainKHR, + swapchain_images: []SwapchainImage, + swapchain_framebuffers: []vk.Framebuffer, + command_buffers: []CommandBuffer, // Pipeline graphics_pipeline: vk.Pipeline, pipeline_layout: vk.PipelineLayout, render_pass: vk.RenderPass, + // Pools + graphics_command_pool: vk.CommandPool, + // Utilities swapchain_image_format: vk.Format, extent: vk.Extent2D, @@ -79,6 +86,9 @@ pub const VulkanRenderer = struct { try self.createSwapchain(); try self.createRenderPass(); try self.createGraphicsPipeline(); + try self.createFramebuffers(); + try self.createCommandPool(); + try self.createCommandBuffers(); return self; } @@ -487,6 +497,105 @@ pub const VulkanRenderer = struct { ); } + fn createFramebuffers(self: *Self) !void { + self.swapchain_framebuffers = try self.allocator.alloc(vk.Framebuffer, self.swapchain_images.len); + + // Create a frammebuffer for each swapchain image + for (self.swapchain_images, 0..) |swapchain_image, i| { + const attachments = [_]vk.ImageView{swapchain_image.image_view}; + + const framebuffer_create_info: vk.FramebufferCreateInfo = .{ + .render_pass = self.render_pass, // Render pass layout the frambuffer will be used with + .attachment_count = @intCast(attachments.len), + .p_attachments = &attachments, // List of attachments (1:1 with render pass) + .width = self.extent.width, // Framebuffer width + .height = self.extent.height, // Framebuffer height + .layers = 1, // Framebuffer layers + }; + + self.swapchain_framebuffers[i] = try self.device.createFramebuffer(&framebuffer_create_info, null); + } + } + + fn createCommandPool(self: *Self) !void { + // Get indices of queue families from device + const queue_family_indices = try self.getQueueFamilies(self.physical_device); + + const pool_create_info: vk.CommandPoolCreateInfo = .{ + // Queue family type that buffers from this command pool will use + .queue_family_index = queue_family_indices.graphics_family.?, + }; + + // Create a graphics queue family command pool + self.graphics_command_pool = try self.device.createCommandPool(&pool_create_info, null); + } + + fn createCommandBuffers(self: *Self) !void { + // Allocate one command buffer for each framebuffer + const command_buffer_handles = try self.allocator.alloc(vk.CommandBuffer, self.swapchain_framebuffers.len); + defer self.allocator.free(command_buffer_handles); + self.command_buffers = try self.allocator.alloc(CommandBuffer, command_buffer_handles.len); + + const command_buffer_allocate_info: vk.CommandBufferAllocateInfo = .{ + .command_pool = self.graphics_command_pool, + .level = .primary, // primary: buffer you submit directly to queue. Can't be called by other buffers + .command_buffer_count = @intCast(command_buffer_handles.len), + }; + + // Allocate command buffers and place handles in array of buffers + try self.device.allocateCommandBuffers(&command_buffer_allocate_info, command_buffer_handles.ptr); + for (command_buffer_handles, 0..) |command_buffer_handle, i| { + self.command_buffers[i] = CommandBuffer.init(command_buffer_handle, self.device.wrapper); + } + } + + fn recordCommands(self: *Self) !void { + // Information about how to begin each command + const buffer_begin_info: vk.CommandBufferBeginInfo = .{ + // Buffer can be resubmitted when it has already been submitted and is awaiting execution + .flags = .{ .simultaneous_use_bit = true }, + }; + + const clear_values = [_]vk.ClearValue{ + .{ .color = .{ .float_32 = [4]f32{ 0.6, 0.65, 0.4, 1.0 } } }, + }; + + // Information about how to begin a render pass (only needed for graphical application) + var render_pass_begin_info: vk.RenderPassBeginInfo = .{ + .render_pass = self.render_pass, // Render pass to begin + .render_area = .{ + .offset = .{ .x = 0, .y = 0 }, // Start point of render pass in pixels + .extent = self.extent, // Size of region to run render pass on (starting at offset) + }, + .p_clear_values = &clear_values, // List of clear values (TODO: Depth attachment clear value) + .clear_value_count = 1, + }; + + for (self.command_buffers, 0..) |command_buffer, i| { + render_pass_begin_info.framebuffer = self.swapchain_framebuffers[i]; + + // Start recording commands to command buffer + try command_buffer.beginCommandBuffer(&buffer_begin_info); + + { + // Begin render pass + command_buffer.beginRenderPass(&render_pass_begin_info, vk.SubpassContents.@"inline"); + + // Bind pipeline to be used in render pass + command_buffer.bindPipeline(.graphics, self.graphics_pipeline); + + // Execute a pipeline + command_buffer.draw(3, 1, 0, 0); + + // End render pass + command_buffer.endRenderPass(); + } + + // Stop recording to command buffer + try command_buffer.endCommandBuffer(); + } + } + fn getPhysicalDevice(self: *Self) !void { var pdev_count: u32 = 0; _ = try self.instance.enumeratePhysicalDevices(&pdev_count, null); @@ -703,6 +812,15 @@ pub const VulkanRenderer = struct { 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);