273 lines
10 KiB
Zig
273 lines
10 KiB
Zig
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);
|
|
}
|