reworking command buffers, adding soft compute routines
Some checks failed
Build / build (push) Successful in 2m4s
Test / build_and_test (push) Failing after 3h24m26s

This commit is contained in:
2026-02-24 04:49:59 +01:00
parent d97533082d
commit e5cbbbcc91
20 changed files with 630 additions and 374 deletions

View File

@@ -2,8 +2,6 @@ const std = @import("std");
const vk = @import("vulkan");
const lib = @import("lib.zig");
const cmd = @import("commands.zig");
const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable;
const VkError = @import("error_set.zig").VkError;
const VulkanAllocator = @import("VulkanAllocator.zig");
@@ -17,8 +15,6 @@ const Image = @import("Image.zig");
const Pipeline = @import("Pipeline.zig");
const DescriptorSet = @import("DescriptorSet.zig");
const COMMAND_BUFFER_BASE_CAPACITY = 256;
const State = enum {
Initial,
Recording,
@@ -35,7 +31,6 @@ pool: *CommandPool,
state: State,
begin_info: ?vk.CommandBufferBeginInfo,
host_allocator: VulkanAllocator,
commands: std.ArrayList(cmd.Command),
state_mutex: std.Thread.Mutex,
vtable: *const VTable,
@@ -49,6 +44,7 @@ pub const DispatchTable = struct {
copyBuffer: *const fn (*Self, *Buffer, *Buffer, []const vk.BufferCopy) VkError!void,
copyImage: *const fn (*Self, *Image, vk.ImageLayout, *Image, vk.ImageLayout, []const vk.ImageCopy) VkError!void,
copyImageToBuffer: *const fn (*Self, *Image, vk.ImageLayout, *Buffer, []const vk.BufferImageCopy) VkError!void,
dispatch: *const fn (*Self, u32, u32, u32) VkError!void,
end: *const fn (*Self) VkError!void,
fillBuffer: *const fn (*Self, *Buffer, vk.DeviceSize, vk.DeviceSize, u32) VkError!void,
reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void,
@@ -68,7 +64,6 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma
.state = .Initial,
.begin_info = null,
.host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object),
.commands = std.ArrayList(cmd.Command).initCapacity(allocator, COMMAND_BUFFER_BASE_CAPACITY) catch return VkError.OutOfHostMemory,
.state_mutex = .{},
.vtable = undefined,
.dispatch_table = undefined,
@@ -85,8 +80,6 @@ inline fn transitionState(self: *Self, target: State, from_allowed: []const Stat
}
pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void {
self.cleanCommandList();
self.commands.deinit(allocator);
self.vtable.destroy(self, allocator);
}
@@ -109,7 +102,6 @@ pub inline fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void
if (!self.pool.flags.reset_command_buffer_bit) {
return VkError.ValidationFailed;
}
defer self.cleanCommandList();
self.transitionState(.Initial, &.{ .Initial, .Recording, .Executable, .Invalid }) catch return VkError.ValidationFailed;
try self.dispatch_table.reset(self, flags);
@@ -124,101 +116,44 @@ pub inline fn submit(self: *Self) VkError!void {
self.transitionState(.Pending, &.{ .Pending, .Executable }) catch return VkError.ValidationFailed;
}
fn cleanCommandList(self: *Self) void {
const allocator = self.host_allocator.allocator();
for (self.commands.items) |command| {
switch (command) {
.CopyBuffer => |data| allocator.free(data.regions),
.CopyImage => |data| allocator.free(data.regions),
.CopyImageToBuffer => |data| allocator.free(data.regions),
else => {},
}
}
}
// Commands ====================================================================================================
pub inline fn bindDescriptorSets(self: *Self, bind_point: vk.PipelineBindPoint, first_set: u32, sets: []const vk.DescriptorSet, dynamic_offsets: []const u32) VkError!void {
const allocator = self.host_allocator.allocator();
var inner_sets = [_]?*DescriptorSet{null} ** lib.VULKAN_MAX_DESCRIPTOR_SETS;
for (sets, inner_sets[0..sets.len]) |set, *inner_set| {
inner_set.* = try NonDispatchable(DescriptorSet).fromHandleObject(set);
}
try self.dispatch_table.bindDescriptorSets(self, bind_point, first_set, inner_sets, dynamic_offsets);
self.commands.append(allocator, .{ .BindDescriptorSets = .{
.bind_point = bind_point,
.first_set = first_set,
.sets = inner_sets,
.dynamic_offsets = dynamic_offsets,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn bindPipeline(self: *Self, bind_point: vk.PipelineBindPoint, pipeline: *Pipeline) VkError!void {
const allocator = self.host_allocator.allocator();
try self.dispatch_table.bindPipeline(self, bind_point, pipeline);
self.commands.append(allocator, .{ .BindPipeline = .{
.bind_point = bind_point,
.pipeline = pipeline,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn clearColorImage(self: *Self, image: *Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void {
const allocator = self.host_allocator.allocator();
for (ranges) |range| {
try self.dispatch_table.clearColorImage(self, image, layout, color, range);
self.commands.append(allocator, .{ .ClearColorImage = .{
.image = image,
.layout = layout,
.clear_color = color.*,
.range = range,
} }) catch return VkError.OutOfHostMemory;
}
}
pub inline fn copyBuffer(self: *Self, src: *Buffer, dst: *Buffer, regions: []const vk.BufferCopy) VkError!void {
const allocator = self.host_allocator.allocator();
try self.dispatch_table.copyBuffer(self, src, dst, regions);
self.commands.append(allocator, .{ .CopyBuffer = .{
.src = src,
.dst = dst,
.regions = allocator.dupe(vk.BufferCopy, regions) catch return VkError.OutOfHostMemory,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn copyImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void {
const allocator = self.host_allocator.allocator();
try self.dispatch_table.copyImage(self, src, src_layout, dst, dst_layout, regions);
self.commands.append(allocator, .{ .CopyImage = .{
.src = src,
.src_layout = src_layout,
.dst = dst,
.dst_layout = dst_layout,
.regions = allocator.dupe(vk.ImageCopy, regions) catch return VkError.OutOfHostMemory,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn copyImageToBuffer(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Buffer, regions: []const vk.BufferImageCopy) VkError!void {
const allocator = self.host_allocator.allocator();
try self.dispatch_table.copyImageToBuffer(self, src, src_layout, dst, regions);
self.commands.append(allocator, .{ .CopyImageToBuffer = .{
.src = src,
.src_layout = src_layout,
.dst = dst,
.regions = allocator.dupe(vk.BufferImageCopy, regions) catch return VkError.OutOfHostMemory,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn dispatch(self: *Self, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void {
try self.dispatch_table.dispatch(self, group_count_x, group_count_y, group_count_z);
}
pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
const allocator = self.host_allocator.allocator();
try self.dispatch_table.fillBuffer(self, buffer, offset, size, data);
self.commands.append(allocator, .{ .FillBuffer = .{
.buffer = buffer,
.offset = offset,
.size = if (size == vk.WHOLE_SIZE) buffer.size else size,
.data = data,
} }) catch return VkError.OutOfHostMemory;
}
pub inline fn resetEvent(self: *Self, event: *Event, stage: vk.PipelineStageFlags) VkError!void {

View File

@@ -47,11 +47,11 @@ pub fn Dispatchable(comptime T: type) type {
pub inline fn fromHandle(vk_handle: anytype) VkError!*Self {
const handle = @intFromEnum(vk_handle);
if (handle == 0) {
return VkError.ValidationFailed;
return VkError.InvalidHandleDrv;
}
const dispatchable: *Self = @ptrFromInt(handle);
if (dispatchable.object_type != T.ObjectType) {
return VkError.ValidationFailed;
return VkError.InvalidHandleDrv;
}
return dispatchable;
}

View File

@@ -79,11 +79,11 @@ pub inline fn getClearFormat(self: *Self) vk.Format {
.r32g32b32a32_sfloat;
}
pub inline fn getPixelSize(self: *Self) usize {
pub inline fn getPixelSize(self: *const Self) usize {
return lib.vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(self.format)));
}
pub inline fn getTotalSize(self: *Self) usize {
pub inline fn getTotalSize(self: *const Self) usize {
const pixel_size = self.getPixelSize();
return self.extent.width * self.extent.height * self.extent.depth * pixel_size;
}
@@ -92,7 +92,7 @@ pub inline fn getFormatPixelSize(format: vk.Format) usize {
return lib.vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(format)));
}
pub inline fn getFormatTotalSize(self: *Self, format: vk.Format) usize {
pub inline fn getFormatTotalSize(self: *const Self, format: vk.Format) usize {
const pixel_size = self.getFormatPixelSize(format);
return self.extent.width * self.extent.height * self.extent.depth * pixel_size;
}

View File

@@ -42,11 +42,11 @@ pub fn NonDispatchable(comptime T: type) type {
pub inline fn fromHandle(vk_handle: anytype) VkError!*Self {
const handle = @intFromEnum(vk_handle);
if (handle == 0) {
return VkError.ValidationFailed;
return VkError.InvalidHandleDrv;
}
const non_dispatchable: *Self = @ptrFromInt(handle);
if (non_dispatchable.object_type != T.ObjectType) {
return VkError.ValidationFailed;
return VkError.InvalidHandleDrv;
}
return non_dispatchable;
}

View File

@@ -1,94 +0,0 @@
const std = @import("std");
const vk = @import("vulkan");
const lib = @import("lib.zig");
const Buffer = @import("Buffer.zig");
const Image = @import("Image.zig");
const Pipeline = @import("Pipeline.zig");
const DescriptorSet = @import("DescriptorSet.zig");
pub const CommandBindDescriptorSets = struct {
bind_point: vk.PipelineBindPoint,
first_set: u32,
sets: [lib.VULKAN_MAX_DESCRIPTOR_SETS]?*DescriptorSet,
dynamic_offsets: []const u32,
};
pub const CommandBindPipeline = struct {
bind_point: vk.PipelineBindPoint,
pipeline: *Pipeline,
};
pub const CommandBindVertexBuffer = struct {
buffers: []*const Buffer,
offsets: []vk.DeviceSize,
first_binding: u32,
};
pub const CommandClearColorImage = struct {
image: *Image,
layout: vk.ImageLayout,
clear_color: vk.ClearColorValue,
range: vk.ImageSubresourceRange,
};
pub const CommandCopyBuffer = struct {
src: *Buffer,
dst: *Buffer,
regions: []const vk.BufferCopy,
};
pub const CommandCopyImage = struct {
src: *Image,
src_layout: vk.ImageLayout,
dst: *Image,
dst_layout: vk.ImageLayout,
regions: []const vk.ImageCopy,
};
pub const CommandCopyImageToBuffer = struct {
src: *Image,
src_layout: vk.ImageLayout,
dst: *Buffer,
regions: []const vk.BufferImageCopy,
};
pub const CommandDraw = struct {
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
};
pub const CommandDrawIndexed = struct {
index_count: u32,
instance_count: u32,
first_index: u32,
vertex_offset: i32,
first_instance: u32,
};
pub const CommandDrawIndexedIndirect = struct {
buffer: *Buffer,
offset: vk.DeviceSize,
count: u32,
stride: u32,
};
pub const CommandDrawIndirect = struct {
buffer: *Buffer,
offset: vk.DeviceSize,
count: u32,
stride: u32,
};
pub const CommandFillBuffer = struct {
buffer: *Buffer,
offset: vk.DeviceSize,
size: vk.DeviceSize,
data: u32,
};
pub const Command = union(enum) {
BindDescriptorSets: CommandBindDescriptorSets,
BindPipeline: CommandBindPipeline,
BindVertexBuffer: CommandBindVertexBuffer,
ClearColorImage: CommandClearColorImage,
CopyBuffer: CommandCopyBuffer,
CopyImage: CommandCopyImage,
CopyImageToBuffer: CommandCopyImageToBuffer,
Draw: CommandDraw,
DrawIndexed: CommandDrawIndexed,
DrawIndexedIndirect: CommandDrawIndexedIndirect,
DrawIndirect: CommandDrawIndirect,
FillBuffer: CommandFillBuffer,
};

View File

@@ -50,6 +50,10 @@ pub const VkError = error{
IncompatibleShaderBinaryExt,
PipelineBinaryMissingKhr,
NotEnoughSpaceKhr,
// ====== Internal errors
InvalidHandleDrv,
InvalidPipelineDrv,
InvalidDeviceMemoryDrv,
};
pub inline fn errorLogger(err: VkError) void {
@@ -80,7 +84,6 @@ pub inline fn toVkResult(err: VkError) vk.Result {
VkError.TooManyObjects => .error_too_many_objects,
VkError.FormatNotSupported => .error_format_not_supported,
VkError.FragmentedPool => .error_fragmented_pool,
VkError.Unknown => .error_unknown,
VkError.ValidationFailed => .error_validation_failed,
VkError.OutOfPoolMemory => .error_out_of_pool_memory,
VkError.InvalidExternalHandle => .error_invalid_external_handle,
@@ -111,5 +114,7 @@ pub inline fn toVkResult(err: VkError) vk.Result {
VkError.IncompatibleShaderBinaryExt => .incompatible_shader_binary_ext,
VkError.PipelineBinaryMissingKhr => .pipeline_binary_missing_khr,
VkError.NotEnoughSpaceKhr => .error_not_enough_space_khr,
VkError.InvalidHandleDrv => .error_validation_failed,
else => .error_unknown,
};
}

View File

@@ -7,7 +7,6 @@ pub const vku = @cImport({
@cInclude("vulkan/utility/vk_format_utils.h");
});
pub const commands = @import("commands.zig");
pub const errors = @import("error_set.zig");
pub const lib_vulkan = @import("lib_vulkan.zig");
pub const logger = @import("logger/logger.zig");

View File

@@ -1429,7 +1429,7 @@ pub export fn strollGetPipelineCacheData(p_device: vk.Device, p_cache: vk.Pipeli
_ = size;
_ = data;
return .error_unknown;
return .success;
}
pub export fn strollGetQueryPoolResults(
@@ -1699,7 +1699,7 @@ pub export fn strollCmdBindPipeline(p_cmd: vk.CommandBuffer, bind_point: vk.Pipe
defer entryPointEndLogTrace();
const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err);
const pipeline = Dispatchable(Pipeline).fromHandleObject(p_pipeline) catch |err| return errorLogger(err);
const pipeline = NonDispatchable(Pipeline).fromHandleObject(p_pipeline) catch |err| return errorLogger(err);
cmd.bindPipeline(bind_point, pipeline) catch |err| return errorLogger(err);
}
@@ -1860,13 +1860,7 @@ pub export fn strollCmdDispatch(p_cmd: vk.CommandBuffer, group_count_x: u32, gro
defer entryPointEndLogTrace();
const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err);
notImplementedWarning();
_ = cmd;
_ = group_count_x;
_ = group_count_y;
_ = group_count_z;
cmd.dispatch(group_count_x, group_count_y, group_count_z) catch |err| return errorLogger(err);
}
pub export fn strollCmdDispatchIndirect(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer, offset: vk.DeviceSize) callconv(vk.vulkan_call_conv) void {