Add depth buffer

This commit is contained in:
Przemyslaw Gasinski 2024-07-26 23:55:48 +02:00
parent cbf0980b67
commit 4bd2bff03e
3 changed files with 160 additions and 20 deletions

View file

@ -47,14 +47,11 @@ pub fn main() !void {
angle -= 360.0; angle -= 360.0;
} }
var first_model = zm.identity(); var first_model = zm.rotationZ(angle);
var second_model = zm.identity(); var second_model = zm.rotationZ(-angle * 2);
first_model = zm.mul(first_model, zm.rotationZ(angle)); first_model = zm.mul(first_model, zm.translation(0.0, 0.0, -2.5));
first_model = zm.mul(first_model, zm.translation(-2.0, 0.0, -5.0)); second_model = zm.mul(second_model, zm.translation(0.0, 0.0, -4.5));
second_model = zm.mul(second_model, zm.rotationZ(-angle * 2));
second_model = zm.mul(second_model, zm.translation(2.0, 0.0, -5.0));
try vulkan_renderer.updateModel(0, first_model); try vulkan_renderer.updateModel(0, first_model);
try vulkan_renderer.updateModel(1, second_model); try vulkan_renderer.updateModel(1, second_model);

View file

@ -36,7 +36,7 @@ pub const SwapchainImage = struct {
image_view: vk.ImageView, image_view: vk.ImageView,
}; };
fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 { pub fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 {
// Get properties of physical device memory // Get properties of physical device memory
const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev); const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev);
const mem_type_count = memory_properties.memory_type_count; const mem_type_count = memory_properties.memory_type_count;

View file

