From 8fd94e631d2d6a4800c24d39b6f7d0c7178e4bb1 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Mon, 8 Jul 2024 14:25:10 -0400 Subject: [PATCH] better separation of swapchain, flight, and uber --- src/Uber.zig | 79 ++++++++------- src/au.zig | 2 +- src/au/Flights.zig | 57 +++++++++++ src/au/SwapChain.zig | 83 ++++++++++++++++ src/au/flights.zig | 64 ------------ src/main.zig | 202 +++++++------------------------------- src/shaders/triangle.vert | 4 +- 7 files changed, 220 insertions(+), 271 deletions(-) create mode 100644 src/au/Flights.zig delete mode 100644 src/au/flights.zig diff --git a/src/Uber.zig b/src/Uber.zig index 3144a25..b1f59f8 100644 --- a/src/Uber.zig +++ b/src/Uber.zig @@ -11,51 +11,41 @@ pipeline: vk.Pipeline, pub const Index = u16; +pub const Uniform = extern struct { + mat: [16]f32, + + const Bindings = [_]vk.DescriptorSetLayoutBinding{.{ + .binding = 0, + .descriptor_type = .uniform_buffer, + .descriptor_count = 1, + .stage_flags = .{ .vertex_bit = true }, + }}; +}; + pub const Vertex = extern struct { pos: [4]f32, color: [3]f32, - const InputStateInfo = vk.PipelineVertexInputStateCreateInfo{ - .vertex_binding_description_count = 1, - .p_vertex_binding_descriptions = &.{ - vk.VertexInputBindingDescription{ - .binding = 0, - .stride = @sizeOf(Vertex), - .input_rate = .vertex, - }, - }, - - .vertex_attribute_description_count = 2, - .p_vertex_attribute_descriptions = &.{ - vk.VertexInputAttributeDescription{ - .binding = 0, - .location = 0, - .format = .r32g32b32a32_sfloat, - .offset = @offsetOf(Vertex, "pos"), - }, - vk.VertexInputAttributeDescription{ - .binding = 0, - .location = 1, - .format = .r32g32b32_sfloat, - .offset = @offsetOf(Vertex, "color"), - }, + const Bindings = [_]vk.VertexInputBindingDescription{ + .{ + .binding = 0, + .stride = @sizeOf(Vertex), + .input_rate = .vertex, }, }; -}; -pub const Uniform = extern struct { - proj: [16]f32, - - pub const DescriptorLayoutInfo = vk.DescriptorSetLayoutCreateInfo{ - .flags = .{}, - .binding_count = 1, - .p_bindings = &.{ - vk.DescriptorSetLayoutBinding{ - .binding = 0, - .descriptor_type = .uniform_buffer, - .descriptor_count = 1, - .stage_flags = .{ .vertex_bit = true }, - }, + const Attributes = [_]vk.VertexInputAttributeDescription{ + .{ + .binding = 0, + .location = 0, + .format = .r32g32b32a32_sfloat, + .offset = @offsetOf(Vertex, "pos"), + }, + .{ + .binding = 0, + .location = 1, + .format = .r32g32b32_sfloat, + .offset = @offsetOf(Vertex, "color"), }, }; }; @@ -73,7 +63,11 @@ pub fn init(cache: vk.PipelineCache) !Self { }, null); defer au.D.destroyShaderModule(frag, null); - const set_layout = try au.D.createDescriptorSetLayout(&Uniform.DescriptorLayoutInfo, null); + const set_layout = try au.D.createDescriptorSetLayout(&vk.DescriptorSetLayoutCreateInfo{ + .flags = .{}, + .binding_count = @intCast(Uniform.Bindings.len), + .p_bindings = &Uniform.Bindings, + }, null); errdefer au.D.destroyDescriptorSetLayout(set_layout, null); const layout = try au.D.createPipelineLayout(&vk.PipelineLayoutCreateInfo{ @@ -96,7 +90,12 @@ pub fn init(cache: vk.PipelineCache) !Self { .subpass = 0, .base_pipeline_handle = .null_handle, .base_pipeline_index = -1, - .p_vertex_input_state = &Vertex.InputStateInfo, + .p_vertex_input_state = &vk.PipelineVertexInputStateCreateInfo{ + .vertex_binding_description_count = @intCast(Vertex.Bindings.len), + .p_vertex_binding_descriptions = &Vertex.Bindings, + .vertex_attribute_description_count = @intCast(Vertex.Attributes.len), + .p_vertex_attribute_descriptions = &Vertex.Attributes, + }, .p_input_assembly_state = &vk.PipelineInputAssemblyStateCreateInfo{ .topology = .triangle_list, .primitive_restart_enable = vk.FALSE, diff --git a/src/au.zig b/src/au.zig index 658fc98..4720b03 100644 --- a/src/au.zig +++ b/src/au.zig @@ -6,7 +6,7 @@ const c = @import("c.zig"); pub const Bus = @import("au/Bus.zig"); pub const SwapChain = @import("au/SwapChain.zig"); -pub const Flights = @import("au/flights.zig").Flights; +pub const Flights = @import("au/Flights.zig"); pub const VkAllocator = @import("au/VkAllocator.zig"); pub const use_debug_messenger = switch (builtin.mode) { diff --git a/src/au/Flights.zig b/src/au/Flights.zig new file mode 100644 index 0000000..d758170 --- /dev/null +++ b/src/au/Flights.zig @@ -0,0 +1,57 @@ +const std = @import("std"); +const vk = @import("vk"); +const au = @import("../au.zig"); + +const Self = @This(); + +const Flight = struct { + acquire: vk.Semaphore = .null_handle, + complete: vk.Semaphore = .null_handle, + fence: vk.Fence = .null_handle, + pool: vk.CommandPool = .null_handle, + cmd: vk.CommandBuffer = .null_handle, +}; + +alloc: std.mem.Allocator, +flights: []Flight, +idx: usize, + +pub fn init(alloc: std.mem.Allocator, n: usize) !Self { + var self: Self = .{ + .alloc = alloc, + .flights = try alloc.alloc(Flight, n), + .idx = 0, + }; + errdefer self.deinit(); + + for (self.flights) |*flight| { + flight.acquire = try au.D.createSemaphore(&.{}, null); + flight.complete = try au.D.createSemaphore(&.{}, null); + flight.fence = try au.D.createFence(&.{ .flags = .{ .signaled_bit = true } }, null); + flight.pool = try au.D.createCommandPool(&.{ .queue_family_index = au.device_config.family }, null); + try au.D.allocateCommandBuffers(&vk.CommandBufferAllocateInfo{ + .command_buffer_count = 1, + .command_pool = flight.pool, + .level = .primary, + }, @ptrCast(&flight.cmd)); + } + + return self; +} + +pub fn deinit(self: Self) void { + for (self.flights) |flight| { + au.D.destroySemaphore(flight.acquire, null); + au.D.destroySemaphore(flight.complete, null); + au.D.destroyFence(flight.fence, null); + au.D.freeCommandBuffers(flight.pool, 1, &.{flight.cmd}); + au.D.destroyCommandPool(flight.pool, null); + } + self.alloc.free(self.flights); +} + +pub fn next(self: *Self) Flight { + const idx = self.idx; + self.idx = (self.idx + 1) % self.flights.len; + return self.flights[idx]; +} diff --git a/src/au/SwapChain.zig b/src/au/SwapChain.zig index 9f451d2..bca6d60 100644 --- a/src/au/SwapChain.zig +++ b/src/au/SwapChain.zig @@ -101,3 +101,86 @@ pub fn getImage(self: Self, idx: u32) vk.Image { pub fn getView(self: Self, idx: u32) vk.ImageView { return self.views.items[idx]; } + +pub fn beginRendering(self: Self, cmd: au.CommandBufferProxy, area: vk.Rect2D, idx: u32) void { + cmd.pipelineBarrier( + .{ .top_of_pipe_bit = true }, + .{ .color_attachment_output_bit = true }, + .{}, + 0, + null, + 0, + null, + 1, + &.{ + vk.ImageMemoryBarrier{ + .src_access_mask = .{}, + .dst_access_mask = .{ .color_attachment_write_bit = true }, + .old_layout = .undefined, + .new_layout = .color_attachment_optimal, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = self.getImage(idx), + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }, + }, + ); + + cmd.beginRendering(&vk.RenderingInfo{ + .render_area = area, + .layer_count = 1, + .view_mask = 0, + .color_attachment_count = 1, + .p_color_attachments = &.{ + vk.RenderingAttachmentInfo{ + .image_view = self.getView(idx), + .image_layout = .color_attachment_optimal, + .resolve_mode = .{}, + .resolve_image_view = .null_handle, + .resolve_image_layout = .undefined, + .load_op = .clear, + .store_op = .store, + .clear_value = .{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } }, + }, + }, + }); +} + +pub fn endRendering(self: Self, cmd: au.CommandBufferProxy, idx: u32) void { + cmd.endRendering(); + + cmd.pipelineBarrier( + .{ .color_attachment_output_bit = true }, + .{ .bottom_of_pipe_bit = true }, + .{}, + 0, + null, + 0, + null, + 1, + &.{ + vk.ImageMemoryBarrier{ + .src_access_mask = .{ .color_attachment_write_bit = true }, + .dst_access_mask = .{}, + .old_layout = .color_attachment_optimal, + .new_layout = .present_src_khr, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = self.getImage(idx), + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }, + }, + ); +} diff --git a/src/au/flights.zig b/src/au/flights.zig deleted file mode 100644 index 86825c3..0000000 --- a/src/au/flights.zig +++ /dev/null @@ -1,64 +0,0 @@ -const std = @import("std"); -const vk = @import("vk"); -const au = @import("../au.zig"); - -pub fn Flights(T: type) type { - return struct { - const Self = @This(); - - const Flight = struct { - acquire: vk.Semaphore = .null_handle, - complete: vk.Semaphore = .null_handle, - fence: vk.Fence = .null_handle, - pool: vk.CommandPool = .null_handle, - cmd: vk.CommandBuffer = .null_handle, - ctx: T, - }; - - alloc: std.mem.Allocator, - flights: []Flight, - idx: usize, - - pub fn init(alloc: std.mem.Allocator, n: usize) !Self { - var self: Self = .{ - .alloc = alloc, - .flights = try alloc.alloc(Flight, n), - .idx = 0, - }; - errdefer self.deinit(); - - for (self.flights) |*flight| { - flight.acquire = try au.D.createSemaphore(&.{}, null); - flight.complete = try au.D.createSemaphore(&.{}, null); - flight.fence = try au.D.createFence(&.{ .flags = .{ .signaled_bit = true } }, null); - flight.pool = try au.D.createCommandPool(&.{ .queue_family_index = au.device_config.family }, null); - try au.D.allocateCommandBuffers(&vk.CommandBufferAllocateInfo{ - .command_buffer_count = 1, - .command_pool = flight.pool, - .level = .primary, - }, @ptrCast(&flight.cmd)); - flight.ctx = try T.init(); - } - - return self; - } - - pub fn deinit(self: Self) void { - for (self.flights) |flight| { - au.D.destroySemaphore(flight.acquire, null); - au.D.destroySemaphore(flight.complete, null); - au.D.destroyFence(flight.fence, null); - au.D.freeCommandBuffers(flight.pool, 1, &.{flight.cmd}); - au.D.destroyCommandPool(flight.pool, null); - flight.ctx.deinit(); - } - self.alloc.free(self.flights); - } - - pub fn next(self: *Self) Flight { - const idx = self.idx; - self.idx = (self.idx + 1) % self.flights.len; - return self.flights[idx]; - } - }; -} diff --git a/src/main.zig b/src/main.zig index ccd4d87..6fd5d86 100644 --- a/src/main.zig +++ b/src/main.zig @@ -24,7 +24,7 @@ const vertices = [_]Uber.Vertex{ const indices = [_]Uber.Index{ 4, 5, 6, 6, 5, 7 }; const uniform = Uber.Uniform{ - .proj = .{ + .mat = .{ 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, @@ -32,157 +32,30 @@ const uniform = Uber.Uniform{ }, }; -const Frame = struct { - pub fn init() !Frame { - return .{}; - } +fn record_render( + cmd: au.CommandBufferProxy, + uber: Uber, + area: vk.Rect2D, // render area, scissor, and viewport. + vertex_buffer: vk.Buffer, + index_buffer: vk.Buffer, + descriptor_set: vk.DescriptorSet, +) void { + cmd.setViewport(0, 1, &.{.{ + .x = @floatFromInt(area.offset.x), + .y = @floatFromInt(area.offset.y), + .width = @floatFromInt(area.extent.width), + .height = @floatFromInt(area.extent.height), + .min_depth = 0, + .max_depth = 1, + }}); + cmd.setScissor(0, 1, &.{area}); - pub fn deinit(self: Frame) void { - _ = self; - } - - pub fn record_render( - self: Frame, - cmd: au.CommandBufferProxy, - image: vk.Image, - view: vk.ImageView, - scissor: vk.Rect2D, - pipeline: vk.Pipeline, - layout: vk.PipelineLayout, - vertex_buffer: vk.Buffer, - index_buffer: vk.Buffer, - uniform_buffer: vk.Buffer, - descriptor_set: vk.DescriptorSet, - ) !void { - _ = self; - - cmd.pipelineBarrier( - .{ .top_of_pipe_bit = true }, - .{ .color_attachment_output_bit = true }, - .{}, - 0, - null, - 0, - null, - 1, - @ptrCast(&vk.ImageMemoryBarrier{ - .src_access_mask = .{}, - .dst_access_mask = .{ .color_attachment_write_bit = true }, - .old_layout = .undefined, - .new_layout = .color_attachment_optimal, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - .image = image, - .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }, - }), - ); - - const info = vk.RenderingInfoKHR{ - .render_area = scissor, - .layer_count = 1, - .view_mask = 0, - .color_attachment_count = 1, - .p_color_attachments = &.{vk.RenderingAttachmentInfo{ - .image_view = view, - .image_layout = .color_attachment_optimal, - .resolve_mode = .{}, - .resolve_image_view = .null_handle, - .resolve_image_layout = .undefined, - .load_op = .clear, - .store_op = .store, - .clear_value = .{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } }, - }}, - }; - - cmd.setViewport(0, 1, &.{.{ - .x = @floatFromInt(scissor.offset.x), - .y = @floatFromInt(scissor.offset.y), - .width = @floatFromInt(scissor.extent.width), - .height = @floatFromInt(scissor.extent.height), - .min_depth = 0, - .max_depth = 1, - }}); - cmd.setScissor(0, 1, &.{scissor}); - - cmd.beginRendering(&info); - - cmd.bindDescriptorSets(.graphics, layout, 0, 1, &.{descriptor_set}, 0, null); - cmd.bindPipeline(.graphics, pipeline); - cmd.bindVertexBuffers(0, 1, &.{vertex_buffer}, &.{0}); - cmd.bindIndexBuffer(index_buffer, 0, .uint16); - cmd.drawIndexed(indices.len, 1, 0, 0, 0); - - im.c.ImGui_ImplVulkan_RenderDrawData(im.c.igGetDrawData(), @ptrFromInt(@intFromEnum(cmd.handle)), null); - - cmd.endRendering(); - - // vulkan implicitly ensures the host writes all data before the host reads it - // be sure the shader reads all the vertex data before the host might modify it - cmd.pipelineBarrier( - .{ .all_graphics_bit = true }, - .{ .host_bit = true }, - .{}, - 0, - null, - 2, - &.{ - vk.BufferMemoryBarrier{ - .buffer = vertex_buffer, - .src_access_mask = .{ .shader_read_bit = true }, - .dst_access_mask = .{ .host_write_bit = true }, - .offset = 0, - .size = vk.WHOLE_SIZE, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - }, - vk.BufferMemoryBarrier{ - .buffer = uniform_buffer, - .src_access_mask = .{ .shader_read_bit = true }, - .dst_access_mask = .{ .host_write_bit = true }, - .offset = 0, - .size = vk.WHOLE_SIZE, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - }, - }, - 0, - null, - ); - - cmd.pipelineBarrier( - .{ .color_attachment_output_bit = true }, - .{ .bottom_of_pipe_bit = true }, - .{}, - 0, - null, - 0, - null, - 1, - @ptrCast(&vk.ImageMemoryBarrier{ - .src_access_mask = .{ .color_attachment_write_bit = true }, - .dst_access_mask = .{}, - .old_layout = .color_attachment_optimal, - .new_layout = .present_src_khr, - .src_queue_family_index = 0, - .dst_queue_family_index = 0, - .image = image, - .subresource_range = .{ - .aspect_mask = .{ .color_bit = true }, - .base_mip_level = 0, - .level_count = 1, - .base_array_layer = 0, - .layer_count = 1, - }, - }), - ); - } -}; + cmd.bindPipeline(.graphics, uber.pipeline); + cmd.bindDescriptorSets(.graphics, uber.layout, 0, 1, &.{descriptor_set}, 0, null); + cmd.bindVertexBuffers(0, 1, &.{vertex_buffer}, &.{0}); + cmd.bindIndexBuffer(index_buffer, 0, .uint16); + cmd.drawIndexed(indices.len, 1, 0, 0, 0); +} pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction { return c.glfwGetInstanceProcAddress(au.I.handle, procname); @@ -199,7 +72,7 @@ pub fn main() !void { var sc = try au.SwapChain.init(alloc); defer sc.deinit(); - var flights = try au.Flights(Frame).init(alloc, 3); // FRAMES IN FLIGHT + var flights = try au.Flights.init(alloc, 3); // FRAMES IN FLIGHT defer flights.deinit(); const ctx = im.c.igCreateContext(null) orelse return error.igCreateContextFailed; @@ -328,8 +201,8 @@ pub fn main() !void { .dst_array_element = 0, .descriptor_type = .uniform_buffer, .descriptor_count = 1, - .p_image_info = &[0]vk.DescriptorImageInfo{}, - .p_texel_buffer_view = &[0]vk.BufferView{}, + .p_image_info = undefined, + .p_texel_buffer_view = undefined, .p_buffer_info = &.{ vk.DescriptorBufferInfo{ .buffer = uniform_buffer, @@ -381,25 +254,26 @@ pub fn main() !void { flight.acquire, .null_handle, ); - const image = sc.getImage(acq.image_index); - const view = sc.getView(acq.image_index); var cmd = au.CommandBufferProxy.init(flight.cmd, au.D.wrapper); - try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); - try flight.ctx.record_render( + const render_area: vk.Rect2D = .{ + .offset = .{ .x = 0, .y = 0 }, + .extent = sc.cinfo.image_extent, + }; + + sc.beginRendering(cmd, render_area, acq.image_index); + record_render( cmd, - image, - view, - vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = sc.cinfo.image_extent }, - uber.pipeline, - uber.layout, + uber, + render_area, vertex_buffer, index_buffer, - uniform_buffer, descriptorSet, ); + im.c.ImGui_ImplVulkan_RenderDrawData(im.c.igGetDrawData(), @ptrFromInt(@intFromEnum(cmd.handle)), null); + sc.endRendering(cmd, acq.image_index); for (vertex_data) |*v| { for (v.pos[0..2]) |*f| { diff --git a/src/shaders/triangle.vert b/src/shaders/triangle.vert index f98be1c..cf7aed7 100644 --- a/src/shaders/triangle.vert +++ b/src/shaders/triangle.vert @@ -1,7 +1,7 @@ #version 450 layout (set = 0, binding = 0) uniform CameraBuffer { - mat4 viewproj; + mat4 mat; } cam; layout (location = 0) in vec4 a_pos; @@ -10,6 +10,6 @@ layout (location = 1) in vec3 a_color; layout (location = 0) out vec3 v_color; void main() { - gl_Position = a_pos * cam.viewproj; + gl_Position = a_pos * cam.mat; v_color = a_color; }