From 27689b8cda14b8e078839ba7e6bcedd61e7d41ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Gasi=C7=B9ski?= Date: Sun, 1 Sep 2024 17:36:22 +0200 Subject: [PATCH] WIP: Subpasses --- build.zig | 5 +- build.zig.zon | 4 +- src/shaders/second.frag | 13 ++ src/shaders/second.vert | 12 ++ src/vulkan_renderer.zig | 390 +++++++++++++++++++++++++++++++++++----- 5 files changed, 373 insertions(+), 51 deletions(-) create mode 100644 src/shaders/second.frag create mode 100644 src/shaders/second.vert diff --git a/build.zig b/build.zig index 0a72756..4ebc93a 100644 --- a/build.zig +++ b/build.zig @@ -28,11 +28,14 @@ pub fn build(b: *std.Build) void { const shader_comp = vkgen.ShaderCompileStep.create( b, - &[_][]const u8{ "glslc", "--target-env=vulkan1.3" }, + .{ .real_path = "glslc" }, + &[_][]const u8{"--target-env=vulkan1.3"}, "-o", ); shader_comp.add("shader_frag", "src/shaders/shader.frag", .{}); shader_comp.add("shader_vert", "src/shaders/shader.vert", .{}); + shader_comp.add("shader_frag", "src/shaders/second.frag", .{}); + shader_comp.add("shader_vert", "src/shaders/second.vert", .{}); exe.root_module.addImport("shaders", shader_comp.getModule()); // SDL2 diff --git a/build.zig.zon b/build.zig.zon index bf20cb5..ea4a2ff 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -7,8 +7,8 @@ .zmath = .{ .path = "libs/zmath" }, .zstbi = .{ .path = "libs/zstbi" }, .vulkan_zig = .{ - .url = "https://github.com/Snektron/vulkan-zig/archive/9f6e6177b1fdb3ed22231d9216a24480e84cfa5e.tar.gz", - .hash = "1220f2961df224f7d35dee774b26194b8b937cc252fa8e4023407776c58521d53e38", + .url = "https://github.com/Snektron/vulkan-zig/archive/18f38ef2b7ae394734bd8b28d43f120f2b9567c1.tar.gz", + .hash = "1220530d62adb3f7ab87bacde31c302955a5803db52e302a0c7f8e107ca03f7aeca5", }, .obj = .{ .url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz", diff --git a/src/shaders/second.frag b/src/shaders/second.frag new file mode 100644 index 0000000..49c4100 --- /dev/null +++ b/src/shaders/second.frag @@ -0,0 +1,13 @@ +#version 450 + +// Colour output from subpass 1 +layout(input_attachment_index = 0, binding = 0) uniform subpassInput inputColour; + +// Depth output from subpass 1 +layout(input_attachment_index = 1, binding = 1) uniform subpassInput inputDepth; + +layout(location = 0) out vec4 colour; + +void main() { + colour = subpassLoad(inputColour).rgba; +} diff --git a/src/shaders/second.vert b/src/shaders/second.vert new file mode 100644 index 0000000..2f30881 --- /dev/null +++ b/src/shaders/second.vert @@ -0,0 +1,12 @@ +#version 450 + +// Array for triangle that fills screen +vec2 positions[3] = vec2[]( + vec2(3.0, -1.0), + vec2(-1.0, -1.0), + vec2(-1.0, 3.0), +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); +} diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index f58728a..6409fd4 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -82,19 +82,26 @@ pub const VulkanRenderer = struct { swapchain_framebuffers: []vk.Framebuffer, command_buffers: []CommandBuffer, - depth_buffer_image: vk.Image, - depth_buffer_image_memory: vk.DeviceMemory, - depth_buffer_image_view: vk.ImageView, + depth_buffer_image: []vk.Image, + depth_buffer_image_memory: []vk.DeviceMemory, + depth_buffer_image_view: []vk.ImageView, + + colour_buffer_image: []vk.Image, + colour_buffer_image_memory: []vk.DeviceMemory, + colour_buffer_image_view: []vk.ImageView, // Descriptors descriptor_set_layout: vk.DescriptorSetLayout, sampler_set_layout: vk.DescriptorSetLayout, + input_set_layout: vk.DescriptorSetLayout, push_constant_range: vk.PushConstantRange, descriptor_pool: vk.DescriptorPool, sampler_descriptor_pool: vk.DescriptorPool, + input_descriptor_pool: vk.DescriptorPool, descriptor_sets: []vk.DescriptorSet, sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet), + input_descriptor_sets: std.ArrayList(vk.DescriptorSet), vp_uniform_buffer: []vk.Buffer, vp_uniform_buffer_memory: []vk.DeviceMemory, @@ -109,6 +116,10 @@ pub const VulkanRenderer = struct { // Pipeline graphics_pipeline: vk.Pipeline, pipeline_layout: vk.PipelineLayout, + + second_pipeline: vk.Pipeline, + second_pipeline_layout: vk.PipelineLayout, + render_pass: vk.RenderPass, // Pools @@ -146,6 +157,7 @@ pub const VulkanRenderer = struct { try self.getPhysicalDevice(); try self.createLogicalDevice(); try self.createSwapchain(); + try self.createColourBufferImage(); try self.createDepthBufferImage(); try self.createRenderPass(); try self.createDescriptorSetLayout(); @@ -154,12 +166,15 @@ pub const VulkanRenderer = struct { try self.createFramebuffers(); try self.createCommandPool(); + self.sampler_descriptor_sets = try std.ArrayList(vk.DescriptorSet).initCapacity(self.allocator, self.swapchain_images.len); + self.input_descriptor_sets = try std.ArrayList(vk.DescriptorSet).initCapacity(self.allocator, self.swapchain_images.len); + try self.createCommandBuffers(); try self.createTextureSampler(); try self.createUniformBuffers(); try self.createDescriptorPool(); try self.createDescriptorSets(); - + try self.createInputDescriptorSets(); try self.createSynchronisation(); self.image_files = std.ArrayList(img.Image).init(self.allocator); @@ -167,7 +182,6 @@ pub const VulkanRenderer = struct { self.texture_image_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator); self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator); self.model_list = std.ArrayList(MeshModel).init(allocator); - self.sampler_descriptor_sets = std.ArrayList(vk.DescriptorSet).init(self.allocator); const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height)); self.ubo_view_projection.projection = zm.perspectiveFovRh( @@ -289,14 +303,32 @@ pub const VulkanRenderer = struct { self.texture_image_memory.deinit(); self.texture_image_views.deinit(); - self.device.destroyImageView(self.depth_buffer_image_view, null); - self.device.destroyImage(self.depth_buffer_image, null); - self.device.freeMemory(self.depth_buffer_image_memory, null); + for (0..self.depth_buffer_image.len) |i| { + self.device.destroyImageView(self.depth_buffer_image_view[i], null); + self.device.destroyImage(self.depth_buffer_image[i], null); + self.device.freeMemory(self.depth_buffer_image_memory[i], null); + } + self.allocator.free(self.depth_buffer_image); + self.allocator.free(self.depth_buffer_image_memory); + self.allocator.free(self.depth_buffer_image_view); + + for (0..self.colour_buffer_image.len) |i| { + self.device.destroyImageView(self.colour_buffer_image_view[i], null); + self.device.destroyImage(self.colour_buffer_image[i], null); + self.device.freeMemory(self.colour_buffer_image_memory[i], null); + } + + self.allocator.free(self.colour_buffer_image); + self.allocator.free(self.colour_buffer_image_memory); + self.allocator.free(self.colour_buffer_image_view); + + self.device.destroyDescriptorPool(self.input_descriptor_pool, null); self.device.destroyDescriptorPool(self.descriptor_pool, null); self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null); self.device.destroyDescriptorPool(self.sampler_descriptor_pool, null); self.device.destroyDescriptorSetLayout(self.sampler_set_layout, null); + self.device.destroyDescriptorSetLayout(self.input_set_layout, null); self.sampler_descriptor_sets.deinit(); for (0..self.swapchain_images.len) |i| { @@ -523,8 +555,65 @@ pub const VulkanRenderer = struct { fn createRenderPass(self: *Self) !void { // -- Attachments -- - // Colour attachment of the render pass + + const subpasses: [2]vk.SubpassDescription = undefined; + + // Subpass 1 attachments and references (input attachments) + + // Colour attachment (input) + const colour_format = chooseSupportedFormat( + self.physical_device, + self.instance, + &[_]vk.Format{.r8g8b8a8_srgb}, + .optimal, + .{ .color_attachment_bit = true }, + ); const colour_attachment: vk.AttachmentDescription = .{ + .format = colour_format, + .samples = .{ .@"1_bit" = true }, + .load_op = .clear, + .store_op = .dont_care, + .stencil_load_op = .dont_care, + .stencil_store_op = .dont_care, + .initial_layout = .undefined, + .final_layout = .color_attachment_optimal, + }; + + // Depth attachment (input) + const depth_attachment: vk.AttachmentDescription = .{ + .format = self.depth_format, + .samples = .{ .@"1_bit" = true }, + .load_op = .clear, + .store_op = .dont_care, + .stencil_load_op = .dont_care, + .stencil_store_op = .dont_care, + .initial_layout = .undefined, + .final_layout = .depth_stencil_attachment_optimal, + }; + + // Colour attachment (input) reference + const colour_attachment_reference: vk.AttachmentReference = .{ + .attachment = 1, + .layout = .color_attachment_optimal, + }; + + // Depth attachment (input) reference + const depth_attachment_reference: vk.AttachmentReference = .{ + .attachment = 2, + .layout = .depth_stencil_attachment_optimal, + }; + + subpasses[0] = .{ + .pipeline_bind_point = .graphics, // Pipeline type subpass is to be bound to + .color_attachment_count = 1, + .p_color_attachments = @ptrCast(&colour_attachment_reference), + .p_depth_stencil_attachment = &depth_attachment_reference, + }; + + // Subpass 2 attachments and references + + // Colour attachment of the render pass + const swapchain_colour_attachment: vk.AttachmentDescription = .{ .format = self.swapchain_image_format, // Format to use for attachment .samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling .load_op = .clear, // Describes what to do with attachment before rendering @@ -537,40 +626,36 @@ pub const VulkanRenderer = struct { .final_layout = vk.ImageLayout.present_src_khr, // Image data layout after render pass (to change to) }; - // Depth attachment of render pass - const depth_attachment: vk.AttachmentDescription = .{ - .format = self.depth_format, - .samples = .{ .@"1_bit" = true }, - .load_op = .clear, - .store_op = .dont_care, - .stencil_load_op = .dont_care, - .stencil_store_op = .dont_care, - .initial_layout = .undefined, - .final_layout = .depth_stencil_attachment_optimal, - }; - - // -- References -- // Attachment reference uses an attachment index that refers to index in the attachment list passed to render pass create info - const colour_attachment_reference: vk.AttachmentReference = .{ + const swapchain_colour_attachment_reference: vk.AttachmentReference = .{ .attachment = 0, .layout = vk.ImageLayout.color_attachment_optimal, }; - const depth_attachment_reference: vk.AttachmentReference = .{ - .attachment = 1, - .layout = vk.ImageLayout.depth_stencil_attachment_optimal, + // References to attachments that subpass will take input from + const input_references = [_]vk.AttachmentReference{ + .{ + .attachment = 1, // Colour attachment + .layout = .shader_read_only_optimal, + }, + .{ + .attachment = 2, // Depth attachment + .layout = .shader_read_only_optimal, + }, }; - // Information about a particular subpass the render pass is using - const subpass: vk.SubpassDescription = .{ - .pipeline_bind_point = .graphics, // Pipeline type subpass is to be bound to + subpasses[1] = .{ + .pipeline_bind_point = .graphics, .color_attachment_count = 1, - .p_color_attachments = @ptrCast(&colour_attachment_reference), - .p_depth_stencil_attachment = &depth_attachment_reference, + .p_color_attachments = @ptrCast(&swapchain_colour_attachment_reference), + .input_attachment_count = @intCast(input_references.len), + .p_input_attachments = &input_references, }; + // -- Subpass dependencies + // Need to determine when layout transitions occur using subpass dependencies - const subpass_dependencies = [2]vk.SubpassDependency{ + const subpass_dependencies = [_]vk.SubpassDependency{ // Conversion from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL vk.SubpassDependency{ // Transition must happen after... @@ -582,6 +667,15 @@ pub const VulkanRenderer = struct { .dst_stage_mask = .{ .color_attachment_output_bit = true }, .dst_access_mask = .{ .color_attachment_read_bit = true, .color_attachment_write_bit = true }, }, + // Subpass 1 layout (colour/depth) to subpass 2 layout (shader read) + .{ + .src_subpass = 0, + .src_stage_mask = .{ .color_attachment_output_bit = true }, + .src_access_mask = .{ .color_attachment_write_bit = true }, + .dst_subpass = 1, + .dst_stage_mask = .{ .fragment_shader_bit = true }, + .dst_access_mask = .{ .shader_read_bit = true }, + }, // Conversion from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR vk.SubpassDependency{ // Transition must happen after... @@ -596,13 +690,13 @@ pub const VulkanRenderer = struct { }; // Order matters - const render_pass_attachments = [_]vk.AttachmentDescription{ colour_attachment, depth_attachment }; + const render_pass_attachments = [_]vk.AttachmentDescription{ swapchain_colour_attachment, colour_attachment, depth_attachment }; const render_pass_create_info: vk.RenderPassCreateInfo = .{ .attachment_count = @intCast(render_pass_attachments.len), .p_attachments = &render_pass_attachments, - .subpass_count = 1, - .p_subpasses = @ptrCast(&subpass), + .subpass_count = @intCast(subpasses.len), + .p_subpasses = &subpasses, .dependency_count = @intCast(subpass_dependencies.len), .p_dependencies = &subpass_dependencies, }; @@ -651,6 +745,34 @@ pub const VulkanRenderer = struct { }; self.sampler_set_layout = try self.device.createDescriptorSetLayout(&texture_layout_info, null); + + // -- Create input attachment image descriptor set layout + // Colour input binding + const colour_input_layout_binding: vk.DescriptorSetLayoutBinding = .{ + .binding = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .stage_flags = .{ .fragment_bit = true }, + }; + + // Depth input binding + const depth_input_layout_binding: vk.DescriptorSetLayoutBinding = .{ + .binding = 1, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .stage_flags = .{ .fragment_bit = true }, + }; + + // Array of input attachment bindings + const input_bindings = [_]vk.DescriptorSetLayoutBinding{ colour_input_layout_binding, depth_input_layout_binding }; + + // Create a descriptor set layout for input attachments + const input_layout_create_info: vk.DescriptorSetLayoutCreateInfo = .{ + .binding_count = @intCast(input_bindings.len), + .p_bindings = &input_bindings, + }; + + self.input_set_layout = try self.device.createDescriptorSetLayout(&input_layout_create_info, null); } fn createPushConstantRange(self: *Self) !void { @@ -662,7 +784,45 @@ pub const VulkanRenderer = struct { }; } + fn createColourBufferImage(self: *Self) !void { + self.colour_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain_images.len); + self.colour_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len); + self.colour_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain_images.len); + + // Get supported format for colour attachment + const colour_format = chooseSupportedFormat( + self.physical_device, + self.instance, + &[_]vk.Format{.r8g8b8a8_srgb}, + .optimal, + .{ .color_attachment_bit = true }, + ) orelse return error.FormatNotSupported; + + // Create colour buffers + for (0..self.colour_buffer_image.len) |i| { + self.colour_buffer_image[i] = try self.createImage( + self.extent.width, + self.extent.height, + colour_format, + .optimal, + .{ .color_attachment_bit = true, .input_attachment_bit = true }, + .{ .device_local_bit = true }, + &self.colour_buffer_image_memory[i], + ); + + self.colour_buffer_image_view[i] = try self.createImageView( + self.colour_buffer_image[i], + colour_format, + .{ .color_bit = true }, + ); + } + } + fn createDepthBufferImage(self: *Self) !void { + self.depth_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain_images.len); + self.depth_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len); + self.depth_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain_images.len); + // Get supported depth buffer format const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint }; self.depth_format = chooseSupportedFormat( @@ -673,19 +833,21 @@ pub const VulkanRenderer = struct { .{ .depth_stencil_attachment_bit = true }, ) orelse return error.UnsupportedDepthBufferFormat; - // Create depth buffer image - self.depth_buffer_image = try self.createImage( - self.extent.width, - self.extent.height, - self.depth_format, - .optimal, - .{ .depth_stencil_attachment_bit = true }, - .{ .device_local_bit = true }, - &self.depth_buffer_image_memory, - ); + for (0..self.depth_buffer_image.len) |i| { + // Create depth buffer image + self.depth_buffer_image[i] = try self.createImage( + self.extent.width, + self.extent.height, + self.depth_format, + .optimal, + .{ .depth_stencil_attachment_bit = true }, + .{ .device_local_bit = true }, + &self.depth_buffer_image_memory[i], + ); - // Create depth buffer image view - self.depth_buffer_image_view = try self.createImageView(self.depth_buffer_image, self.depth_format, .{ .depth_bit = true }); + // Create depth buffer image view + self.depth_buffer_image_view[i] = try self.createImageView(self.depth_buffer_image[i], self.depth_format, .{ .depth_bit = true }); + } } fn createGraphicsPipeline(self: *Self) !void { @@ -903,6 +1065,48 @@ pub const VulkanRenderer = struct { null, @ptrCast(&self.graphics_pipeline), ); + + // -- Create second pass pipeline + // Second pass shaders + const second_vert_shader_module = try self.device.createShaderModule(&.{ + .code_size = shaders.second_vert.len, + .p_code = @ptrCast(&shaders.shader_vert), + }, null); + defer self.device.destroyShaderModule(second_vert_shader_module, null); + + const second_frag_shader_module = try self.device.createShaderModule(&.{ + .code_size = shaders.second_frag.len, + .p_code = @ptrCast(&shaders.shader_frag), + }, null); + defer self.device.destroyShaderModule(second_frag_shader_module, null); + + // Set new shaders + vertex_shader_create_info.module = second_vert_shader_module; + fragment_shader_create_info.module = second_frag_shader_module; + + const second_shader_stages = []vk.PipelineShaderStageCreateInfo{ vertex_shader_create_info, fragment_shader_create_info }; + + // No vertex data for second pass + vertex_input_create_info.vertex_binding_description_count = 0; + vertex_input_create_info.p_vertex_binding_descriptions = null; + vertex_input_create_info.vertex_attribute_description_count = 0; + vertex_input_create_info.p_vertex_attribute_descriptions = null; + + // Don't want to write to depth buffer + depth_stencil_create_info.depth_write_enable = vk.FALSE; + + // Create new pipeline layout + const second_pipeline_layout_create_info: vk.PipelineLayoutCreateInfo = .{ + .set_layout_count = 1, + .p_set_layouts = @ptrCast(self.input_set_layout), + }; + + self.second_pipeline_layout = try self.device.createPipelineLayout(&second_pipeline_layout_create_info, null); + + pipeline_create_info.stage_count = @intCast(second_shader_stages.len); + pipeline_create_info.p_stages = &second_shader_stages; + pipeline_create_info.layout = self.second_pipeline_layout; + pipeline_create_info.subpass = 1; } fn createFramebuffers(self: *Self) !void { @@ -911,7 +1115,11 @@ pub const VulkanRenderer = struct { // Create a frammebuffer for each swapchain image for (self.swapchain_images, 0..) |swapchain_image, i| { // Order matters - const attachments = [_]vk.ImageView{ swapchain_image.image_view, self.depth_buffer_image_view }; + const attachments = [_]vk.ImageView{ + swapchain_image.image_view, + self.colour_buffer_image_view[i], + self.depth_buffer_image_view[i], + }; const framebuffer_create_info: vk.FramebufferCreateInfo = .{ .render_pass = self.render_pass, // Render pass layout the frambuffer will be used with @@ -1056,6 +1264,30 @@ pub const VulkanRenderer = struct { }; self.sampler_descriptor_pool = try self.device.createDescriptorPool(&sampler_pool_create_info, null); + + // -- Create input attachment descriptor pool + // Colour attachment pool size + const colour_input_pool_size: vk.DescriptorPoolSize = .{ + .type = .input_attachment, + .descriptor_count = @intCast(self.colour_buffer_image_view.len), + }; + + // Depth attachment pool size + const depth_input_pool_size: vk.DescriptorPoolSize = .{ + .type = .input_attachment, + .descriptor_count = @intCast(self.depth_buffer_image_view.len), + }; + + const input_pool_sizes = [_]vk.DescriptorPoolSize{ colour_input_pool_size, depth_input_pool_size }; + + // Create input attachment pool + const input_pool_create_info: vk.DescriptorPoolCreateInfo = .{ + .max_sets = self.swapchain_images.len, + .pool_size_count = @intCast(input_pool_sizes.len), + .p_pool_sizes = &input_pool_sizes, + }; + + self.input_descriptor_pool = try self.device.createDescriptorPool(&input_pool_create_info, null); } fn createDescriptorSets(self: *Self) !void { @@ -1108,6 +1340,68 @@ pub const VulkanRenderer = struct { } } + fn createInputDescriptorSets(self: *Self) !void { + // Fill array of layouts ready for set creation + var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain_images.len); + defer self.allocator.free(set_layouts); + for (0..set_layouts.len) |i| { + set_layouts[i] = self.input_set_layout; + } + + // Input attachment descriptor set allocation info + const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ + .descriptor_pool = self.input_descriptor_pool, + .descriptor_set_count = @intCast(self.swapchain_images.len), + .p_set_layouts = &set_layouts, + }; + + // Allocate descriptor sets + try self.device.allocateDescriptorSets(&set_alloc_info, self.input_descriptor_sets.items.ptr); + + // Update each descriptor set with input attachment + for (0..self.swapchain_images.len) |i| { + // Colour attachment descriptor + const colour_attachment_descriptor: vk.DescriptorImageInfo = .{ + .image_layout = .read_only_optimal, + .image_view = self.colour_buffer_image_view[i], + .sampler = .null_handle, + }; + + // Colour attachment descriptor write + const colour_write: vk.WriteDescriptorSet = .{ + .dst_set = self.input_descriptor_sets.items[i], + .dst_binding = 0, + .dst_array_element = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .p_image_info = @ptrCast(&colour_attachment_descriptor), + }; + + // Depth attachment descriptor + const depth_attachment_descriptor: vk.DescriptorImageInfo = .{ + .image_layout = .read_only_optimal, + .image_view = self.depth_buffer_image_view[i], + .sampler = .null_handle, + }; + + // Depth attachment descriptor write + const depth_write: vk.WriteDescriptorSet = .{ + .dst_set = self.input_descriptor_sets.items[i], + .dst_binding = 1, + .dst_array_element = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .p_image_info = @ptrCast(&depth_attachment_descriptor), + }; + + // List of input descriptor set writes + const set_writes = [_]vk.WriteDescriptorSet{ colour_write, depth_write }; + + // Update descriptor sets + self.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null); + } + } + fn updateUniformBuffers(self: *Self, image_index: u32) !void { // Copy VP data const data = try self.device.mapMemory(