WIP: Subpasses
This commit is contained in:
parent
56ec32fcf2
commit
27689b8cda
5 changed files with 373 additions and 51 deletions
|
@ -28,11 +28,14 @@ pub fn build(b: *std.Build) void {
|
||||||
|
|
||||||
const shader_comp = vkgen.ShaderCompileStep.create(
|
const shader_comp = vkgen.ShaderCompileStep.create(
|
||||||
b,
|
b,
|
||||||
&[_][]const u8{ "glslc", "--target-env=vulkan1.3" },
|
.{ .real_path = "glslc" },
|
||||||
|
&[_][]const u8{"--target-env=vulkan1.3"},
|
||||||
"-o",
|
"-o",
|
||||||
);
|
);
|
||||||
shader_comp.add("shader_frag", "src/shaders/shader.frag", .{});
|
shader_comp.add("shader_frag", "src/shaders/shader.frag", .{});
|
||||||
shader_comp.add("shader_vert", "src/shaders/shader.vert", .{});
|
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());
|
exe.root_module.addImport("shaders", shader_comp.getModule());
|
||||||
|
|
||||||
// SDL2
|
// SDL2
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
.zmath = .{ .path = "libs/zmath" },
|
.zmath = .{ .path = "libs/zmath" },
|
||||||
.zstbi = .{ .path = "libs/zstbi" },
|
.zstbi = .{ .path = "libs/zstbi" },
|
||||||
.vulkan_zig = .{
|
.vulkan_zig = .{
|
||||||
.url = "https://github.com/Snektron/vulkan-zig/archive/9f6e6177b1fdb3ed22231d9216a24480e84cfa5e.tar.gz",
|
.url = "https://github.com/Snektron/vulkan-zig/archive/18f38ef2b7ae394734bd8b28d43f120f2b9567c1.tar.gz",
|
||||||
.hash = "1220f2961df224f7d35dee774b26194b8b937cc252fa8e4023407776c58521d53e38",
|
.hash = "1220530d62adb3f7ab87bacde31c302955a5803db52e302a0c7f8e107ca03f7aeca5",
|
||||||
},
|
},
|
||||||
.obj = .{
|
.obj = .{
|
||||||
.url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz",
|
.url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz",
|
||||||
|
|
13
src/shaders/second.frag
Normal file
13
src/shaders/second.frag
Normal file
|
@ -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;
|
||||||
|
}
|
12
src/shaders/second.vert
Normal file
12
src/shaders/second.vert
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -82,19 +82,26 @@ pub const VulkanRenderer = struct {
|
||||||
swapchain_framebuffers: []vk.Framebuffer,
|
swapchain_framebuffers: []vk.Framebuffer,
|
||||||
command_buffers: []CommandBuffer,
|
command_buffers: []CommandBuffer,
|
||||||
|
|
||||||
depth_buffer_image: vk.Image,
|
depth_buffer_image: []vk.Image,
|
||||||
depth_buffer_image_memory: vk.DeviceMemory,
|
depth_buffer_image_memory: []vk.DeviceMemory,
|
||||||
depth_buffer_image_view: vk.ImageView,
|
depth_buffer_image_view: []vk.ImageView,
|
||||||
|
|
||||||
|
colour_buffer_image: []vk.Image,
|
||||||
|
colour_buffer_image_memory: []vk.DeviceMemory,
|
||||||
|
colour_buffer_image_view: []vk.ImageView,
|
||||||
|
|
||||||
// Descriptors
|
// Descriptors
|
||||||
descriptor_set_layout: vk.DescriptorSetLayout,
|
descriptor_set_layout: vk.DescriptorSetLayout,
|
||||||
sampler_set_layout: vk.DescriptorSetLayout,
|
sampler_set_layout: vk.DescriptorSetLayout,
|
||||||
|
input_set_layout: vk.DescriptorSetLayout,
|
||||||
push_constant_range: vk.PushConstantRange,
|
push_constant_range: vk.PushConstantRange,
|
||||||
|
|
||||||
descriptor_pool: vk.DescriptorPool,
|
descriptor_pool: vk.DescriptorPool,
|
||||||
sampler_descriptor_pool: vk.DescriptorPool,
|
sampler_descriptor_pool: vk.DescriptorPool,
|
||||||
|
input_descriptor_pool: vk.DescriptorPool,
|
||||||
descriptor_sets: []vk.DescriptorSet,
|
descriptor_sets: []vk.DescriptorSet,
|
||||||
sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet),
|
sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet),
|
||||||
|
input_descriptor_sets: std.ArrayList(vk.DescriptorSet),
|
||||||
|
|
||||||
vp_uniform_buffer: []vk.Buffer,
|
vp_uniform_buffer: []vk.Buffer,
|
||||||
vp_uniform_buffer_memory: []vk.DeviceMemory,
|
vp_uniform_buffer_memory: []vk.DeviceMemory,
|
||||||
|
@ -109,6 +116,10 @@ pub const VulkanRenderer = struct {
|
||||||
// Pipeline
|
// Pipeline
|
||||||
graphics_pipeline: vk.Pipeline,
|
graphics_pipeline: vk.Pipeline,
|
||||||
pipeline_layout: vk.PipelineLayout,
|
pipeline_layout: vk.PipelineLayout,
|
||||||
|
|
||||||
|
second_pipeline: vk.Pipeline,
|
||||||
|
second_pipeline_layout: vk.PipelineLayout,
|
||||||
|
|
||||||
render_pass: vk.RenderPass,
|
render_pass: vk.RenderPass,
|
||||||
|
|
||||||
// Pools
|
// Pools
|
||||||
|
@ -146,6 +157,7 @@ pub const VulkanRenderer = struct {
|
||||||
try self.getPhysicalDevice();
|
try self.getPhysicalDevice();
|
||||||
try self.createLogicalDevice();
|
try self.createLogicalDevice();
|
||||||
try self.createSwapchain();
|
try self.createSwapchain();
|
||||||
|
try self.createColourBufferImage();
|
||||||
try self.createDepthBufferImage();
|
try self.createDepthBufferImage();
|
||||||
try self.createRenderPass();
|
try self.createRenderPass();
|
||||||
try self.createDescriptorSetLayout();
|
try self.createDescriptorSetLayout();
|
||||||
|
@ -154,12 +166,15 @@ pub const VulkanRenderer = struct {
|
||||||
try self.createFramebuffers();
|
try self.createFramebuffers();
|
||||||
try self.createCommandPool();
|
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.createCommandBuffers();
|
||||||
try self.createTextureSampler();
|
try self.createTextureSampler();
|
||||||
try self.createUniformBuffers();
|
try self.createUniformBuffers();
|
||||||
try self.createDescriptorPool();
|
try self.createDescriptorPool();
|
||||||
try self.createDescriptorSets();
|
try self.createDescriptorSets();
|
||||||
|
try self.createInputDescriptorSets();
|
||||||
try self.createSynchronisation();
|
try self.createSynchronisation();
|
||||||
|
|
||||||
self.image_files = std.ArrayList(img.Image).init(self.allocator);
|
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_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator);
|
||||||
self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator);
|
self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator);
|
||||||
self.model_list = std.ArrayList(MeshModel).init(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));
|
const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height));
|
||||||
self.ubo_view_projection.projection = zm.perspectiveFovRh(
|
self.ubo_view_projection.projection = zm.perspectiveFovRh(
|
||||||
|
@ -289,14 +303,32 @@ pub const VulkanRenderer = struct {
|
||||||
self.texture_image_memory.deinit();
|
self.texture_image_memory.deinit();
|
||||||
self.texture_image_views.deinit();
|
self.texture_image_views.deinit();
|
||||||
|
|
||||||
self.device.destroyImageView(self.depth_buffer_image_view, null);
|
for (0..self.depth_buffer_image.len) |i| {
|
||||||
self.device.destroyImage(self.depth_buffer_image, null);
|
self.device.destroyImageView(self.depth_buffer_image_view[i], null);
|
||||||
self.device.freeMemory(self.depth_buffer_image_memory, 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.destroyDescriptorPool(self.descriptor_pool, null);
|
||||||
self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
|
self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
|
||||||
self.device.destroyDescriptorPool(self.sampler_descriptor_pool, null);
|
self.device.destroyDescriptorPool(self.sampler_descriptor_pool, null);
|
||||||
self.device.destroyDescriptorSetLayout(self.sampler_set_layout, null);
|
self.device.destroyDescriptorSetLayout(self.sampler_set_layout, null);
|
||||||
|
self.device.destroyDescriptorSetLayout(self.input_set_layout, null);
|
||||||
self.sampler_descriptor_sets.deinit();
|
self.sampler_descriptor_sets.deinit();
|
||||||
|
|
||||||
for (0..self.swapchain_images.len) |i| {
|
for (0..self.swapchain_images.len) |i| {
|
||||||
|
@ -523,8 +555,65 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
fn createRenderPass(self: *Self) !void {
|
fn createRenderPass(self: *Self) !void {
|
||||||
// -- Attachments --
|
// -- 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 = .{
|
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
|
.format = self.swapchain_image_format, // Format to use for attachment
|
||||||
.samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling
|
.samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling
|
||||||
.load_op = .clear, // Describes what to do with attachment before rendering
|
.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)
|
.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
|
// 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,
|
.attachment = 0,
|
||||||
.layout = vk.ImageLayout.color_attachment_optimal,
|
.layout = vk.ImageLayout.color_attachment_optimal,
|
||||||
};
|
};
|
||||||
|
|
||||||
const depth_attachment_reference: vk.AttachmentReference = .{
|
// References to attachments that subpass will take input from
|
||||||
.attachment = 1,
|
const input_references = [_]vk.AttachmentReference{
|
||||||
.layout = vk.ImageLayout.depth_stencil_attachment_optimal,
|
.{
|
||||||
|
.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
|
subpasses[1] = .{
|
||||||
const subpass: vk.SubpassDescription = .{
|
.pipeline_bind_point = .graphics,
|
||||||
.pipeline_bind_point = .graphics, // Pipeline type subpass is to be bound to
|
|
||||||
.color_attachment_count = 1,
|
.color_attachment_count = 1,
|
||||||
.p_color_attachments = @ptrCast(&colour_attachment_reference),
|
.p_color_attachments = @ptrCast(&swapchain_colour_attachment_reference),
|
||||||
.p_depth_stencil_attachment = &depth_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
|
// 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
|
// Conversion from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||||
vk.SubpassDependency{
|
vk.SubpassDependency{
|
||||||
// Transition must happen after...
|
// Transition must happen after...
|
||||||
|
@ -582,6 +667,15 @@ pub const VulkanRenderer = struct {
|
||||||
.dst_stage_mask = .{ .color_attachment_output_bit = true },
|
.dst_stage_mask = .{ .color_attachment_output_bit = true },
|
||||||
.dst_access_mask = .{ .color_attachment_read_bit = true, .color_attachment_write_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
|
// Conversion from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||||
vk.SubpassDependency{
|
vk.SubpassDependency{
|
||||||
// Transition must happen after...
|
// Transition must happen after...
|
||||||
|
@ -596,13 +690,13 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Order matters
|
// 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 = .{
|
const render_pass_create_info: vk.RenderPassCreateInfo = .{
|
||||||
.attachment_count = @intCast(render_pass_attachments.len),
|
.attachment_count = @intCast(render_pass_attachments.len),
|
||||||
.p_attachments = &render_pass_attachments,
|
.p_attachments = &render_pass_attachments,
|
||||||
.subpass_count = 1,
|
.subpass_count = @intCast(subpasses.len),
|
||||||
.p_subpasses = @ptrCast(&subpass),
|
.p_subpasses = &subpasses,
|
||||||
.dependency_count = @intCast(subpass_dependencies.len),
|
.dependency_count = @intCast(subpass_dependencies.len),
|
||||||
.p_dependencies = &subpass_dependencies,
|
.p_dependencies = &subpass_dependencies,
|
||||||
};
|
};
|
||||||
|
@ -651,6 +745,34 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.sampler_set_layout = try self.device.createDescriptorSetLayout(&texture_layout_info, null);
|
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 {
|
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 {
|
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
|
// Get supported depth buffer format
|
||||||
const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint };
|
const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint };
|
||||||
self.depth_format = chooseSupportedFormat(
|
self.depth_format = chooseSupportedFormat(
|
||||||
|
@ -673,19 +833,21 @@ pub const VulkanRenderer = struct {
|
||||||
.{ .depth_stencil_attachment_bit = true },
|
.{ .depth_stencil_attachment_bit = true },
|
||||||
) orelse return error.UnsupportedDepthBufferFormat;
|
) orelse return error.UnsupportedDepthBufferFormat;
|
||||||
|
|
||||||
|
for (0..self.depth_buffer_image.len) |i| {
|
||||||
// Create depth buffer image
|
// Create depth buffer image
|
||||||
self.depth_buffer_image = try self.createImage(
|
self.depth_buffer_image[i] = try self.createImage(
|
||||||
self.extent.width,
|
self.extent.width,
|
||||||
self.extent.height,
|
self.extent.height,
|
||||||
self.depth_format,
|
self.depth_format,
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .depth_stencil_attachment_bit = true },
|
.{ .depth_stencil_attachment_bit = true },
|
||||||
.{ .device_local_bit = true },
|
.{ .device_local_bit = true },
|
||||||
&self.depth_buffer_image_memory,
|
&self.depth_buffer_image_memory[i],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create depth buffer image view
|
// Create depth buffer image view
|
||||||
self.depth_buffer_image_view = try self.createImageView(self.depth_buffer_image, self.depth_format, .{ .depth_bit = true });
|
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 {
|
fn createGraphicsPipeline(self: *Self) !void {
|
||||||
|
@ -903,6 +1065,48 @@ pub const VulkanRenderer = struct {
|
||||||
null,
|
null,
|
||||||
@ptrCast(&self.graphics_pipeline),
|
@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 {
|
fn createFramebuffers(self: *Self) !void {
|
||||||
|
@ -911,7 +1115,11 @@ pub const VulkanRenderer = struct {
|
||||||
// Create a frammebuffer for each swapchain image
|
// Create a frammebuffer for each swapchain image
|
||||||
for (self.swapchain_images, 0..) |swapchain_image, i| {
|
for (self.swapchain_images, 0..) |swapchain_image, i| {
|
||||||
// Order matters
|
// 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 = .{
|
const framebuffer_create_info: vk.FramebufferCreateInfo = .{
|
||||||
.render_pass = self.render_pass, // Render pass layout the frambuffer will be used with
|
.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);
|
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 {
|
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 {
|
fn updateUniformBuffers(self: *Self, image_index: u32) !void {
|
||||||
// Copy VP data
|
// Copy VP data
|
||||||
const data = try self.device.mapMemory(
|
const data = try self.device.mapMemory(
|
||||||
|
|
Loading…
Reference in a new issue