diff --git a/src/soft/SoftCommandPool.zig b/src/soft/SoftCommandPool.zig index 8868c82..46c82cb 100644 --- a/src/soft/SoftCommandPool.zig +++ b/src/soft/SoftCommandPool.zig @@ -2,9 +2,12 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const NonDispatchable = base.NonDispatchable; const VkError = base.VkError; const Device = base.Device; +const SoftCommandBuffer = @import("SoftCommandBuffer.zig"); + const Self = @This(); pub const Interface = base.CommandPool; @@ -28,10 +31,18 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v return self; } -pub fn allocateCommandBuffers(interface: *Interface, info: *const vk.CommandBufferAllocateInfo) VkError![]*base.CommandBuffer { - _ = interface; - _ = info; - return VkError.FeatureNotPresent; +pub fn allocateCommandBuffers(interface: *Interface, info: *const vk.CommandBufferAllocateInfo) VkError!void { + const allocator = interface.host_allocator.allocator(); + + while (interface.buffers.capacity < interface.buffers.items.len + info.command_buffer_count) { + interface.buffers.ensureUnusedCapacity(allocator, base.CommandPool.BUFFER_POOL_BASE_CAPACITY) catch return VkError.OutOfHostMemory; + } + + for (0..info.command_buffer_count) |_| { + const cmd = try SoftCommandBuffer.create(interface.owner, allocator, info); + const non_dis_cmd = try NonDispatchable(base.CommandBuffer).wrap(allocator, &cmd.interface); + interface.buffers.appendAssumeCapacity(non_dis_cmd); + } } pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { diff --git a/src/soft/SoftPhysicalDevice.zig b/src/soft/SoftPhysicalDevice.zig index d0a84e3..8da35d2 100644 --- a/src/soft/SoftPhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -7,6 +7,7 @@ const cpuinfo = @import("cpuinfo"); const SoftDevice = @import("SoftDevice.zig"); const VkError = base.VkError; +const VulkanAllocator = base.VulkanAllocator; const Self = @This(); pub const Interface = base.PhysicalDevice; @@ -14,6 +15,8 @@ pub const Interface = base.PhysicalDevice; interface: Interface, pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkError!*Self { + const command_allocator = VulkanAllocator.from(allocator).cloneWithScope(.command).allocator(); + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; errdefer allocator.destroy(self); @@ -81,8 +84,8 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr interface.queue_family_props.appendSlice(allocator, queue_family_props[0..]) catch return VkError.OutOfHostMemory; // TODO: use Pytorch's cpuinfo someday - const info = cpuinfo.get(allocator) catch return VkError.InitializationFailed; - defer info.deinit(allocator); + const info = cpuinfo.get(command_allocator) catch return VkError.InitializationFailed; + defer info.deinit(command_allocator); var writer = std.Io.Writer.fixed(interface.props.device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); writer.print("{s} [" ++ root.DRIVER_NAME ++ " StrollDriver]", .{info.name}) catch return VkError.InitializationFailed; diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 15123c8..55d5ab7 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -25,5 +25,6 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma } pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + std.debug.print("{any}\n", .{self}); self.vtable.destroy(self, allocator); } diff --git a/src/vulkan/CommandPool.zig b/src/vulkan/CommandPool.zig index 7bd014b..8e7a3cc 100644 --- a/src/vulkan/CommandPool.zig +++ b/src/vulkan/CommandPool.zig @@ -3,25 +3,32 @@ const vk = @import("vulkan"); const VkError = @import("error_set.zig").VkError; const VulkanAllocator = @import("VulkanAllocator.zig"); +const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; + const CommandBuffer = @import("CommandBuffer.zig"); const Device = @import("Device.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .command_pool; -const BUFFER_POOL_BASE_CAPACITY = 64; +pub const BUFFER_POOL_BASE_CAPACITY = 64; owner: *Device, flags: vk.CommandPoolCreateFlags, queue_family_index: u32, -buffers: std.ArrayList(*CommandBuffer), -first_free_buffer_index: usize, host_allocator: VulkanAllocator, +/// Contiguous dynamic array of command buffers with free ones +/// grouped at the end and the first free index being storesd in +/// `first_free_buffer_index` +/// When freed swaps happen to keep the free buffers at the end +buffers: std.ArrayList(*NonDispatchable(CommandBuffer)), +first_free_buffer_index: usize, + vtable: *const VTable, pub const VTable = struct { - allocateCommandBuffers: *const fn (*Self, *const vk.CommandBufferAllocateInfo) VkError![]*CommandBuffer, + allocateCommandBuffers: *const fn (*Self, *const vk.CommandBufferAllocateInfo) VkError!void, destroy: *const fn (*Self, std.mem.Allocator) void, reset: *const fn (*Self, vk.CommandPoolResetFlags) VkError!void, }; @@ -31,18 +38,29 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma .owner = device, .flags = info.flags, .queue_family_index = info.queue_family_index, - .buffers = std.ArrayList(*CommandBuffer).initCapacity(allocator, BUFFER_POOL_BASE_CAPACITY) catch return VkError.OutOfHostMemory, .host_allocator = VulkanAllocator.from(allocator).clone(), + .buffers = std.ArrayList(*NonDispatchable(CommandBuffer)).initCapacity(allocator, BUFFER_POOL_BASE_CAPACITY) catch return VkError.OutOfHostMemory, .first_free_buffer_index = 0, .vtable = undefined, }; } -pub inline fn allocateCommandBuffers(self: *Self, info: *const vk.CommandBufferAllocateInfo) VkError![]*CommandBuffer { - return self.vtable.allocateCommandBuffers(self, info); +pub fn allocateCommandBuffers(self: *Self, info: *const vk.CommandBufferAllocateInfo) VkError![]*NonDispatchable(CommandBuffer) { + if (self.buffers.items.len < info.command_buffer_count or self.first_free_buffer_index + info.command_buffer_count > self.buffers.items.len) { + try self.vtable.allocateCommandBuffers(self, info); + } + + const bound_up = self.first_free_buffer_index + info.command_buffer_count; + const slice = self.buffers.items[self.first_free_buffer_index..bound_up]; + self.first_free_buffer_index += info.command_buffer_count; + return slice; } pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + for (self.buffers.items) |non_dis_cmd| { + non_dis_cmd.object.destroy(allocator); + non_dis_cmd.destroy(allocator); + } self.buffers.deinit(allocator); self.vtable.destroy(self, allocator); } diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index 78bde2e..0f26dd8 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -2,6 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const Dispatchable = @import("Dispatchable.zig").Dispatchable; +const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; @@ -29,7 +30,7 @@ pub const VTable = struct { }; pub const DispatchTable = struct { - allocateCommandBuffers: *const fn (*Self, *const vk.CommandBufferAllocateInfo) VkError![]*CommandBuffer, + allocateCommandBuffers: *const fn (*Self, *const vk.CommandBufferAllocateInfo) VkError![]*NonDispatchable(CommandBuffer), allocateMemory: *const fn (*Self, std.mem.Allocator, *const vk.MemoryAllocateInfo) VkError!*DeviceMemory, createCommandPool: *const fn (*Self, std.mem.Allocator, *const vk.CommandPoolCreateInfo) VkError!*CommandPool, createFence: *const fn (*Self, std.mem.Allocator, *const vk.FenceCreateInfo) VkError!*Fence, @@ -112,7 +113,7 @@ pub inline fn waitForFences(self: *Self, fences: []*Fence, waitForAll: bool, tim // Command Pool functions ============================================================================================================================ -pub inline fn allocateCommandBuffers(self: *Self, info: *const vk.CommandBufferAllocateInfo) VkError![]*CommandBuffer { +pub inline fn allocateCommandBuffers(self: *Self, info: *const vk.CommandBufferAllocateInfo) VkError![]*NonDispatchable(CommandBuffer) { return self.dispatch_table.allocateCommandBuffers(self, info); } diff --git a/src/vulkan/Instance.zig b/src/vulkan/Instance.zig index 45b0eea..76a3c76 100644 --- a/src/vulkan/Instance.zig +++ b/src/vulkan/Instance.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const vk = @import("vulkan"); + const VkError = @import("error_set.zig").VkError; const Dispatchable = @import("Dispatchable.zig").Dispatchable; const PhysicalDevice = @import("PhysicalDevice.zig"); diff --git a/src/vulkan/NonDispatchable.zig b/src/vulkan/NonDispatchable.zig index d0955fc..8af166f 100644 --- a/src/vulkan/NonDispatchable.zig +++ b/src/vulkan/NonDispatchable.zig @@ -36,16 +36,16 @@ pub fn NonDispatchable(comptime T: type) type { if (handle == 0) { return VkError.Unknown; } - const nondispatchable: *Self = @ptrFromInt(handle); - if (nondispatchable.object_type != T.ObjectType) { + const non_dispatchable: *Self = @ptrFromInt(handle); + if (non_dispatchable.object_type != T.ObjectType) { return VkError.Unknown; } - return nondispatchable; + return non_dispatchable; } pub inline fn fromHandleObject(handle: anytype) VkError!*T { - const nondispatchable_handle = try Self.fromHandle(handle); - return nondispatchable_handle.object; + const non_dispatchable_handle = try Self.fromHandle(handle); + return non_dispatchable_handle.object; } }; } diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index bcf98a4..da7c9f7 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -290,12 +290,9 @@ pub export fn strollAllocateCommandBuffers(p_device: vk.Device, p_info: ?*const return .error_validation_failed; } const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); - const pool = NonDispatchable(CommandPool).fromHandleObject(info.command_pool) catch |err| return toVkResult(err); - const allocator = pool.host_allocator.allocator(); - const cmds = device.allocateCommandBuffers(info) catch |err| return toVkResult(err); for (cmds[0..info.command_buffer_count], 0..) |cmd, i| { - p_cmds[i] = (NonDispatchable(CommandBuffer).wrap(allocator, cmd) catch |err| return toVkResult(err)).toVkHandle(vk.CommandBuffer); + p_cmds[i] = cmd.toVkHandle(vk.CommandBuffer); } return .success; } @@ -336,6 +333,15 @@ pub export fn strollCreateFence(p_device: vk.Device, p_info: ?*const vk.FenceCre return .success; } +pub export fn strollDestroyCommandPool(p_device: vk.Device, p_pool: vk.CommandPool, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch return; + const non_dispatchable_pool = NonDispatchable(CommandPool).fromHandle(p_pool) catch return; + + device.destroyCommandPool(allocator, non_dispatchable_pool.object) catch return; + non_dispatchable_pool.destroy(allocator); +} + pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const dispatchable = Dispatchable(Device).fromHandle(p_device) catch return; @@ -347,15 +353,6 @@ pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.All dispatchable.destroy(allocator); } -pub export fn strollDestroyCommandPool(p_device: vk.Device, p_pool: vk.CommandPool, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { - const allocator = VulkanAllocator.init(callbacks, .object).allocator(); - const device = Dispatchable(Device).fromHandleObject(p_device) catch return; - const non_dispatchable_pool = NonDispatchable(CommandPool).fromHandle(p_pool) catch return; - - device.destroyCommandPool(allocator, non_dispatchable_pool.object) catch return; - non_dispatchable_pool.destroy(allocator); -} - pub export fn strollDestroyFence(p_device: vk.Device, p_fence: vk.Fence, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch return;