295 lines
8.9 KiB
Zig
295 lines
8.9 KiB
Zig
//! A thin wrapper around `@import("vk").CommandBufferProxy` that ziggifies
|
|
//! arguments by turning pointer-length pairs into slices and integrates with
|
|
//! different queues from `Engine` struct.
|
|
//!
|
|
//! The wrapper retains information about the queue type, such that it can
|
|
//! submit to the correct queue preallocated in the `Engine` struct when calling
|
|
//! `CommandBuffer.submit`.
|
|
|
|
const CommandBuffer = @This();
|
|
const std = @import("std");
|
|
|
|
const ctx = @import("../AppContext.zig");
|
|
const vk = @import("vulkan");
|
|
|
|
const Engine = @import("Engine.zig");
|
|
const QueueType = @import("QueueType.zig").QueueType;
|
|
|
|
proxy: vk.CommandBufferProxy,
|
|
queue_type: QueueType,
|
|
|
|
pub fn init(queue_type: QueueType) !CommandBuffer {
|
|
const engine = ctx.engine;
|
|
|
|
const handle = try engine.allocateCommandBuffer(.{ .queue_type = queue_type });
|
|
return .{
|
|
.proxy = .init(handle, engine.device.wrapper),
|
|
.queue_type = queue_type,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *CommandBuffer) void {
|
|
const engine = ctx.engine;
|
|
|
|
engine.freeCommandBuffer(.{
|
|
.queue_type = self.queue_type,
|
|
.command_buffer = self.proxy.handle,
|
|
});
|
|
self.* = undefined;
|
|
}
|
|
|
|
pub fn submit(self: CommandBuffer, submit_info: Engine.SubmitInfo) !void {
|
|
const engine = ctx.engine;
|
|
|
|
try engine.queueSubmit(self.queue_type, self.proxy.handle, submit_info);
|
|
}
|
|
|
|
// --- VULKAN WRAPPERS ---------------------------------------------------------
|
|
|
|
fn ToVkType(comptime T: type) type {
|
|
if (!std.meta.hasFn(T, "toVk")) {
|
|
@compileError("Type " ++ T ++ " has no toVk method.");
|
|
}
|
|
|
|
const to_vk_type_info = @typeInfo(@TypeOf(@field(T, "toVk")));
|
|
return to_vk_type_info.@"fn".return_type.?;
|
|
}
|
|
|
|
fn toVkOptional(comptime T: type, maybe_value: ?T) !?*const ToVkType(T) {
|
|
const allocator_frame = ctx.allocator_frame;
|
|
|
|
if (maybe_value) |value| {
|
|
const ptr = try allocator_frame.create(ToVkType(T));
|
|
if (std.meta.hasFn(T, "toVk")) {
|
|
ptr.* = value.toVk();
|
|
}
|
|
return ptr;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
fn toVkMulti(comptime T: type, values: []const T) ![*]const ToVkType(T) {
|
|
const allocator_frame = ctx.allocator_frame;
|
|
|
|
const slice = try allocator_frame.alloc(ToVkType(T), values.len);
|
|
for (slice, values) |*y, x| {
|
|
y.* = x.toVk();
|
|
}
|
|
|
|
return slice.ptr;
|
|
}
|
|
|
|
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 RenderingAttachmentInfo = struct {
|
|
image_view: vk.ImageView = .null_handle,
|
|
image_layout: vk.ImageLayout,
|
|
resolve_mode: vk.ResolveModeFlags = .{},
|
|
resolve_image_view: vk.ImageView = .null_handle,
|
|
resolve_image_layout: vk.ImageLayout = .undefined,
|
|
load_op: vk.AttachmentLoadOp,
|
|
store_op: vk.AttachmentStoreOp,
|
|
clear_value: vk.ClearValue,
|
|
|
|
pub fn toVk(self: RenderingAttachmentInfo) vk.RenderingAttachmentInfo {
|
|
return .{
|
|
.image_view = self.image_view,
|
|
.image_layout = self.image_layout,
|
|
.resolve_mode = self.resolve_mode,
|
|
.resolve_image_view = self.resolve_image_view,
|
|
.resolve_image_layout = self.resolve_image_layout,
|
|
.load_op = self.load_op,
|
|
.store_op = self.store_op,
|
|
.clear_value = self.clear_value,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const RenderingInfo = struct {
|
|
flags: vk.RenderingFlags = .{},
|
|
render_area: vk.Rect2D,
|
|
layer_count: u32,
|
|
view_mask: u32,
|
|
color_attachments: []const RenderingAttachmentInfo = &.{},
|
|
depth_attachment: ?RenderingAttachmentInfo = null,
|
|
stencil_attachment: ?RenderingAttachmentInfo = null,
|
|
|
|
pub fn toVk(self: RenderingInfo) !vk.RenderingInfo {
|
|
return .{
|
|
.flags = self.flags,
|
|
.render_area = self.render_area,
|
|
.layer_count = self.layer_count,
|
|
.view_mask = self.view_mask,
|
|
.color_attachment_count = @intCast(self.color_attachments.len),
|
|
.p_color_attachments = try toVkMulti(RenderingAttachmentInfo, self.color_attachments),
|
|
.p_depth_attachment = try toVkOptional(RenderingAttachmentInfo, self.depth_attachment),
|
|
.p_stencil_attachment = try toVkOptional(RenderingAttachmentInfo, self.stencil_attachment),
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const VertexBufferBinding = struct {
|
|
buffer: vk.Buffer,
|
|
offset: usize,
|
|
|
|
pub fn transpose(vertex_buffer_bindings: []const VertexBufferBinding) !struct { []const vk.Buffer, []const usize } {
|
|
const allocator_frame = ctx.allocator_frame;
|
|
|
|
var t: std.MultiArrayList(VertexBufferBinding) = .empty;
|
|
try t.ensureTotalCapacity(allocator_frame, vertex_buffer_bindings.len);
|
|
|
|
for (vertex_buffer_bindings) |binding| {
|
|
t.appendAssumeCapacity(binding);
|
|
}
|
|
|
|
return .{
|
|
t.items(.buffer),
|
|
t.items(.offset),
|
|
};
|
|
}
|
|
};
|
|
|
|
pub fn beginCommandBuffer(self: CommandBuffer) !void {
|
|
try self.proxy.beginCommandBuffer(&.{
|
|
.flags = .{
|
|
.one_time_submit_bit = true,
|
|
},
|
|
});
|
|
}
|
|
|
|
pub fn beginRendering(self: CommandBuffer, rendering_info: RenderingInfo) !void {
|
|
const rendering_info_vk = try rendering_info.toVk();
|
|
self.proxy.beginRendering(&rendering_info_vk);
|
|
}
|
|
|
|
pub fn bindDescriptorSet(
|
|
self: CommandBuffer,
|
|
pipeline_bind_point: vk.PipelineBindPoint,
|
|
layout: vk.PipelineLayout,
|
|
set: u32,
|
|
descriptor_set: vk.DescriptorSet,
|
|
dynamic_offset: ?u32,
|
|
) void {
|
|
self.bindDescriptorSets(
|
|
pipeline_bind_point,
|
|
layout,
|
|
set,
|
|
&.{descriptor_set},
|
|
if (dynamic_offset) |x| &.{x} else &.{},
|
|
);
|
|
}
|
|
|
|
pub fn bindDescriptorSets(
|
|
self: CommandBuffer,
|
|
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,
|
|
descriptor_sets,
|
|
dynamic_offsets,
|
|
);
|
|
}
|
|
|
|
pub fn bindIndexBuffer(self: CommandBuffer, buffer: vk.Buffer, offset: u64, index_type: vk.IndexType) void {
|
|
self.proxy.bindIndexBuffer(buffer, offset, index_type);
|
|
}
|
|
|
|
pub fn bindPipeline(self: CommandBuffer, pipeline_bind_point: vk.PipelineBindPoint, pipeline: vk.Pipeline) void {
|
|
self.proxy.bindPipeline(pipeline_bind_point, pipeline);
|
|
}
|
|
|
|
pub fn bindVertexBuffer(self: CommandBuffer, index: u32, binding: VertexBufferBinding) !void {
|
|
self.proxy.bindVertexBuffers(index, &.{binding.buffer}, &.{binding.offset});
|
|
}
|
|
|
|
pub fn bindVertexBuffers(self: CommandBuffer, first_binding: u32, bindings: []const VertexBufferBinding) !void {
|
|
const buffers, const offsets = try VertexBufferBinding.transpose(bindings);
|
|
self.proxy.bindVertexBuffers(first_binding, buffers, offsets);
|
|
}
|
|
|
|
pub fn copyBuffer(
|
|
self: CommandBuffer,
|
|
src_buffer: vk.Buffer,
|
|
dst_buffer: vk.Buffer,
|
|
regions: []const vk.BufferCopy,
|
|
) void {
|
|
self.proxy.copyBuffer(src_buffer, dst_buffer, regions);
|
|
}
|
|
|
|
pub fn copyBufferToImage(
|
|
self: CommandBuffer,
|
|
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, regions);
|
|
}
|
|
|
|
pub fn drawIndexed(self: CommandBuffer, 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 fn endCommandBuffer(self: CommandBuffer) !void {
|
|
try self.proxy.endCommandBuffer();
|
|
}
|
|
|
|
pub fn endRendering(self: CommandBuffer) void {
|
|
self.proxy.endRendering();
|
|
}
|
|
|
|
pub fn pipelineBarrier(self: CommandBuffer, barrier: PipelineBarrier) void {
|
|
self.proxy.pipelineBarrier(
|
|
barrier.src_stage_mask,
|
|
barrier.dst_stage_mask,
|
|
barrier.dependency_flags,
|
|
barrier.memory_barriers,
|
|
barrier.buffer_memory_barriers,
|
|
barrier.image_memory_barriers,
|
|
);
|
|
}
|
|
|
|
pub fn setScissor(self: CommandBuffer, index: u32, scissor: vk.Rect2D) void {
|
|
self.proxy.setScissor(index, &.{scissor});
|
|
}
|
|
|
|
pub fn setScissors(self: CommandBuffer, first_scissor: u32, scissors: []const vk.Rect2D) void {
|
|
self.proxy.setScissor(first_scissor, scissors);
|
|
}
|
|
|
|
pub fn setViewport(self: CommandBuffer, index: u32, viewports: vk.Viewport) void {
|
|
self.proxy.setViewport(index, &.{viewports});
|
|
}
|
|
|
|
pub fn setViewports(self: CommandBuffer, first_viewport: u32, viewports: []const vk.Viewport) void {
|
|
self.proxy.setViewport(first_viewport, viewports);
|
|
}
|