CommandBuffer wrapper
This commit is contained in:
272
src/engine/CommandBuffer.zig
Normal file
272
src/engine/CommandBuffer.zig
Normal file
@@ -0,0 +1,272 @@
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const QueueType = @import("QueueType.zig").QueueType;
|
||||
const Transient = @import("Transient.zig").Transient;
|
||||
const WaitSemaphore = @import("WaitSemaphore.zig");
|
||||
|
||||
pub const DrawIndexed = struct {
|
||||
index_count: u32,
|
||||
instance_count: u32 = 1,
|
||||
first_index: u32 = 0,
|
||||
vertex_offset: i32 = 0,
|
||||
first_instance: u32 = 0,
|
||||
};
|
||||
|
||||
pub const PipelineBarrier = struct {
|
||||
src_stage_mask: vk.PipelineStageFlags,
|
||||
dst_stage_mask: vk.PipelineStageFlags,
|
||||
dependency_flags: vk.DependencyFlags = .{},
|
||||
memory_barriers: []const vk.MemoryBarrier = &.{},
|
||||
buffer_memory_barriers: []const vk.BufferMemoryBarrier = &.{},
|
||||
image_memory_barriers: []const vk.ImageMemoryBarrier = &.{},
|
||||
};
|
||||
|
||||
pub const RenderPassBeginInfo = struct {
|
||||
render_pass: vk.RenderPass,
|
||||
framebuffer: vk.Framebuffer,
|
||||
render_area: vk.Rect2D,
|
||||
clear_values: []const vk.ClearValue = &.{},
|
||||
};
|
||||
|
||||
pub const SubmitInfo = struct {
|
||||
wait_semaphores: []const WaitSemaphore = &.{},
|
||||
signal_semaphores: []const vk.Semaphore = &.{},
|
||||
fence: vk.Fence = .null_handle,
|
||||
};
|
||||
|
||||
pub const VertexBufferBinding = struct {
|
||||
buffer: vk.Buffer,
|
||||
offset: usize,
|
||||
};
|
||||
|
||||
pub fn CommandBuffer(comptime queue_type: QueueType, comptime transient: Transient) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
proxy: vk.CommandBufferProxy,
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
pub fn init(engine: *const Engine) !Self {
|
||||
const handle = try allocateCommandBuffer(engine, queue_type, transient);
|
||||
const proxy: vk.CommandBufferProxy = .init(handle, engine.device.wrapper);
|
||||
const allocator = engine.vk_allocator.allocator;
|
||||
return .{ .proxy = proxy, .allocator = allocator };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, engine: *const Engine) void {
|
||||
freeCommandBuffer(engine, queue_type, transient, self.proxy.handle);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn submit(self: Self, engine: *const Engine, submit_info: SubmitInfo) !void {
|
||||
try submitCommandBuffer(engine, queue_type, self.proxy.handle, submit_info);
|
||||
}
|
||||
|
||||
pub const CommandBufferBeginInfo = struct {
|
||||
flags: vk.CommandBufferUsageFlags = .{
|
||||
.one_time_submit_bit = switch (transient) {
|
||||
.persistent => false,
|
||||
.transient => true,
|
||||
},
|
||||
},
|
||||
inheritance_info: ?vk.CommandBufferInheritanceInfo = null,
|
||||
};
|
||||
|
||||
pub fn beginCommandBuffer(self: Self, begin_info: CommandBufferBeginInfo) !void {
|
||||
try self.proxy.beginCommandBuffer(&.{
|
||||
.flags = begin_info.flags,
|
||||
.p_inheritance_info = if (begin_info.inheritance_info) |*x| x else null,
|
||||
});
|
||||
}
|
||||
|
||||
pub inline fn beginRenderPass(self: Self, render_pass_begin: RenderPassBeginInfo, contents: vk.SubpassContents) void {
|
||||
self.proxy.beginRenderPass(&.{
|
||||
.render_pass = render_pass_begin.render_pass,
|
||||
.framebuffer = render_pass_begin.framebuffer,
|
||||
.render_area = render_pass_begin.render_area,
|
||||
.clear_value_count = @intCast(render_pass_begin.clear_values.len),
|
||||
.p_clear_values = render_pass_begin.clear_values.ptr,
|
||||
}, contents);
|
||||
}
|
||||
|
||||
pub inline fn bindDescriptorSets(
|
||||
self: Self,
|
||||
pipeline_bind_point: vk.PipelineBindPoint,
|
||||
layout: vk.PipelineLayout,
|
||||
first_set: u32,
|
||||
descriptor_sets: []const vk.DescriptorSet,
|
||||
dynamic_offsets: []const u32,
|
||||
) void {
|
||||
self.proxy.bindDescriptorSets(
|
||||
pipeline_bind_point,
|
||||
layout,
|
||||
first_set,
|
||||
@intCast(descriptor_sets.len),
|
||||
descriptor_sets.ptr,
|
||||
@intCast(dynamic_offsets.len),
|
||||
dynamic_offsets.ptr,
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn bindPipeline(self: Self, pipeline_bind_point: vk.PipelineBindPoint, pipeline: vk.Pipeline) void {
|
||||
self.proxy.bindPipeline(pipeline_bind_point, pipeline);
|
||||
}
|
||||
|
||||
pub inline fn bindIndexBuffer(self: Self, buffer: vk.Buffer, offset: u64, index_type: vk.IndexType) void {
|
||||
self.proxy.bindIndexBuffer(buffer, offset, index_type);
|
||||
}
|
||||
|
||||
pub inline fn bindVertexBuffers(self: Self, first_binding: u32, bindings: []const VertexBufferBinding) !void {
|
||||
var vertex_buffer_bindings = std.MultiArrayList(VertexBufferBinding){};
|
||||
defer vertex_buffer_bindings.deinit(self.allocator);
|
||||
try vertex_buffer_bindings.ensureTotalCapacity(self.allocator, bindings.len);
|
||||
|
||||
for (bindings) |binding| {
|
||||
vertex_buffer_bindings.appendAssumeCapacity(binding);
|
||||
}
|
||||
|
||||
self.proxy.bindVertexBuffers(
|
||||
first_binding,
|
||||
@intCast(vertex_buffer_bindings.len),
|
||||
vertex_buffer_bindings.items(.buffer).ptr,
|
||||
vertex_buffer_bindings.items(.offset).ptr,
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn drawIndexed(self: Self, draw_indexed: DrawIndexed) void {
|
||||
self.proxy.drawIndexed(
|
||||
draw_indexed.index_count,
|
||||
draw_indexed.instance_count,
|
||||
draw_indexed.first_index,
|
||||
draw_indexed.vertex_offset,
|
||||
draw_indexed.first_instance,
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn endCommandBuffer(self: Self) !void {
|
||||
try self.proxy.endCommandBuffer();
|
||||
}
|
||||
|
||||
pub inline fn endRenderPass(self: Self) void {
|
||||
self.proxy.endRenderPass();
|
||||
}
|
||||
|
||||
pub inline fn copyBuffer(
|
||||
self: Self,
|
||||
src_buffer: vk.Buffer,
|
||||
dst_buffer: vk.Buffer,
|
||||
regions: []const vk.BufferCopy,
|
||||
) void {
|
||||
self.proxy.copyBuffer(src_buffer, dst_buffer, @intCast(regions.len), regions.ptr);
|
||||
}
|
||||
|
||||
pub inline fn copyBufferToImage(
|
||||
self: Self,
|
||||
src_buffer: vk.Buffer,
|
||||
dst_image: vk.Image,
|
||||
dst_image_layout: vk.ImageLayout,
|
||||
regions: []const vk.BufferImageCopy,
|
||||
) void {
|
||||
self.proxy.copyBufferToImage(src_buffer, dst_image, dst_image_layout, @intCast(regions.len), regions.ptr);
|
||||
}
|
||||
|
||||
pub inline fn pipelineBarrier(self: Self, barrier: PipelineBarrier) void {
|
||||
self.proxy.pipelineBarrier(
|
||||
barrier.src_stage_mask,
|
||||
barrier.dst_stage_mask,
|
||||
barrier.dependency_flags,
|
||||
@intCast(barrier.memory_barriers.len),
|
||||
barrier.memory_barriers.ptr,
|
||||
@intCast(barrier.buffer_memory_barriers.len),
|
||||
barrier.buffer_memory_barriers.ptr,
|
||||
@intCast(barrier.image_memory_barriers.len),
|
||||
barrier.image_memory_barriers.ptr,
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn setScissor(self: Self, first_scissor: u32, scissors: []const vk.Rect2D) void {
|
||||
self.proxy.setScissor(first_scissor, @intCast(scissors.len), scissors.ptr);
|
||||
}
|
||||
|
||||
pub inline fn setViewport(self: Self, first_viewport: u32, viewports: []const vk.Viewport) void {
|
||||
self.proxy.setViewport(first_viewport, @intCast(viewports.len), viewports.ptr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline fn resolveCommandPool(self: *const Engine, comptime queue_type: QueueType, comptime transient: Transient) vk.CommandPool {
|
||||
return switch (queue_type) {
|
||||
.graphics => switch (transient) {
|
||||
.persistent => self.graphics_command_pool,
|
||||
.transient => self.transient_graphics_command_pool,
|
||||
},
|
||||
.compute => switch (transient) {
|
||||
.persistent => self.compute_command_pool,
|
||||
.transient => self.transient_compute_command_pool,
|
||||
},
|
||||
.transfer => switch (transient) {
|
||||
.persistent => self.transfer_command_pool,
|
||||
.transient => self.transient_transfer_command_pool,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn allocateCommandBuffer(engine: *const Engine, comptime queue_type: QueueType, comptime transient: Transient) !vk.CommandBuffer {
|
||||
const command_pool = resolveCommandPool(engine, queue_type, transient);
|
||||
|
||||
var command_buffers: [1]vk.CommandBuffer = undefined;
|
||||
try engine.device.allocateCommandBuffers(&.{
|
||||
.command_pool = command_pool,
|
||||
.level = .primary,
|
||||
.command_buffer_count = command_buffers.len,
|
||||
}, &command_buffers);
|
||||
|
||||
return command_buffers[0];
|
||||
}
|
||||
|
||||
fn freeCommandBuffer(engine: *const Engine, comptime queue_type: QueueType, comptime transient: Transient, command_buffer: vk.CommandBuffer) void {
|
||||
const command_pool = resolveCommandPool(engine, queue_type, transient);
|
||||
const command_buffers = [_]vk.CommandBuffer{command_buffer};
|
||||
|
||||
engine.device.freeCommandBuffers(command_pool, command_buffers.len, &command_buffers);
|
||||
}
|
||||
|
||||
fn submitCommandBuffer(
|
||||
engine: *const Engine,
|
||||
comptime queue_type: QueueType,
|
||||
command_buffer: vk.CommandBuffer,
|
||||
submit_info: SubmitInfo,
|
||||
) !void {
|
||||
const queue = switch (queue_type) {
|
||||
.graphics => engine.graphics_queue.handle,
|
||||
.compute => engine.compute_queue.handle,
|
||||
.transfer => engine.transfer_queue.handle,
|
||||
};
|
||||
|
||||
const command_buffers = [_]vk.CommandBuffer{command_buffer};
|
||||
|
||||
var wait_semaphores = std.MultiArrayList(WaitSemaphore){};
|
||||
defer wait_semaphores.deinit(engine.vk_allocator.allocator);
|
||||
try wait_semaphores.ensureTotalCapacity(engine.vk_allocator.allocator, submit_info.wait_semaphores.len);
|
||||
|
||||
for (submit_info.wait_semaphores) |wait_semaphore| {
|
||||
wait_semaphores.appendAssumeCapacity(wait_semaphore);
|
||||
}
|
||||
|
||||
const submits = [_]vk.SubmitInfo{
|
||||
.{
|
||||
.wait_semaphore_count = @intCast(wait_semaphores.len),
|
||||
.p_wait_semaphores = wait_semaphores.items(.semaphore).ptr,
|
||||
.p_wait_dst_stage_mask = wait_semaphores.items(.stage_flags).ptr,
|
||||
.command_buffer_count = command_buffers.len,
|
||||
.p_command_buffers = &command_buffers,
|
||||
.signal_semaphore_count = @intCast(submit_info.signal_semaphores.len),
|
||||
.p_signal_semaphores = submit_info.signal_semaphores.ptr,
|
||||
},
|
||||
};
|
||||
|
||||
try engine.device.queueSubmit(queue, submits.len, &submits, submit_info.fence);
|
||||
}
|
||||
Reference in New Issue
Block a user