From b2d964c96a737ae743312d2e1ce116fcd1a38506 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sun, 9 Nov 2025 21:06:33 +0100 Subject: [PATCH] working on queues --- build.zig | 7 ++++--- src/soft/SoftDevice.zig | 12 +++++++++++- src/soft/SoftQueue.zig | 14 ++++++++++++++ src/soft/lib.zig | 5 ++++- src/vulkan/Device.zig | 5 ++++- src/vulkan/Queue.zig | 27 +++++++++++++++++++++++++-- src/vulkan/VulkanAllocator.zig | 6 +++++- src/vulkan/lib.zig | 7 ++++--- src/vulkan/lib_vulkan.zig | 12 ++++++------ test/c/main.c | 28 +++++++--------------------- 10 files changed, 84 insertions(+), 39 deletions(-) create mode 100644 src/soft/SoftQueue.zig diff --git a/build.zig b/build.zig index 21a4191..b448ef7 100644 --- a/build.zig +++ b/build.zig @@ -60,7 +60,7 @@ pub fn build(b: *std.Build) void { .root_module = lib_mod, .linkage = .dynamic, }); - const lib_install_step = b.addInstallArtifact(lib, .{}); + const lib_install = b.addInstallArtifact(lib, .{}); const lib_tests = b.addTest(.{ .root_module = lib_mod }); @@ -87,10 +87,11 @@ pub fn build(b: *std.Build) void { .flags = &.{b.fmt("-DLIBVK=\"{s}\"", .{lib.name})}, }); - b.installArtifact(c_test_exe); + const c_test_exe_install = b.addInstallArtifact(c_test_exe, .{}); const run_c_test = b.addRunArtifact(c_test_exe); - run_c_test.step.dependOn(&lib_install_step.step); + run_c_test.step.dependOn(&lib_install.step); + run_c_test.step.dependOn(&c_test_exe_install.step); const test_c_step = b.step(b.fmt("test-c-{s}", .{impl.name}), b.fmt("Run lib{s} C test", .{impl.name})); test_c_step.dependOn(&run_c_test.step); diff --git a/src/soft/SoftDevice.zig b/src/soft/SoftDevice.zig index fd1501e..7d64664 100644 --- a/src/soft/SoftDevice.zig +++ b/src/soft/SoftDevice.zig @@ -10,8 +10,11 @@ const VkError = base.VkError; const Self = @This(); pub const Interface = base.Device; +const SpawnError = std.Thread.SpawnError; + interface: Interface, device_allocator: std.heap.ThreadSafeAllocator, +workers: std.Thread.Pool, pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; @@ -32,13 +35,20 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato self.* = .{ .interface = interface, - .device_allocator = .{ .child_allocator = std.heap.c_allocator }, // TODO: better device allocator base + .device_allocator = .{ .child_allocator = std.heap.c_allocator }, // TODO: better device allocator + .workers = undefined, + }; + + self.workers.init(.{ .allocator = std.heap.c_allocator }) catch |err| return switch (err) { + SpawnError.OutOfMemory, SpawnError.LockedMemoryLimitExceeded => VkError.OutOfDeviceMemory, + else => VkError.Unknown, }; return self; } pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.workers.deinit(); allocator.destroy(self); } diff --git a/src/soft/SoftQueue.zig b/src/soft/SoftQueue.zig new file mode 100644 index 0000000..324a1e8 --- /dev/null +++ b/src/soft/SoftQueue.zig @@ -0,0 +1,14 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); +const SoftFence = @import("SoftFence.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Queue; + +interface: Interface, +mutex: std.Thread.Mutex, diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 86671f1..123699e 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -4,8 +4,11 @@ pub const base = @import("base"); pub const SoftInstance = @import("SoftInstance.zig"); pub const SoftDevice = @import("SoftDevice.zig"); -pub const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); pub const SoftPhysicalDevice = @import("SoftPhysicalDevice.zig"); +pub const SoftQueue = @import("SoftQueue.zig"); + +pub const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); +pub const SoftFence = @import("SoftFence.zig"); pub const Instance = SoftInstance; diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index 140b6c3..169b73c 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -1,6 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); +const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; const PhysicalDevice = @import("PhysicalDevice.zig"); const DeviceMemory = @import("DeviceMemory.zig"); @@ -11,6 +12,7 @@ pub const ObjectType: vk.ObjectType = .device; physical_device: *const PhysicalDevice, dispatch_table: *const DispatchTable, +host_allocator: VulkanAllocator, pub const DispatchTable = struct { allocateMemory: *const fn (*Self, std.mem.Allocator, *const vk.MemoryAllocateInfo) VkError!*DeviceMemory, @@ -24,11 +26,12 @@ pub const DispatchTable = struct { }; pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice, info: *const vk.DeviceCreateInfo) VkError!Self { - _ = allocator; + const vulkan_allocator: *VulkanAllocator = @ptrCast(@alignCast(allocator.ptr)); _ = info; return .{ .physical_device = physical_device, .dispatch_table = undefined, + .host_allocator = vulkan_allocator.*, }; } diff --git a/src/vulkan/Queue.zig b/src/vulkan/Queue.zig index 99e1908..e1a6a2e 100644 --- a/src/vulkan/Queue.zig +++ b/src/vulkan/Queue.zig @@ -16,7 +16,30 @@ flags: vk.DeviceQueueCreateFlags, dispatch_table: *const DispatchTable, pub const DispatchTable = struct { - bindSparse: *const fn (*Self, u32, *const vk.BindSparseInfo, ?*Fence) VkError!void, - submit: *const fn (*Self, u32, *const vk.SubmitInfo, ?*Fence) VkError!void, + bindSparse: *const fn (*Self, []*const vk.BindSparseInfo, ?*Fence) VkError!void, + submit: *const fn (*Self, []*const vk.SubmitInfo, ?*Fence) VkError!void, waitIdle: *const fn (*Self) VkError!void, }; + +pub fn init(allocator: std.mem.Allocator, device: *const Device, index: u32, info: vk.DeviceQueueCreateInfo) VkError!Self { + _ = allocator; + return .{ + .owner = device, + .family_index = info.queueFamilyIndex, + .index = index, + .flags = info.flags, + .dispatch_table = undefined, + }; +} + +pub inline fn bindSparse(self: *Self, info: []*const vk.BindSparseInfo, fence: ?*Fence) VkError!void { + try self.dispatch_table.bindSparse(self, info, fence); +} + +pub inline fn submit(self: *Self, info: []*const vk.SubmitInfo, fence: ?*Fence) VkError!void { + try self.dispatch_table.submit(self, info, fence); +} + +pub inline fn waitIdle(self: *Self) VkError!void { + try self.dispatch_table.waitIdle(self); +} diff --git a/src/vulkan/VulkanAllocator.zig b/src/vulkan/VulkanAllocator.zig index fecb3e5..abbf000 100644 --- a/src/vulkan/VulkanAllocator.zig +++ b/src/vulkan/VulkanAllocator.zig @@ -22,8 +22,12 @@ pub fn init(callbacks: ?*const vk.AllocationCallbacks, scope: vk.SystemAllocatio pub fn allocator(self: *const Self) Allocator { if (self.callbacks == null) { - return std.heap.c_allocator; // TODO: fallback on a better allocator + return .{ + .ptr = @constCast(self), + .vtable = std.heap.c_allocator.vtable, + }; } + return .{ .ptr = @constCast(self), .vtable = &.{ diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index a8dae2a..19efd44 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -7,14 +7,15 @@ pub const logger = @import("logger.zig"); pub const Dispatchable = @import("Dispatchable.zig").Dispatchable; pub const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; pub const VkError = @import("error_set.zig").VkError; +pub const VulkanAllocator = @import("VulkanAllocator.zig"); pub const Instance = @import("Instance.zig"); pub const Device = @import("Device.zig"); -pub const DeviceMemory = @import("DeviceMemory.zig"); -pub const Fence = @import("Fence.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const Queue = @import("Queue.zig"); -pub const VulkanAllocator = @import("VulkanAllocator.zig"); + +pub const DeviceMemory = @import("DeviceMemory.zig"); +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_LOGS_ENV_NAME = "STROLL_LOGS_LEVEL"; diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 33c01d8..ad7a8be 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -193,7 +193,7 @@ pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, p_info: ? if (info.s_type != .device_create_info) { return .error_validation_failed; } - const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); + const allocator = VulkanAllocator.init(callbacks, .device).allocator(); const physical_device = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err); std.log.scoped(.vkCreateDevice).info("Creating VkDevice from {s}", .{physical_device.props.device_name}); logger.indent(); @@ -271,7 +271,7 @@ pub export fn strollAllocateMemory(p_device: vk.Device, p_info: ?*const vk.Memor if (info.s_type != .memory_allocate_info) { return .error_validation_failed; } - const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); const device_memory = device.allocateMemory(allocator, info) catch |err| return toVkResult(err); p_memory.* = (NonDispatchable(DeviceMemory).wrap(allocator, device_memory) catch |err| return toVkResult(err)).toVkHandle(vk.DeviceMemory); @@ -283,7 +283,7 @@ pub export fn strollCreateFence(p_device: vk.Device, p_info: ?*const vk.FenceCre if (info.s_type != .fence_create_info) { return .error_validation_failed; } - const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); const fence = device.createFence(allocator, info) catch |err| return toVkResult(err); p_fence.* = (NonDispatchable(Fence).wrap(allocator, fence) catch |err| return toVkResult(err)).toVkHandle(vk.Fence); @@ -291,7 +291,7 @@ pub export fn strollCreateFence(p_device: vk.Device, p_info: ?*const vk.FenceCre } pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { - const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const dispatchable = Dispatchable(Device).fromHandle(p_device) catch return; std.log.scoped(.vkDestroyDevice).info("Destroying VkDevice created from {s}", .{dispatchable.object.physical_device.props.device_name}); logger.indent(); @@ -302,7 +302,7 @@ pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.All } 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, .device).allocator(); + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch return; const non_dispatchable_fence = NonDispatchable(Fence).fromHandle(p_fence) catch return; @@ -311,7 +311,7 @@ pub export fn strollDestroyFence(p_device: vk.Device, p_fence: vk.Fence, callbac } pub export fn strollFreeMemory(p_device: vk.Device, p_memory: vk.DeviceMemory, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { - const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch return; const non_dispatchable_device_memory = NonDispatchable(DeviceMemory).fromHandle(p_memory) catch return; diff --git a/test/c/main.c b/test/c/main.c index d854308..6abe95d 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -60,11 +60,8 @@ int main(void) CheckVk(vkCreateInstance(&instance_create_info, NULL, &instance)); volkLoadInstance(instance); - printf("VkInstance %p\n", instance); - uint32_t count; vkEnumeratePhysicalDevices(instance, &count, NULL); - printf("VkPhysicalDevice count %d\n", count); VkPhysicalDevice* physical_devices = (VkPhysicalDevice*)calloc(count, sizeof(VkPhysicalDevice)); vkEnumeratePhysicalDevices(instance, &count, physical_devices); @@ -77,28 +74,17 @@ int main(void) VkDevice device = VK_NULL_HANDLE; CheckVk(vkCreateDevice(physical_devices[0], &device_create_info, NULL, &device)); - printf("VkDevice %p\n", device); volkLoadDevice(device); - VkMemoryAllocateInfo memory_allocate_info = {}; - memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_allocate_info.allocationSize = 512; - memory_allocate_info.memoryTypeIndex = 0; + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + VkFence fence = VK_NULL_HANDLE; + CheckVk(vkCreateFence(device, &fence_info, NULL, &fence)); + printf("VkFence %p\n", fence); - VkDeviceMemory memory = VK_NULL_HANDLE; - CheckVk(vkAllocateMemory(device, &memory_allocate_info, NULL, &memory)); - printf("VkDeviceMemory %p\n", memory); - - void* map; - CheckVk(vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &map)); - const unsigned char data[5] = { 't', 'e', 's', 't', 0x00 }; - memcpy(map, data, 5); - printf("Mapped %p\n", map); - printf("Mapped data: %s\n", (char*)map); - vkUnmapMemory(device, memory); - - vkFreeMemory(device, memory, NULL); + vkDestroyFence(device, fence, NULL); vkDestroyDevice(device, NULL); vkDestroyInstance(instance, NULL);