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;
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue