diff --git a/assets/shaders/triangle.glsl b/assets/shaders/triangle.glsl index f18df08..3072e29 100644 --- a/assets/shaders/triangle.glsl +++ b/assets/shaders/triangle.glsl @@ -22,7 +22,7 @@ layout(location = 0) out vec3 VertexColor; void main() { VertexColor = colors[gl_VertexIndex]; - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0) * Global.view.world_to_clip; + gl_Position = vec4(positions[gl_VertexIndex] + vec2(gl_InstanceIndex, 0), gl_InstanceIndex, 1.0) * Global.view.world_to_clip; } #endif diff --git a/src/AssetManager.zig b/src/AssetManager.zig index 3160602..27f1f8e 100644 --- a/src/AssetManager.zig +++ b/src/AssetManager.zig @@ -354,6 +354,13 @@ fn loadShaderProgramErr(self: *AssetManager, id: AssetId) !LoadedShaderProgram { var pipelines = [1]vk.Pipeline{.null_handle}; _ = try self.gc.device.createGraphicsPipelines(self.gc.pipeline_cache, 1, &.{ vk.GraphicsPipelineCreateInfo{ + .p_next = &vk.PipelineRenderingCreateInfo{ + .color_attachment_count = 1, + .p_color_attachment_formats = &[_]vk.Format{.r8g8b8a8_unorm}, + .depth_attachment_format = .d24_unorm_s8_uint, + .stencil_attachment_format = .d24_unorm_s8_uint, + .view_mask = 0, + }, .base_pipeline_index = 0, .p_input_assembly_state = &vk.PipelineInputAssemblyStateCreateInfo{ .primitive_restart_enable = vk.FALSE, @@ -374,17 +381,17 @@ fn loadShaderProgramErr(self: *AssetManager, id: AssetId) !LoadedShaderProgram { }, .p_viewport_state = &vk.PipelineViewportStateCreateInfo{}, .layout = pipeline_layout, - // .p_depth_stencil_state = &vk.PipelineDepthStencilStateCreateInfo{ - // .depth_test_enable = true, - // .depth_write_enable = true, - // .depth_compare_op = .less, - // .depth_bounds_test_enable = true, - // .stencil_test_enable = false, - // .front = std.mem.zeroes(vk.StencilOpState), - // .back = std.mem.zeroes(vk.StencilOpState), - // .min_depth_bounds = 0.0, - // .max_depth_bounds = 1.0, - // }, + .p_depth_stencil_state = &vk.PipelineDepthStencilStateCreateInfo{ + .depth_test_enable = vk.TRUE, + .depth_write_enable = vk.TRUE, + .depth_compare_op = .greater, + .depth_bounds_test_enable = vk.TRUE, + .stencil_test_enable = vk.FALSE, + .front = std.mem.zeroes(vk.StencilOpState), + .back = std.mem.zeroes(vk.StencilOpState), + .min_depth_bounds = 0.0, + .max_depth_bounds = 1.0, + }, .p_dynamic_state = &vk.PipelineDynamicStateCreateInfo{ .dynamic_state_count = @intCast(dynamic_states.len), .p_dynamic_states = &dynamic_states, @@ -399,7 +406,19 @@ fn loadShaderProgramErr(self: *AssetManager, id: AssetId) !LoadedShaderProgram { .p_color_blend_state = &vk.PipelineColorBlendStateCreateInfo{ .logic_op_enable = vk.FALSE, .logic_op = .copy, - .attachment_count = 0, + .attachment_count = 1, + .p_attachments = &.{ + vk.PipelineColorBlendAttachmentState{ + .blend_enable = vk.FALSE, + .src_color_blend_factor = .zero, + .dst_color_blend_factor = .zero, + .color_blend_op = .add, + .src_alpha_blend_factor = .zero, + .dst_alpha_blend_factor = .zero, + .alpha_blend_op = .add, + .color_write_mask = .{ .r_bit = true, .g_bit = true, .b_bit = true, .a_bit = true }, + }, + }, .blend_constants = [4]f32{ 0.0, 0.0, 0.0, 0.0 }, }, .stage_count = 2, diff --git a/src/GraphicsContext.zig b/src/GraphicsContext.zig index a5fd3a1..61b87b5 100644 --- a/src/GraphicsContext.zig +++ b/src/GraphicsContext.zig @@ -214,14 +214,14 @@ pub const ImageSyncState = struct { }; pub const Image = struct { - handle: vk.Image, - mip_count: u32, - layer_count: u32, - format: vk.Format, + handle: vk.Image = .null_handle, + mip_count: u32 = 0, + layer_count: u32 = 0, + format: vk.Format = .undefined, sync_state: ImageSyncState = .{}, - pub fn sync(self: *Image, cmds: CommandBuffer, masks: SyncBarrierMasks, layout: vk.ImageLayout) !void { + pub fn sync(self: *Image, cmds: CommandBuffer, masks: SyncBarrierMasks, layout: vk.ImageLayout, aspect: vk.ImageAspectFlags) !void { const old_layout = self.sync_state.layout; if (self.sync_state.sync(masks, layout)) |req| { cmds.pipelineBarrier2(&vk.DependencyInfo{ @@ -238,7 +238,7 @@ pub const Image = struct { .src_queue_family_index = vk.QUEUE_FAMILY_IGNORED, .dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED, .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, + .aspect_mask = aspect, .base_array_layer = 0, .base_mip_level = 0, .layer_count = self.layer_count, @@ -485,6 +485,29 @@ pub fn acquireSwapchainImage(self: *GraphicsContext, acuire_semaphore: vk.Semaph return swapchain_img; } +pub const MemoryRequirements = struct { + size: u64 = 0, + alignment: u64 = 0, + memory_type_bits: u32 = 0, + prefers_dedicated: bool = false, + requires_dedicated: bool = false, +}; + +pub fn getImageMemoryRequirements(self: *GraphicsContext, image: vk.Image) MemoryRequirements { + var result: MemoryRequirements = .{}; + var dedicated_reqs: vk.MemoryDedicatedRequirements = .{ .prefers_dedicated_allocation = vk.FALSE, .requires_dedicated_allocation = vk.FALSE }; + var mem_reqs: vk.MemoryRequirements2 = .{ .p_next = &dedicated_reqs, .memory_requirements = std.mem.zeroes(vk.MemoryRequirements) }; + self.device.getImageMemoryRequirements2(&.{ .image = image }, &mem_reqs); + + result.size = mem_reqs.memory_requirements.size; + result.alignment = mem_reqs.memory_requirements.alignment; + result.memory_type_bits = mem_reqs.memory_requirements.memory_type_bits; + result.prefers_dedicated = dedicated_reqs.prefers_dedicated_allocation == vk.TRUE; + result.requires_dedicated = dedicated_reqs.requires_dedicated_allocation == vk.TRUE; + + return result; +} + fn maybeResizeSwapchain(self: *GraphicsContext) !void { var width: c_int = 0; var height: c_int = 0; diff --git a/src/Render2.zig b/src/Render2.zig index 9cefed4..4adfdcd 100644 --- a/src/Render2.zig +++ b/src/Render2.zig @@ -243,12 +243,68 @@ pub fn init(self: *Render2, gc: *GraphicsContext, shaderman: *ShaderManager, ass }; errdefer self.command_pool.deinit(); - // NOTE: TEST for (0..MAX_FRAME_LAG) |i| { self.frame_data[i] = try FrameData.init(gc, self.command_pool); + + try self.maybeResizeFrameBuffer(&self.frame_data[i]); } } +fn maybeResizeFrameBuffer(self: *Render2, frame: *FrameData) !void { + const gc = self.gc; + if ((gc.swapchain_extent.width == frame.depth_buffer_extent.width or gc.swapchain_extent.height == frame.depth_buffer_extent.height) and frame.depth_buffer.handle != .null_handle) { + return; + } + if (frame.depth_buffer.handle != .null_handle) { + gc.device.destroyImage(frame.depth_buffer.handle, null); + gc.device.freeMemory(frame.depth_buffer_memory, null); + frame.depth_buffer = .{}; + frame.depth_buffer_memory = .null_handle; + } + + const swapchain_width = gc.swapchain_extent.width; + const swapchain_height = gc.swapchain_extent.height; + + const depth_image = try gc.device.createImage(&.{ + .image_type = .@"2d", + .array_layers = 1, + .extent = .{ .width = swapchain_width, .height = swapchain_height, .depth = 1 }, + .mip_levels = 1, + .sharing_mode = .exclusive, + .tiling = .optimal, + .usage = .{ .depth_stencil_attachment_bit = true }, + .format = .d24_unorm_s8_uint, + .samples = .{ .@"1_bit" = true }, + .initial_layout = .undefined, + }, null); + + const mem_reqs = gc.getImageMemoryRequirements(depth_image); + std.debug.assert(mem_reqs.memory_type_bits & (@as(u32, 1) << @intCast(gc.memory_config.gpu.type_index)) != 0); + // Nvidia apparently doesn't prefer dedicated allocation... Figure out what to do here + // std.debug.assert(mem_reqs.prefers_dedicated); + + frame.depth_buffer_memory = try gc.device.allocateMemory(&.{ + .p_next = @ptrCast(&vk.MemoryDedicatedAllocateInfo{ + .image = depth_image, + }), + .allocation_size = mem_reqs.size, + .memory_type_index = gc.memory_config.gpu.type_index, + }, null); + + try gc.device.bindImageMemory(depth_image, frame.depth_buffer_memory, 0); + + frame.depth_buffer = GraphicsContext.Image{ + .handle = depth_image, + .format = .d24_unorm_s8_uint, + .layer_count = 1, + .mip_count = 1, + .sync_state = .{ + .layout = .undefined, + }, + }; + frame.depth_buffer_extent = .{ .width = swapchain_width, .height = swapchain_height }; +} + fn createPerFrameBuffer(self: *Render2, usage: vk.BufferUsageFlags, size: u64, out_addr: *u64) !vk.Buffer { while (true) { if (self.vulkan_frame_arena.createBufferRaw(self.gc.device, usage, size, out_addr)) |buffer| { @@ -272,20 +328,21 @@ fn frameAllocMemReqs(self: *Render2, mem_reqs: vk.MemoryRequirements) !u64 { } pub fn draw(self: *Render2) !void { - const device = self.gc.device; + const gc = self.gc; + const device = gc.device; const frame = &self.frame_data[self.frame]; - try frame.waitForDrawAndReset(self.gc.device); + try frame.waitForDrawAndReset(gc.device); self.vulkan_frame_arena.resetFrame(self.frame); - self.vulkan_frame_arena.startFrame(self.gc.device, self.frame); + self.vulkan_frame_arena.startFrame(gc.device, self.frame); var global_buffer_addr: u64 = 0; const global_uniform_buffer = try self.createPerFrameBuffer(.{ .uniform_buffer_bit = true, .transfer_dst_bit = true }, @sizeOf(GlobalUniform), &global_buffer_addr); const global_uniform = blk: { const view = self.camera.view_mat; - // const fwidth: f32 = @floatFromInt(self.gc.swapchain_extent.width); - // const fheight: f32 = @floatFromInt(self.gc.swapchain_extent.height); + // const fwidth: f32 = @floatFromInt(gc.swapchain_extent.width); + // const fheight: f32 = @floatFromInt(gc.swapchain_extent.height); const projection = self.camera.projection(); const view_projection = projection.mul(view); @@ -299,11 +356,16 @@ pub fn draw(self: *Render2) !void { }; // Move this out into a separate func - const swapchain_image_index: u32 = try self.gc.acquireSwapchainImage(frame.acquire_swapchain_image); + const swapchain_image_index: u32 = try gc.acquireSwapchainImage(frame.acquire_swapchain_image); - var current_image = GraphicsContext.Image{ .handle = self.gc.swapchain_images[swapchain_image_index], .mip_count = 1, .layer_count = 1, .format = .r8g8b8a8_unorm }; - const current_image_view = try current_image.createView(self.gc.device, .{ .color_bit = true }); - defer self.gc.device.destroyImageView(current_image_view, null); + try self.maybeResizeFrameBuffer(frame); + const depth_image: *GraphicsContext.Image = &frame.depth_buffer; + const depth_image_view = try depth_image.createView(gc.device, .{ .depth_bit = true, .stencil_bit = true }); + defer gc.device.destroyImageView(depth_image_view, null); + + var swapchain_image = GraphicsContext.Image{ .handle = gc.swapchain_images[swapchain_image_index], .mip_count = 1, .layer_count = 1, .format = .r8g8b8a8_unorm }; + const swapchain_image_view = try swapchain_image.createView(gc.device, .{ .color_bit = true }); + defer gc.device.destroyImageView(swapchain_image_view, null); const cmds = frame.command_buffer; @@ -348,10 +410,30 @@ pub fn draw(self: *Render2) !void { }, }, 0, null); - try current_image.sync(cmds, .{ .stage_mask = .{ .color_attachment_output_bit = true }, .access_mask = .{ .color_attachment_write_bit = true } }, .attachment_optimal); + try swapchain_image.sync( + cmds, + .{ + .stage_mask = .{ .color_attachment_output_bit = true }, + .access_mask = .{ .color_attachment_write_bit = true }, + }, + .attachment_optimal, + .{ .color_bit = true }, + ); + try depth_image.sync( + cmds, + .{ + .stage_mask = .{ .early_fragment_tests_bit = true, .late_fragment_tests_bit = true }, + .access_mask = .{ + .depth_stencil_attachment_write_bit = true, + .depth_stencil_attachment_read_bit = true, + }, + }, + .depth_stencil_attachment_optimal, + .{ .depth_bit = true, .stencil_bit = true }, + ); { - cmds.beginRendering(&.{ - .render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = self.gc.swapchain_extent }, + cmds.beginRendering(&vk.RenderingInfo{ + .render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = gc.swapchain_extent }, .layer_count = 1, .view_mask = 0, .color_attachment_count = 1, @@ -361,11 +443,29 @@ pub fn draw(self: *Render2) !void { .load_op = .clear, .store_op = .store, .image_layout = .attachment_optimal, - .image_view = current_image_view, + .image_view = swapchain_image_view, .resolve_image_layout = .attachment_optimal, .resolve_mode = .{}, }, }, + .p_depth_attachment = &vk.RenderingAttachmentInfo{ + .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, + .load_op = .clear, + .store_op = .store, + .image_layout = .depth_stencil_attachment_optimal, + .image_view = depth_image_view, + .resolve_image_layout = .depth_stencil_attachment_optimal, + .resolve_mode = .{}, + }, + .p_stencil_attachment = &vk.RenderingAttachmentInfo{ + .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, + .load_op = .clear, + .store_op = .none, + .image_layout = .depth_stencil_attachment_optimal, + .image_view = depth_image_view, + .resolve_image_layout = .depth_stencil_attachment_optimal, + .resolve_mode = .{}, + }, }); defer cmds.endRendering(); @@ -377,24 +477,24 @@ pub fn draw(self: *Render2) !void { cmds.setViewportWithCount(1, &.{vk.Viewport{ .x = 0, .y = 0, - .width = @floatFromInt(self.gc.swapchain_extent.width), - .height = @floatFromInt(self.gc.swapchain_extent.height), + .width = @floatFromInt(gc.swapchain_extent.width), + .height = @floatFromInt(gc.swapchain_extent.height), .min_depth = 0, .max_depth = 1, }}); cmds.setScissorWithCount(1, &.{vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, - .extent = self.gc.swapchain_extent, + .extent = gc.swapchain_extent, }}); - cmds.draw(3, 1, 0, 0); + cmds.draw(3, 2, 0, 0); } - try current_image.sync(cmds, .{}, .present_src_khr); + try swapchain_image.sync(cmds, .{}, .present_src_khr, .{ .color_bit = true }); } try cmds.endCommandBuffer(); - try self.gc.queues.graphics.submit( + try gc.queues.graphics.submit( &GraphicsContext.SubmitInfo{ .wait_semaphores = &.{frame.acquire_swapchain_image}, .wait_dst_stage_mask = &.{vk.PipelineStageFlags{}}, @@ -404,11 +504,11 @@ pub fn draw(self: *Render2) !void { frame.draw_fence, ); - _ = try self.gc.device.queuePresentKHR(self.gc.queues.graphics.handle, &.{ + _ = try gc.device.queuePresentKHR(gc.queues.graphics.handle, &.{ .swapchain_count = 1, .wait_semaphore_count = 1, .p_wait_semaphores = &.{frame.draw_sema}, - .p_swapchains = &.{self.gc.swapchain}, + .p_swapchains = &.{gc.swapchain}, .p_image_indices = &.{swapchain_image_index}, }); @@ -439,6 +539,9 @@ const FrameData = struct { command_buffer: GraphicsContext.CommandBuffer, descriptor_pool: vk.DescriptorPool = .null_handle, + depth_buffer_extent: vk.Extent2D = .{ .width = 0, .height = 0 }, + depth_buffer_memory: vk.DeviceMemory = .null_handle, + depth_buffer: GraphicsContext.Image = .{}, pub fn init(gc: *GraphicsContext, command_pool: GraphicsContext.CommandPool) !FrameData { return FrameData{