diff --git a/src/soft/SoftDevice.zig b/src/soft/SoftDevice.zig index 5f42840..fd1501e 100644 --- a/src/soft/SoftDevice.zig +++ b/src/soft/SoftDevice.zig @@ -1,8 +1,10 @@ const std = @import("std"); const vk = @import("vulkan"); -const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); const base = @import("base"); +const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); +const SoftFence = @import("SoftFence.zig"); + const VkError = base.VkError; const Self = @This(); @@ -11,16 +13,21 @@ pub const Interface = base.Device; interface: Interface, device_allocator: std.heap.ThreadSafeAllocator, -pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*Self { +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; errdefer allocator.destroy(self); - var interface = try Interface.init(allocator, physical_device, infos); + var interface = try Interface.init(allocator, physical_device, info); interface.dispatch_table = &.{ .allocateMemory = allocateMemory, - .freeMemory = freeMemory, + .createFence = createFence, .destroy = destroy, + .destroyFence = destroyFence, + .freeMemory = freeMemory, + .getFenceStatus = getFenceStatus, + .resetFences = resetFences, + .waitForFences = waitForFences, }; self.* = .{ @@ -30,17 +37,47 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato return self; } -pub fn allocateMemory(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.MemoryAllocateInfo) VkError!*base.DeviceMemory { - const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - const device_memory = try SoftDeviceMemory.create(self, allocator, infos.allocation_size, infos.memory_type_index); - return &device_memory.interface; -} - pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); allocator.destroy(self); } +// Fence functions =================================================================================================================================== + +pub fn createFence(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*base.Fence { + const fence = try SoftFence.create(interface, allocator, info); + return &fence.interface; +} + +pub fn destroyFence(_: *Interface, allocator: std.mem.Allocator, fence: *base.Fence) VkError!void { + fence.destroy(allocator); +} + +pub fn getFenceStatus(_: *Interface, fence: *base.Fence) VkError!void { + try fence.getStatus(); +} + +pub fn resetFences(_: *Interface, fences: []*base.Fence) VkError!void { + for (fences) |fence| { + try fence.reset(); + } +} + +pub fn waitForFences(_: *Interface, fences: []*base.Fence, waitForAll: bool, timeout: u64) VkError!void { + for (fences) |fence| { + try fence.wait(timeout); + if (!waitForAll) return; + } +} + +// Memory functions ================================================================================================================================== + +pub fn allocateMemory(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*base.DeviceMemory { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const device_memory = try SoftDeviceMemory.create(self, allocator, info.allocation_size, info.memory_type_index); + return &device_memory.interface; +} + pub fn freeMemory(_: *Interface, allocator: std.mem.Allocator, device_memory: *base.DeviceMemory) VkError!void { device_memory.destroy(allocator); } diff --git a/src/soft/SoftFence.zig b/src/soft/SoftFence.zig index 58c8195..61b3581 100644 --- a/src/soft/SoftFence.zig +++ b/src/soft/SoftFence.zig @@ -76,8 +76,8 @@ pub fn wait(interface: *Interface, timeout: u64) VkError!void { defer self.mutex.unlock(); if (timeout == std.math.maxInt(@TypeOf(timeout))) { - self.condition.wait(self.mutex); + self.condition.wait(&self.mutex); } else { - self.condition.timedWait(self.mutex, timeout) catch return VkError.Timeout; + self.condition.timedWait(&self.mutex, timeout) catch return VkError.Timeout; } } diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index 1b948f5..140b6c3 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -36,23 +36,6 @@ pub fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void { try self.dispatch_table.destroy(self, allocator); } -pub inline fn getFenceStatus(self: *Self, fence: *Fence) VkError!void { - try self.dispatch_table.getFenceStatus(fence); -} - -pub inline fn resetFences(_: *Self, fences: []*Fence) VkError!void { - for (fences) |fence| { - try fence.reset(); - } -} - -pub inline fn waitForFences(_: *Self, fences: []*Fence, waitForAll: bool, timeout: u64) VkError!void { - for (fences) |fence| { - try fence.wait(timeout); - if (!waitForAll) return; - } -} - // Fence functions =================================================================================================================================== pub inline fn createFence(self: *Self, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*Fence { @@ -63,6 +46,18 @@ pub inline fn destroyFence(self: *Self, allocator: std.mem.Allocator, fence: *Fe try self.dispatch_table.destroyFence(self, allocator, fence); } +pub inline fn getFenceStatus(self: *Self, fence: *Fence) VkError!void { + try self.dispatch_table.getFenceStatus(self, fence); +} + +pub inline fn resetFences(self: *Self, fences: []*Fence) VkError!void { + try self.dispatch_table.resetFences(self, fences); +} + +pub inline fn waitForFences(self: *Self, fences: []*Fence, waitForAll: bool, timeout: u64) VkError!void { + try self.dispatch_table.waitForFences(self, fences, waitForAll, timeout); +} + // Memory functions ================================================================================================================================== pub inline fn allocateMemory(self: *Self, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*DeviceMemory { diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index c4273f2..33c01d8 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -17,6 +17,7 @@ const VulkanAllocator = @import("VulkanAllocator.zig"); const Instance = @import("Instance.zig"); const Device = @import("Device.zig"); const DeviceMemory = @import("DeviceMemory.zig"); +const Fence = @import("Fence.zig"); const PhysicalDevice = @import("PhysicalDevice.zig"); // This file contains all exported Vulkan entrypoints. @@ -70,10 +71,15 @@ const physical_device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComp const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ functionMapEntryPoint("vkAllocateMemory"), + functionMapEntryPoint("vkDestroyFence"), functionMapEntryPoint("vkDestroyDevice"), + functionMapEntryPoint("vkCreateFence"), functionMapEntryPoint("vkFreeMemory"), + functionMapEntryPoint("vkGetFenceStatus"), functionMapEntryPoint("vkMapMemory"), functionMapEntryPoint("vkUnmapMemory"), + functionMapEntryPoint("vkResetFences"), + functionMapEntryPoint("vkWaitForFences"), }); // ICD Interface ============================================================================================================================================= @@ -272,18 +278,19 @@ pub export fn strollAllocateMemory(p_device: vk.Device, p_info: ?*const vk.Memor return .success; } -pub export fn strollCreateFence(p_device: vk.Device, info: ?*const vk.FenceCreateInfo, callbacks: ?*const vk.allocationcallbacks, p_fence: *vk.Fence) callconv(vk.vulkan_call_conv) vk.Result { +pub export fn strollCreateFence(p_device: vk.Device, p_info: ?*const vk.FenceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_fence: *vk.Fence) callconv(vk.vulkan_call_conv) vk.Result { const info = p_info orelse return .error_validation_failed; if (info.s_type != .fence_create_info) { return .error_validation_failed; } const allocator = VulkanAllocator.init(callbacks, .device).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); return .success; } -pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.allocationcallbacks) callconv(vk.vulkan_call_conv) void { +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 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}); @@ -294,6 +301,15 @@ pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.all dispatchable.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, .device).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch return; + const non_dispatchable_fence = NonDispatchable(Fence).fromHandle(p_fence) catch return; + + device.destroyFence(allocator, non_dispatchable_fence.object) catch return; + non_dispatchable_fence.destroy(allocator); +} + 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 device = Dispatchable(Device).fromHandleObject(p_device) catch return; @@ -314,6 +330,13 @@ pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u return null; } +pub export fn strollGetFenceStatus(p_device: vk.Device, p_fence: vk.Fence) callconv(vk.vulkan_call_conv) vk.Result { + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const fence = NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err); + device.getFenceStatus(fence) catch |err| return toVkResult(err); + return .success; +} + pub export fn strollMapMemory(p_device: vk.Device, p_memory: vk.DeviceMemory, offset: vk.DeviceSize, size: vk.DeviceSize, _: vk.MemoryMapFlags, pp_data: *?*anyopaque) callconv(vk.vulkan_call_conv) vk.Result { const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); const device_memory = NonDispatchable(DeviceMemory).fromHandleObject(p_memory) catch |err| return toVkResult(err); @@ -326,3 +349,33 @@ pub export fn strollUnmapMemory(p_device: vk.Device, p_memory: vk.DeviceMemory) const device_memory = NonDispatchable(DeviceMemory).fromHandleObject(p_memory) catch return; device.unmapMemory(device_memory); } + +pub export fn strollResetFences(p_device: vk.Device, count: u32, p_fences: [*]const vk.Fence) callconv(vk.vulkan_call_conv) vk.Result { + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const allocator = std.heap.c_allocator; + + const fences: []*Fence = allocator.alloc(*Fence, count) catch return .error_unknown; + defer allocator.free(fences); + + for (p_fences, 0..count) |fence, i| { + fences[i] = NonDispatchable(Fence).fromHandleObject(fence) catch |err| return toVkResult(err); + } + + device.resetFences(fences) catch |err| return toVkResult(err); + return .success; +} + +pub export fn strollWaitForFences(p_device: vk.Device, count: u32, p_fences: [*]const vk.Fence, waitForAll: vk.Bool32, timeout: u64) callconv(vk.vulkan_call_conv) vk.Result { + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const allocator = std.heap.c_allocator; + + const fences: []*Fence = allocator.alloc(*Fence, count) catch return .error_unknown; + defer allocator.free(fences); + + for (p_fences, 0..count) |fence, i| { + fences[i] = NonDispatchable(Fence).fromHandleObject(fence) catch |err| return toVkResult(err); + } + + device.waitForFences(fences, (waitForAll == .true), timeout) catch |err| return toVkResult(err); + return .success; +}