better separation of swapchain, flight, and uber

This commit is contained in:
David Allemang
2024-07-08 14:25:10 -04:00
parent 53d063246b
commit 8fd94e631d
7 changed files with 220 additions and 271 deletions

View File

@@ -11,52 +11,42 @@ pipeline: vk.Pipeline,
pub const Index = u16; 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 { pub const Vertex = extern struct {
pos: [4]f32, pos: [4]f32,
color: [3]f32, color: [3]f32,
const InputStateInfo = vk.PipelineVertexInputStateCreateInfo{ const Bindings = [_]vk.VertexInputBindingDescription{
.vertex_binding_description_count = 1, .{
.p_vertex_binding_descriptions = &.{
vk.VertexInputBindingDescription{
.binding = 0, .binding = 0,
.stride = @sizeOf(Vertex), .stride = @sizeOf(Vertex),
.input_rate = .vertex, .input_rate = .vertex,
}, },
}, };
.vertex_attribute_description_count = 2, const Attributes = [_]vk.VertexInputAttributeDescription{
.p_vertex_attribute_descriptions = &.{ .{
vk.VertexInputAttributeDescription{
.binding = 0, .binding = 0,
.location = 0, .location = 0,
.format = .r32g32b32a32_sfloat, .format = .r32g32b32a32_sfloat,
.offset = @offsetOf(Vertex, "pos"), .offset = @offsetOf(Vertex, "pos"),
}, },
vk.VertexInputAttributeDescription{ .{
.binding = 0, .binding = 0,
.location = 1, .location = 1,
.format = .r32g32b32_sfloat, .format = .r32g32b32_sfloat,
.offset = @offsetOf(Vertex, "color"), .offset = @offsetOf(Vertex, "color"),
}, },
},
};
};
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 },
},
},
}; };
}; };
@@ -73,7 +63,11 @@ pub fn init(cache: vk.PipelineCache) !Self {
}, null); }, null);
defer au.D.destroyShaderModule(frag, 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); errdefer au.D.destroyDescriptorSetLayout(set_layout, null);
const layout = try au.D.createPipelineLayout(&vk.PipelineLayoutCreateInfo{ const layout = try au.D.createPipelineLayout(&vk.PipelineLayoutCreateInfo{
@@ -96,7 +90,12 @@ pub fn init(cache: vk.PipelineCache) !Self {
.subpass = 0, .subpass = 0,
.base_pipeline_handle = .null_handle, .base_pipeline_handle = .null_handle,
.base_pipeline_index = -1, .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{ .p_input_assembly_state = &vk.PipelineInputAssemblyStateCreateInfo{
.topology = .triangle_list, .topology = .triangle_list,
.primitive_restart_enable = vk.FALSE, .primitive_restart_enable = vk.FALSE,

View File

@@ -6,7 +6,7 @@ const c = @import("c.zig");
pub const Bus = @import("au/Bus.zig"); pub const Bus = @import("au/Bus.zig");
pub const SwapChain = @import("au/SwapChain.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 VkAllocator = @import("au/VkAllocator.zig");
pub const use_debug_messenger = switch (builtin.mode) { pub const use_debug_messenger = switch (builtin.mode) {

57
src/au/Flights.zig Normal file
View File

@@ -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];
}

View File

@@ -101,3 +101,86 @@ pub fn getImage(self: Self, idx: u32) vk.Image {
pub fn getView(self: Self, idx: u32) vk.ImageView { pub fn getView(self: Self, idx: u32) vk.ImageView {
return self.views.items[idx]; 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,
},
},
},
);
}

View File

@@ -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];
}
};
}

View File

@@ -24,7 +24,7 @@ const vertices = [_]Uber.Vertex{
const indices = [_]Uber.Index{ 4, 5, 6, 6, 5, 7 }; const indices = [_]Uber.Index{ 4, 5, 6, 6, 5, 7 };
const uniform = Uber.Uniform{ const uniform = Uber.Uniform{
.proj = .{ .mat = .{
0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
@@ -32,157 +32,30 @@ const uniform = Uber.Uniform{
}, },
}; };
const Frame = struct { fn record_render(
pub fn init() !Frame {
return .{};
}
pub fn deinit(self: Frame) void {
_ = self;
}
pub fn record_render(
self: Frame,
cmd: au.CommandBufferProxy, cmd: au.CommandBufferProxy,
image: vk.Image, uber: Uber,
view: vk.ImageView, area: vk.Rect2D, // render area, scissor, and viewport.
scissor: vk.Rect2D,
pipeline: vk.Pipeline,
layout: vk.PipelineLayout,
vertex_buffer: vk.Buffer, vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer, index_buffer: vk.Buffer,
uniform_buffer: vk.Buffer,
descriptor_set: vk.DescriptorSet, descriptor_set: vk.DescriptorSet,
) !void { ) 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, &.{.{ cmd.setViewport(0, 1, &.{.{
.x = @floatFromInt(scissor.offset.x), .x = @floatFromInt(area.offset.x),
.y = @floatFromInt(scissor.offset.y), .y = @floatFromInt(area.offset.y),
.width = @floatFromInt(scissor.extent.width), .width = @floatFromInt(area.extent.width),
.height = @floatFromInt(scissor.extent.height), .height = @floatFromInt(area.extent.height),
.min_depth = 0, .min_depth = 0,
.max_depth = 1, .max_depth = 1,
}}); }});
cmd.setScissor(0, 1, &.{scissor}); cmd.setScissor(0, 1, &.{area});
cmd.beginRendering(&info); cmd.bindPipeline(.graphics, uber.pipeline);
cmd.bindDescriptorSets(.graphics, uber.layout, 0, 1, &.{descriptor_set}, 0, null);
cmd.bindDescriptorSets(.graphics, layout, 0, 1, &.{descriptor_set}, 0, null);
cmd.bindPipeline(.graphics, pipeline);
cmd.bindVertexBuffers(0, 1, &.{vertex_buffer}, &.{0}); cmd.bindVertexBuffers(0, 1, &.{vertex_buffer}, &.{0});
cmd.bindIndexBuffer(index_buffer, 0, .uint16); cmd.bindIndexBuffer(index_buffer, 0, .uint16);
cmd.drawIndexed(indices.len, 1, 0, 0, 0); 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,
},
}),
);
} }
};
pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction { pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction {
return c.glfwGetInstanceProcAddress(au.I.handle, procname); return c.glfwGetInstanceProcAddress(au.I.handle, procname);
@@ -199,7 +72,7 @@ pub fn main() !void {
var sc = try au.SwapChain.init(alloc); var sc = try au.SwapChain.init(alloc);
defer sc.deinit(); 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(); defer flights.deinit();
const ctx = im.c.igCreateContext(null) orelse return error.igCreateContextFailed; const ctx = im.c.igCreateContext(null) orelse return error.igCreateContextFailed;
@@ -328,8 +201,8 @@ pub fn main() !void {
.dst_array_element = 0, .dst_array_element = 0,
.descriptor_type = .uniform_buffer, .descriptor_type = .uniform_buffer,
.descriptor_count = 1, .descriptor_count = 1,
.p_image_info = &[0]vk.DescriptorImageInfo{}, .p_image_info = undefined,
.p_texel_buffer_view = &[0]vk.BufferView{}, .p_texel_buffer_view = undefined,
.p_buffer_info = &.{ .p_buffer_info = &.{
vk.DescriptorBufferInfo{ vk.DescriptorBufferInfo{
.buffer = uniform_buffer, .buffer = uniform_buffer,
@@ -381,25 +254,26 @@ pub fn main() !void {
flight.acquire, flight.acquire,
.null_handle, .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); var cmd = au.CommandBufferProxy.init(flight.cmd, au.D.wrapper);
try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); 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, cmd,
image, uber,
view, render_area,
vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = sc.cinfo.image_extent },
uber.pipeline,
uber.layout,
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
uniform_buffer,
descriptorSet, 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 (vertex_data) |*v| {
for (v.pos[0..2]) |*f| { for (v.pos[0..2]) |*f| {

View File

@@ -1,7 +1,7 @@
#version 450 #version 450
layout (set = 0, binding = 0) uniform CameraBuffer { layout (set = 0, binding = 0) uniform CameraBuffer {
mat4 viewproj; mat4 mat;
} cam; } cam;
layout (location = 0) in vec4 a_pos; 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; layout (location = 0) out vec3 v_color;
void main() { void main() {
gl_Position = a_pos * cam.viewproj; gl_Position = a_pos * cam.mat;
v_color = a_color; v_color = a_color;
} }