adding command buffer pool logic

This commit is contained in:
2025-11-15 21:29:08 +01:00
parent fbdce598e3
commit 027bd2ce1c
8 changed files with 65 additions and 33 deletions

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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;
}
};
}

View File

@@ -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;