@ -79,6 +79,10 @@ 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_memory: vk.DeviceMemory,
depth_buffer_image_view: vk.ImageView,
// Descriptors // Descriptors
descriptor_set_layout: vk.DescriptorSetLayout, descriptor_set_layout: vk.DescriptorSetLayout,
push_constant_range: vk.PushConstantRange, push_constant_range: vk.PushConstantRange,
@ -99,6 +103,7 @@ pub const VulkanRenderer = struct {
// Utilities // Utilities
swapchain_image_format: vk.Format, swapchain_image_format: vk.Format,
depth_format: vk.Format,
extent: vk.Extent2D, extent: vk.Extent2D,
// Synchronisation // Synchronisation
@ -126,6 +131,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.createDepthBufferImage();
try self.createRenderPass(); try self.createRenderPass();
try self.createDescriptorSetLayout(); try self.createDescriptorSetLayout();
try self.createPushConstantRange(); try self.createPushConstantRange();
@ -153,16 +159,16 @@ pub const VulkanRenderer = struct {
// Vertex Data // Vertex Data
var mesh_vertices = [_]Vertex{ var mesh_vertices = [_]Vertex{
.{ .pos = .{ -0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0 .{ .pos = .{ -0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0
.{ .pos = .{ -0.4, -0.4, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 1 .{ .pos = .{ -0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 1
.{ .pos = .{ 0.4, -0.4, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 2 .{ .pos = .{ 0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 2
.{ .pos = .{ 0.4, 0.4, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3 .{ .pos = .{ 0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 3
}; };
var mesh_vertices2 = [_]Vertex{ var mesh_vertices2 = [_]Vertex{
.{ .pos = .{ -0.25, 0.6, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0 .{ .pos = .{ -0.25, 0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 0
.{ .pos = .{ -0.25, -0.6, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 1 .{ .pos = .{ -0.25, -0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 1
.{ .pos = .{ 0.25, -0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 2 .{ .pos = .{ 0.25, -0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 2
.{ .pos = .{ 0.25, 0.6, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3 .{ .pos = .{ 0.25, 0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 3
}; };
// Index Data // Index Data
@ -274,6 +280,10 @@ pub const VulkanRenderer = struct {
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null); self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
} }
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);
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);
@ -496,6 +506,7 @@ pub const VulkanRenderer = struct {
} }
fn createRenderPass(self: *Self) !void { fn createRenderPass(self: *Self) !void {
// -- Attachments --
// Colour attachment of the render pass // Colour attachment of the render pass
const colour_attachment: vk.AttachmentDescription = .{ const colour_attachment: vk.AttachmentDescription = .{
.format = self.swapchain_image_format, // Format to use for attachment .format = self.swapchain_image_format, // Format to use for attachment
@ -510,17 +521,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 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 = .{
.attachment = 1,
.layout = vk.ImageLayout.depth_stencil_attachment_optimal,
};
// Information about a particular subpass the render pass is using // Information about a particular subpass the render pass is using
const subpass: vk.SubpassDescription = .{ const subpass: vk.SubpassDescription = .{
.pipeline_bind_point = .graphics, // Pipeline type subpass is to be bound to .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(&colour_attachment_reference),
.p_depth_stencil_attachment = &depth_attachment_reference,
}; };
// Need to determine when layout transitions occur using subpass dependencies // Need to determine when layout transitions occur using subpass dependencies
@ -549,9 +579,12 @@ pub const VulkanRenderer = struct {
}, },
}; };
// Order matters
const render_pass_attachments = [_]vk.AttachmentDescription{ colour_attachment, depth_attachment };
const render_pass_create_info: vk.RenderPassCreateInfo = .{ const render_pass_create_info: vk.RenderPassCreateInfo = .{
.attachment_count = 1, .attachment_count = @intCast(render_pass_attachments.len),
.p_attachments = @ptrCast(&colour_attachment), .p_attachments = &render_pass_attachments,
.subpass_count = 1, .subpass_count = 1,
.p_subpasses = @ptrCast(&subpass), .p_subpasses = @ptrCast(&subpass),
.dependency_count = @intCast(subpass_dependencies.len), .dependency_count = @intCast(subpass_dependencies.len),
@ -592,6 +625,32 @@ pub const VulkanRenderer = struct {
}; };
} }
fn createDepthBufferImage(self: *Self) !void {
// Get supported depth buffer format
const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint };
self.depth_format = chooseSupportedFormat(
self.physical_device,
self.instance,
&formats,
.optimal,
.{ .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,
);
// Create depth buffer image view
self.depth_buffer_image_view = try self.createImageView(self.depth_buffer_image, self.depth_format, .{ .depth_bit = true });
}
fn createGraphicsPipeline(self: *Self) !void { fn createGraphicsPipeline(self: *Self) !void {
// Create shader modules // Create shader modules
const vert = try self.device.createShaderModule(&.{ const vert = try self.device.createShaderModule(&.{
@ -759,7 +818,17 @@ pub const VulkanRenderer = struct {
self.pipeline_layout = try self.device.createPipelineLayout(&pipeline_layout_create_info, null); self.pipeline_layout = try self.device.createPipelineLayout(&pipeline_layout_create_info, null);
// -- Depth stencil testing -- // -- Depth stencil testing --
// TODO: Set a depth stencil testing const depth_stencil_create_info: vk.PipelineDepthStencilStateCreateInfo = .{
.depth_test_enable = vk.TRUE, // Enable checking depth to determine fragment write
.depth_write_enable = vk.TRUE, // Enable writing to depth buffer to replace all values
.depth_compare_op = .less, // Comparison operation that allows an overwrite (is in front)
.depth_bounds_test_enable = vk.FALSE, // Depth bounds test: does the depth value exist between two bounds
.stencil_test_enable = vk.FALSE, // Enable stencil test
.front = undefined,
.back = undefined,
.min_depth_bounds = undefined,
.max_depth_bounds = undefined,
};
// -- Graphics pipeline creation -- // -- Graphics pipeline creation --
const pipeline_create_info: vk.GraphicsPipelineCreateInfo = .{ const pipeline_create_info: vk.GraphicsPipelineCreateInfo = .{
@ -772,7 +841,7 @@ pub const VulkanRenderer = struct {
.p_rasterization_state = &rasterizer_create_info, .p_rasterization_state = &rasterizer_create_info,
.p_multisample_state = &multisampling_create_info, .p_multisample_state = &multisampling_create_info,
.p_color_blend_state = &colour_blending_create_info, .p_color_blend_state = &colour_blending_create_info,
.p_depth_stencil_state = null, .p_depth_stencil_state = &depth_stencil_create_info,
.layout = self.pipeline_layout, // Pipeline layout the pipeline should use .layout = self.pipeline_layout, // Pipeline layout the pipeline should use
.render_pass = self.render_pass, // Renderpass description the pipeline is compatible with .render_pass = self.render_pass, // Renderpass description the pipeline is compatible with
.subpass = 0, // Subpass of renderpass to use with pipeline .subpass = 0, // Subpass of renderpass to use with pipeline
@ -795,7 +864,8 @@ 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| {
const attachments = [_]vk.ImageView{swapchain_image.image_view}; // Order matters
const attachments = [_]vk.ImageView{ swapchain_image.image_view, self.depth_buffer_image_view };
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
@ -973,6 +1043,7 @@ pub const VulkanRenderer = struct {
const clear_values = [_]vk.ClearValue{ const clear_values = [_]vk.ClearValue{
.{ .color = .{ .float_32 = [4]f32{ 0.6, 0.65, 0.4, 1.0 } } }, .{ .color = .{ .float_32 = [4]f32{ 0.6, 0.65, 0.4, 1.0 } } },
.{ .depth_stencil = .{ .depth = 1.0, .stencil = 1 } },
}; };
// Information about how to begin a render pass (only needed for graphical application) // Information about how to begin a render pass (only needed for graphical application)
@ -982,7 +1053,7 @@ pub const VulkanRenderer = struct {
.offset = .{ .x = 0, .y = 0 }, // Start point of render pass in pixels .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) .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) .p_clear_values = &clear_values, // List of clear values
.clear_value_count = @intCast(clear_values.len), .clear_value_count = @intCast(clear_values.len),
.framebuffer = undefined, .framebuffer = undefined,
}; };
@ -1234,6 +1305,54 @@ pub const VulkanRenderer = struct {
}; };
} }
fn createImage(
self: *Self,
width: u32,
height: u32,
format: vk.Format,
tiling: vk.ImageTiling,
use_flags: vk.ImageUsageFlags,
prop_flags: vk.MemoryPropertyFlags,
image_memory: *vk.DeviceMemory,
) !vk.Image {
// -- Create Image --
const image_create_info: vk.ImageCreateInfo = .{
.image_type = .@"2d", // Type of image (1D, 2D or 3D)
.extent = .{
.width = width, // Width of image extent
.height = height, // Height of image extent
.depth = 1, // Depth of image (just 1, no 3D aspecct)
},
.mip_levels = 1, // Number of mipmap levels
.array_layers = 1, // Number of level in image array
.format = format, // Format type of image
.tiling = tiling, // How image data should be tiled (arranged for optimal reading)
.initial_layout = .undefined, // Layout of image data on creation
.usage = use_flags, // Bit flags defining what image will be used for
.samples = .{ .@"1_bit" = true }, // Number of samples for multi-sampling
.sharing_mode = .exclusive, // Whether image can be shared between queues
};
const image = try self.device.createImage(&image_create_info, null);
// -- Create memory for image --
// Get memory requirements for a type of image
const memory_requirements = self.device.getImageMemoryRequirements(image);
// Allocate memory using image requirements and user-defined properties
const memory_alloc_info: vk.MemoryAllocateInfo = .{
.allocation_size = memory_requirements.size,
.memory_type_index = Utilities.findMemoryTypeIndex(self.physical_device, self.instance, memory_requirements.memory_type_bits, prop_flags),
};
image_memory.* = try self.device.allocateMemory(&memory_alloc_info, null);
// Connect memory to image
try self.device.bindImageMemory(image, image_memory.*, 0);
return image;
}
fn createImageView(self: Self, image: vk.Image, format: vk.Format, aspect_flags: vk.ImageAspectFlags) !vk.ImageView { fn createImageView(self: Self, image: vk.Image, format: vk.Format, aspect_flags: vk.ImageAspectFlags) !vk.ImageView {
const image_view_create_info: vk.ImageViewCreateInfo = .{ const image_view_create_info: vk.ImageViewCreateInfo = .{
.image = image, .image = image,
@ -1311,6 +1430,30 @@ fn chooseSwapExtent(window: *sdl.Window, surface_capabilities: vk.SurfaceCapabil
return extent; return extent;
} }
fn chooseSupportedFormat(
pdev: vk.PhysicalDevice,
instance: Instance,
formats: []const vk.Format,
tiling: vk.ImageTiling,
feature_flags: vk.FormatFeatureFlags,
) ?vk.Format {
// Loop through the options and find a compatible one
// Depending on tiling choice. Need to check for different bit flag
for (formats) |format| {
// Get properties for given format on this device
const properties = instance.getPhysicalDeviceFormatProperties(pdev, format);
if (tiling == .linear and properties.linear_tiling_features.contains(feature_flags)) {
return format;
} else if (tiling == .optimal and properties.optimal_tiling_features.contains(feature_flags)) {
return format;
}
}
return null;
}
// Validation layers stuff // Validation layers stuff
fn createDebugMessenger(instance: Instance) !vk.DebugUtilsMessengerEXT { fn createDebugMessenger(instance: Instance) !vk.DebugUtilsMessengerEXT {
const debug_create_info = getDebugUtilsCreateInfo(); const debug_create_info = getDebugUtilsCreateInfo();