Add depth buffer
This commit is contained in:
parent
cbf0980b67
commit
4bd2bff03e
3 changed files with 160 additions and 20 deletions
11
src/main.zig
11
src/main.zig
|
@ -47,14 +47,11 @@ pub fn main() !void {
|
|||
angle -= 360.0;
|
||||
}
|
||||
|
||||
var first_model = zm.identity();
|
||||
var second_model = zm.identity();
|
||||
var first_model = zm.rotationZ(angle);
|
||||
var second_model = zm.rotationZ(-angle * 2);
|
||||
|
||||
first_model = zm.mul(first_model, zm.rotationZ(angle));
|
||||
first_model = zm.mul(first_model, zm.translation(-2.0, 0.0, -5.0));
|
||||
|
||||
second_model = zm.mul(second_model, zm.rotationZ(-angle * 2));
|
||||
second_model = zm.mul(second_model, zm.translation(2.0, 0.0, -5.0));
|
||||
first_model = zm.mul(first_model, zm.translation(0.0, 0.0, -2.5));
|
||||
second_model = zm.mul(second_model, zm.translation(0.0, 0.0, -4.5));
|
||||
|
||||
try vulkan_renderer.updateModel(0, first_model);
|
||||
try vulkan_renderer.updateModel(1, second_model);
|
||||
|
|
|
@ -36,7 +36,7 @@ pub const SwapchainImage = struct {
|
|||
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
|
||||
const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev);
|
||||
const mem_type_count = memory_properties.memory_type_count;
|
||||
|
|
|
@ -79,6 +79,10 @@ 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,
|
||||
|
||||
// Descriptors
|
||||
descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
push_constant_range: vk.PushConstantRange,
|
||||
|
@ -99,6 +103,7 @@ pub const VulkanRenderer = struct {
|
|||
|
||||
// Utilities
|
||||
swapchain_image_format: vk.Format,
|
||||
depth_format: vk.Format,
|
||||
extent: vk.Extent2D,
|
||||
|
||||
// Synchronisation
|
||||
|
@ -126,6 +131,7 @@ pub const VulkanRenderer = struct {
|
|||
try self.getPhysicalDevice();
|
||||
try self.createLogicalDevice();
|
||||
try self.createSwapchain();
|
||||
try self.createDepthBufferImage();
|
||||
try self.createRenderPass();
|
||||
try self.createDescriptorSetLayout();
|
||||
try self.createPushConstantRange();
|
||||
|
@ -153,16 +159,16 @@ pub const VulkanRenderer = struct {
|
|||
// Vertex Data
|
||||
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 = .{ 0.0, 1.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 = .{ 0.0, 1.0, 0.0 } }, // 3
|
||||
.{ .pos = .{ -0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 1
|
||||
.{ .pos = .{ 0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 2
|
||||
.{ .pos = .{ 0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 3
|
||||
};
|
||||
|
||||
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, 1.0, 0.0 } }, // 1
|
||||
.{ .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, 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, 1.0, 0.0 } }, // 3
|
||||
.{ .pos = .{ 0.25, 0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 3
|
||||
};
|
||||
|
||||
// Index Data
|
||||
|
@ -274,6 +280,10 @@ pub const VulkanRenderer = struct {
|
|||
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.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
|
||||
|
||||
|
@ -496,6 +506,7 @@ pub const VulkanRenderer = struct {
|
|||
}
|
||||
|
||||
fn createRenderPass(self: *Self) !void {
|
||||
// -- Attachments --
|
||||
// Colour attachment of the render pass
|
||||
const colour_attachment: vk.AttachmentDescription = .{
|
||||
.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)
|
||||
};
|
||||
|
||||
// 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 = .{
|
||||
.attachment = 0,
|
||||
.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
|
||||
const subpass: vk.SubpassDescription = .{
|
||||
.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,
|
||||
};
|
||||
|
||||
// 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 = .{
|
||||
.attachment_count = 1,
|
||||
.p_attachments = @ptrCast(&colour_attachment),
|
||||
.attachment_count = @intCast(render_pass_attachments.len),
|
||||
.p_attachments = &render_pass_attachments,
|
||||
.subpass_count = 1,
|
||||
.p_subpasses = @ptrCast(&subpass),
|
||||
.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 {
|
||||
// Create shader modules
|
||||
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);
|
||||
|
||||
// -- 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 --
|
||||
const pipeline_create_info: vk.GraphicsPipelineCreateInfo = .{
|
||||
|
@ -772,7 +841,7 @@ pub const VulkanRenderer = struct {
|
|||
.p_rasterization_state = &rasterizer_create_info,
|
||||
.p_multisample_state = &multisampling_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
|
||||
.render_pass = self.render_pass, // Renderpass description the pipeline is compatible with
|
||||
.subpass = 0, // Subpass of renderpass to use with pipeline
|
||||
|
@ -795,7 +864,8 @@ pub const VulkanRenderer = struct {
|
|||
|
||||
// Create a frammebuffer for each swapchain image
|
||||
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 = .{
|
||||
.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{
|
||||
.{ .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)
|
||||
|
@ -982,7 +1053,7 @@ pub const VulkanRenderer = struct {
|
|||
.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)
|
||||
.p_clear_values = &clear_values, // List of clear values
|
||||
.clear_value_count = @intCast(clear_values.len),
|
||||
.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 {
|
||||
const image_view_create_info: vk.ImageViewCreateInfo = .{
|
||||
.image = image,
|
||||
|
@ -1311,6 +1430,30 @@ fn chooseSwapExtent(window: *sdl.Window, surface_capabilities: vk.SurfaceCapabil
|
|||
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
|
||||
fn createDebugMessenger(instance: Instance) !vk.DebugUtilsMessengerEXT {
|
||||
const debug_create_info = getDebugUtilsCreateInfo();
|
||||
|
|
Loading…
Reference in a new issue