From 5bfc0e6254afd38ba43f02ee0178386847b3a99d Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Tue, 18 Nov 2025 00:00:11 +0100 Subject: [PATCH] adding command buffer states --- src/soft/SoftCommandBuffer.zig | 6 ++++ src/soft/lib.zig | 4 +++ src/vulkan/CommandBuffer.zig | 56 +++++++++++++++++++++++++++++++++- src/vulkan/Dispatchable.zig | 4 +-- src/vulkan/NonDispatchable.zig | 4 +-- src/vulkan/Queue.zig | 10 ++++++ src/vulkan/lib.zig | 3 -- src/vulkan/lib_vulkan.zig | 7 +++++ test/c/main.c | 11 ++----- 9 files changed, 88 insertions(+), 17 deletions(-) diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 28a67b3..1cf9ce0 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -23,6 +23,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v interface.dispatch_table = &.{ .begin = begin, .end = end, + .reset = reset, }; self.* = .{ @@ -44,3 +45,8 @@ pub fn begin(interface: *Interface, info: *const vk.CommandBufferBeginInfo) VkEr pub fn end(interface: *Interface) VkError!void { _ = interface; } + +pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!void { + _ = interface; + _ = flags; +} diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 0f4692f..9df45f0 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -23,6 +23,10 @@ pub const DEVICE_ID = 0x600DCAFE; pub const std_options = base.std_options; +comptime { + _ = base; +} + test { std.testing.refAllDeclsRecursive(@This()); } diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 226dbed..58aa18b 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -2,12 +2,25 @@ const std = @import("std"); const vk = @import("vulkan"); const VkError = @import("error_set.zig").VkError; +const CommandPool = @import("CommandPool.zig"); const Device = @import("Device.zig"); +const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; + +const State = enum { + Initial, + Recording, + Executable, + Pending, + Invalid, +}; const Self = @This(); pub const ObjectType: vk.ObjectType = .command_buffer; owner: *Device, +pool: *CommandPool, +state: State, +begin_info: ?vk.CommandBufferBeginInfo, vtable: *const VTable, dispatch_table: *const DispatchTable, @@ -15,6 +28,7 @@ dispatch_table: *const DispatchTable, pub const DispatchTable = struct { begin: *const fn (*Self, *const vk.CommandBufferBeginInfo) VkError!void, end: *const fn (*Self) VkError!void, + reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void, }; pub const VTable = struct { @@ -23,22 +37,62 @@ pub const VTable = struct { pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.CommandBufferAllocateInfo) VkError!Self { _ = allocator; - _ = info; return .{ .owner = device, + .pool = try NonDispatchable(CommandPool).fromHandleObject(info.command_pool), + .state = .Initial, + .begin_info = null, .vtable = undefined, .dispatch_table = undefined, }; } +inline fn transitionState(self: *Self, target: State, from_allowed: std.EnumSet(State)) error{NotAllowed}!void { + if (!from_allowed.contains(self.state)) { + return error.NotAllowed; + } + self.state = target; +} + +inline fn transitionStateNotAllowed(self: *Self, target: State, from_not_allowed: std.EnumSet(State)) error{NotAllowed}!void { + if (from_not_allowed.contains(self.state)) { + return error.NotAllowed; + } + self.state = target; +} + pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { self.vtable.destroy(self, allocator); } pub inline fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError!void { + if (!self.pool.flags.reset_command_buffer_bit) { + self.transitionState(.Recording, .initOne(.Initial)) catch return VkError.ValidationFailed; + } else { + self.transitionStateNotAllowed(.Recording, .initMany(&.{ .Recording, .Pending })) catch return VkError.ValidationFailed; + } try self.dispatch_table.begin(self, info); + self.begin_info = info.*; } pub inline fn end(self: *Self) VkError!void { + self.transitionState(.Executable, .initOne(.Recording)) catch return VkError.ValidationFailed; try self.dispatch_table.end(self); } + +pub inline fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void { + if (!self.pool.flags.reset_command_buffer_bit) { + return VkError.ValidationFailed; + } + self.transitionStateNotAllowed(.Initial, .initOne(.Pending)) catch return VkError.ValidationFailed; + try self.dispatch_table.reset(self, flags); +} + +pub inline fn submit(self: *Self) VkError!void { + self.transitionState(.Initial, .initMany(&.{ .Pending, .Executable })) catch return VkError.ValidationFailed; + if (self.begin_info) |begin_info| { + if (!begin_info.flags.simultaneous_use_bit) { + self.transitionStateNotAllowed(.Initial, .initOne(.Pending)) catch return VkError.ValidationFailed; + } + } +} diff --git a/src/vulkan/Dispatchable.zig b/src/vulkan/Dispatchable.zig index b6af105..43da6e4 100644 --- a/src/vulkan/Dispatchable.zig +++ b/src/vulkan/Dispatchable.zig @@ -39,11 +39,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.Unknown; + return VkError.ValidationFailed; } const dispatchable: *Self = @ptrFromInt(handle); if (dispatchable.object_type != T.ObjectType) { - return VkError.Unknown; + return VkError.ValidationFailed; } return dispatchable; } diff --git a/src/vulkan/NonDispatchable.zig b/src/vulkan/NonDispatchable.zig index 8af166f..a75806d 100644 --- a/src/vulkan/NonDispatchable.zig +++ b/src/vulkan/NonDispatchable.zig @@ -34,11 +34,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.Unknown; + return VkError.ValidationFailed; } const non_dispatchable: *Self = @ptrFromInt(handle); if (non_dispatchable.object_type != T.ObjectType) { - return VkError.Unknown; + return VkError.ValidationFailed; } return non_dispatchable; } diff --git a/src/vulkan/Queue.zig b/src/vulkan/Queue.zig index 5bcfa50..5cffdfe 100644 --- a/src/vulkan/Queue.zig +++ b/src/vulkan/Queue.zig @@ -2,7 +2,9 @@ const std = @import("std"); const vk = @import("vulkan"); const VkError = @import("error_set.zig").VkError; +const CommandBuffer = @import("CommandBuffer.zig"); const Device = @import("Device.zig"); +const Dispatchable = @import("Dispatchable.zig").Dispatchable; const Fence = @import("Fence.zig"); const Self = @This(); @@ -39,6 +41,14 @@ pub inline fn bindSparse(self: *Self, info: []const vk.BindSparseInfo, fence: ?* pub inline fn submit(self: *Self, info: []const vk.SubmitInfo, fence: ?*Fence) VkError!void { try self.dispatch_table.submit(self, info, fence); + for (info) |submit_info| { + if (submit_info.p_command_buffers) |p_command_buffers| { + for (p_command_buffers[0..submit_info.command_buffer_count]) |p_cmd| { + const cmd = try Dispatchable(CommandBuffer).fromHandleObject(p_cmd); + try cmd.submit(); + } + } + } } pub inline fn waitIdle(self: *Self) VkError!void { diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 316e405..1375ca8 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -21,9 +21,6 @@ pub const Fence = @import("Fence.zig"); pub const VULKAN_VENDOR_ID = @typeInfo(vk.VendorId).@"enum".fields[@typeInfo(vk.VendorId).@"enum".fields.len - 1].value + 1; -pub const DRIVER_NAME = "VulkanBase"; -pub const VULKAN_VERSION = vk.makeApiVersion(0, 1, 0, 0); - pub const DRIVER_LOGS_ENV_NAME = "STROLL_LOGS_LEVEL"; pub const DRIVER_DEBUG_ALLOCATOR_ENV_NAME = "STROLL_DEBUG_ALLOCATOR"; diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 8f0b0a3..a376d0c 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -89,6 +89,7 @@ const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ functionMapEntryPoint("vkGetFenceStatus"), functionMapEntryPoint("vkMapMemory"), functionMapEntryPoint("vkUnmapMemory"), + functionMapEntryPoint("vkResetCommandBuffer"), functionMapEntryPoint("vkResetFences"), functionMapEntryPoint("vkQueueBindSparse"), functionMapEntryPoint("vkQueueSubmit"), @@ -495,3 +496,9 @@ pub export fn strollEndCommandBuffer(p_cmd: vk.CommandBuffer) callconv(vk.vulkan cmd.end() catch |err| return toVkResult(err); return .success; } + +pub export fn strollResetCommandBuffer(p_cmd: vk.CommandBuffer, flags: vk.CommandBufferResetFlags) callconv(vk.vulkan_call_conv) vk.Result { + const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return toVkResult(err); + cmd.reset(flags) catch |err| return toVkResult(err); + return .success; +} diff --git a/test/c/main.c b/test/c/main.c index 18d07e6..1264e03 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -20,15 +20,6 @@ #define KVF_NO_KHR #include -#define CheckVk(x) \ - do { \ - if((x) != VK_SUCCESS) \ - { \ - fprintf(stderr, "Vulkan call failed %d\n", (x)); \ - abort(); \ - } \ - } while(0) - int main(void) { volkInitialize(); @@ -65,10 +56,12 @@ int main(void) VkFence fence = kvfCreateFence(device); VkCommandBuffer cmd = kvfCreateCommandBuffer(device); + kvfBeginCommandBuffer(cmd, 0); kvfEndCommandBuffer(cmd); kvfSubmitCommandBuffer(device, cmd, KVF_GRAPHICS_QUEUE, VK_NULL_HANDLE, VK_NULL_HANDLE, fence, NULL); + kvfCheckVk(vkResetCommandBuffer(cmd, 0)); kvfWaitForFence(device, fence); kvfDestroyFence(device, fence);