diff --git a/src/Game.zig b/src/Game.zig index 40be509..c2db7a0 100644 --- a/src/Game.zig +++ b/src/Game.zig @@ -441,6 +441,17 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain .alpha_to_coverage_enable = .false, .alpha_to_one_enable = .false, }, + .depth_stencil_state = .{ + .depth_test_enable = .true, + .depth_write_enable = .true, + .depth_compare_op = .greater, + .depth_bounds_test_enable = .false, + .stencil_test_enable = .false, + .front = undefined, + .back = undefined, + .min_depth_bounds = 0, + .max_depth_bounds = 1, + }, .color_blend_state = .{ .logic_op_enable = .false, .logic_op = .copy, @@ -639,10 +650,10 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain }); const object_count: u32 = blk: { - var objects: std.ArrayList(ObjectUniforms) = try .initCapacity(allocator, 289); + var objects: std.ArrayList(ObjectUniforms) = try .initCapacity(allocator, 578); defer objects.deinit(allocator); - var it = Iterator3.init(.init(-8, -8, 0), .init(8, 8, 0), .one); + var it = Iterator3.init(.init(-8, -8, 0), .init(8, 8, 2), .init(1, 1, 2)); while (it.next()) |pos| { const material: Materials.Id = @enumFromInt(engine.random.uintLessThan(u16, @intFromEnum(materials.next_id))); const matrix_os_to_ws = Matrix4x4.initTranslation(pos); @@ -750,9 +761,9 @@ pub fn update(self: *Game, dt: f32) void { // zig fmt: off const matrix_vs_to_cs = Matrix4x4.init( camera_xscale, 0, 0, 0, - 0, 0, camera_near_plane, 1, + 0, 0, 0, 1, 0, -camera_yscale, 0, 0, - 0, 0, 0, 0, + 0, 0, camera_near_plane, 0, ); // zig fmt: on @@ -863,7 +874,17 @@ fn render(self: *Game) !void { try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); { const clear_values = [_]vk.ClearValue{ - .{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } }, + .{ + .color = .{ + .float_32 = .{ 0, 0, 0, 0 }, + }, + }, + .{ + .depth_stencil = .{ + .depth = 0, + .stencil = 0, + }, + }, }; command_buffer.beginRenderPass(&.{ diff --git a/src/engine/Swapchain.zig b/src/engine/Swapchain.zig index f99df23..f7d4259 100644 --- a/src/engine/Swapchain.zig +++ b/src/engine/Swapchain.zig @@ -5,6 +5,7 @@ const vk = @import("vulkan"); const Engine = @import("Engine.zig"); const QSM = @import("QueueSharingMode.zig"); +const Texture = @import("Texture.zig"); params: Params, render_pass: vk.RenderPass, @@ -12,6 +13,7 @@ render_pass: vk.RenderPass, extent: vk.Extent2D = .{ .width = 0, .height = 0 }, swapchain: vk.SwapchainKHR = .null_handle, swapchain_images: []SwapchainImage = &.{}, +depth_texture: ?Texture = null, image_index: u32 = 0, semaphore_image_acquired: vk.Semaphore = .null_handle, @@ -35,6 +37,16 @@ pub fn init(engine: *Engine) !Swapchain { .initial_layout = .undefined, .final_layout = .present_src_khr, }, + .{ + .format = Texture.Usage.depth.vkFormat(), + .samples = .{ .@"1_bit" = true }, + .load_op = .clear, + .store_op = .dont_care, + .stencil_load_op = .clear, + .stencil_store_op = .dont_care, + .initial_layout = .undefined, + .final_layout = .depth_stencil_attachment_optimal, + }, }; const color_attachments = [_]vk.AttachmentReference{ @@ -44,11 +56,39 @@ pub fn init(engine: *Engine) !Swapchain { }, }; + const depth_stencil_attachment: vk.AttachmentReference = .{ + .attachment = 1, + .layout = .depth_stencil_attachment_optimal, + }; + const subpasses = [_]vk.SubpassDescription{ .{ .pipeline_bind_point = .graphics, .color_attachment_count = color_attachments.len, .p_color_attachments = &color_attachments, + .p_depth_stencil_attachment = &depth_stencil_attachment, + }, + }; + + const dependencies = [_]vk.SubpassDependency{ + .{ + .src_subpass = 0, + .dst_subpass = 0, + .src_stage_mask = .{ + .color_attachment_output_bit = true, + .late_fragment_tests_bit = true, + }, + .dst_stage_mask = .{ + .color_attachment_output_bit = true, + .early_fragment_tests_bit = true, + }, + .src_access_mask = .{ + .depth_stencil_attachment_write_bit = true, + }, + .dst_access_mask = .{ + .color_attachment_write_bit = true, + .depth_stencil_attachment_write_bit = true, + }, }, }; @@ -57,6 +97,8 @@ pub fn init(engine: *Engine) !Swapchain { .p_attachments = &attachments, .subpass_count = subpasses.len, .p_subpasses = &subpasses, + .dependency_count = dependencies.len, + .p_dependencies = &dependencies, }, &engine.vk_allocator.interface); }; errdefer engine.device.destroyRenderPass(render_pass, &engine.vk_allocator.interface); @@ -80,6 +122,10 @@ pub fn deinit(self: *Swapchain, engine: *Engine) void { } allocator.free(self.swapchain_images); + if (self.depth_texture) |*depth_texture| { + depth_texture.deinit(engine); + } + if (self.swapchain != .null_handle) { engine.device.destroySwapchainKHR(self.swapchain, &engine.vk_allocator.interface); } @@ -95,6 +141,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void { const old_swapchain = self.swapchain; const old_swapchain_images = self.swapchain_images; + var old_depth_texture = self.depth_texture; const old_semaphore_image_acquired = self.semaphore_image_acquired; const extent = try getCurrentExtent(engine); @@ -137,6 +184,10 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void { allocator.free(self.swapchain_images); self.swapchain_images = &.{}; + if (old_depth_texture) |*depth_texture| { + depth_texture.deinit(engine); + } + if (old_swapchain != .null_handle) { engine.device.destroySwapchainKHR(old_swapchain, &engine.vk_allocator.interface); self.swapchain = .null_handle; @@ -149,6 +200,16 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void { self.semaphore_image_acquired = .null_handle; } + // --- CREATE DEPTH TEXTURE ------------------------------------------------ + + var new_depth_texture = try Texture.init(engine, .{ + .width = extent.width, + .height = extent.height, + .target_queue = .graphics, + .usage = .depth, + }); + errdefer new_depth_texture.deinit(engine); + // --- CREATE NEW SWAPCHAIN IMAGES ----------------------------------------- const new_swapchain_images = blk: { @@ -166,6 +227,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void { .format = self.params.surface_format.format, .render_pass = self.render_pass, .extent = extent, + .depth_stencil_image_view = new_depth_texture.image_view, })); } @@ -195,6 +257,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void { self.extent = extent; self.swapchain = new_swapchain; self.swapchain_images = new_swapchain_images; + self.depth_texture = new_depth_texture; self.image_index = res.image_index; self.semaphore_image_acquired = semaphore_image_acquired; } @@ -359,6 +422,7 @@ const SwapchainImage = struct { format: vk.Format, render_pass: vk.RenderPass, extent: vk.Extent2D, + depth_stencil_image_view: vk.ImageView, }; fn init(engine: *Engine, props: InitProps) !SwapchainImage { @@ -389,7 +453,7 @@ const SwapchainImage = struct { const framebuffer = try engine.createFramebuffer(.{ .render_pass = props.render_pass, - .attachments = &.{image_view}, + .attachments = &.{ image_view, props.depth_stencil_image_view }, .width = props.extent.width, .height = props.extent.height, .layers = 1, diff --git a/src/engine/Texture.zig b/src/engine/Texture.zig index 669ea11..9a5a34e 100644 --- a/src/engine/Texture.zig +++ b/src/engine/Texture.zig @@ -12,6 +12,7 @@ pub const Usage = enum { normal, occlusion_roughness_metallic, emissive, + depth, pub fn vkFormat(self: Usage) vk.Format { return switch (self) { @@ -19,6 +20,7 @@ pub const Usage = enum { .normal => .r8g8b8a8_snorm, .occlusion_roughness_metallic => .r8g8b8a8_unorm, .emissive => .r16g16b16a16_sfloat, + .depth => .d32_sfloat, }; } @@ -28,6 +30,7 @@ pub const Usage = enum { .normal => 4, .occlusion_roughness_metallic => 4, .emissive => 4, + .depth => 1, }; } @@ -37,6 +40,7 @@ pub const Usage = enum { .normal => i8, .occlusion_roughness_metallic => u8, .emissive => f16, + .depth => f32, }; } @@ -80,6 +84,11 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Texture { }; const transfer_queue_family = engine.transfer_queue.allocation.family; + const queue_family_indices: []const u32 = if (init_info.usage == .depth) + &.{target_queue_family} + else + &.{ target_queue_family, transfer_queue_family }; + const image = try engine.createImage(.{ .image_type = .@"2d", .format = init_info.usage.vkFormat(), @@ -93,10 +102,11 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Texture { .samples = .{ .@"1_bit" = true }, .tiling = .optimal, .usage = .{ - .transfer_dst_bit = true, - .sampled_bit = true, + .depth_stencil_attachment_bit = init_info.usage == .depth, + .transfer_dst_bit = init_info.usage != .depth, + .sampled_bit = init_info.usage != .depth, }, - .queue_family_indices = &.{ target_queue_family, transfer_queue_family }, + .queue_family_indices = queue_family_indices, .initial_layout = .undefined, }); errdefer engine.destroyImage(image); @@ -112,7 +122,10 @@ pub fn init(engine: *Engine, init_info: InitInfo) !Texture { .view_type = .@"2d", .format = init_info.usage.vkFormat(), .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, + .aspect_mask = .{ + .color_bit = init_info.usage != .depth, + .depth_bit = init_info.usage == .depth, + }, .base_mip_level = 0, .level_count = 1, .base_array_layer = 0, @@ -167,6 +180,7 @@ pub fn writeRaw(self: Texture, engine: *Engine, data: []const u8) !void { const texel_count = try std.math.mul(u32, self.width, self.height); const byte_length = try std.math.mul(u32, texel_count, self.usage.bytesPerTexel()); std.debug.assert(data.len == byte_length); + std.debug.assert(self.usage != .depth); var staging_buffer = try StagingBuffer.init(engine, .{ .capacity = @intCast(byte_length),