Files
VulkanDriver/src/vulkan/lib_vulkan.zig
2025-11-15 00:52:28 +01:00

473 lines
24 KiB
Zig

//! This file contains all exported Vulkan entrypoints.
const std = @import("std");
const vk = @import("vulkan");
const root = @import("root");
const lib = @import("lib.zig");
const builtin = @import("builtin");
const logger = @import("logger.zig");
const error_set = @import("error_set.zig");
const VkError = error_set.VkError;
const toVkResult = error_set.toVkResult;
const Dispatchable = @import("Dispatchable.zig").Dispatchable;
const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable;
const VulkanAllocator = @import("VulkanAllocator.zig");
const Instance = @import("Instance.zig");
const Device = @import("Device.zig");
const PhysicalDevice = @import("PhysicalDevice.zig");
const Queue = @import("Queue.zig");
const CommandBuffer = @import("CommandBuffer.zig");
const CommandPool = @import("CommandPool.zig");
const DeviceMemory = @import("DeviceMemory.zig");
const Fence = @import("Fence.zig");
fn entryPointNotFoundErrorLog(comptime scope: @Type(.enum_literal), name: []const u8) void {
if (lib.getLogVerboseLevel() != .High) return;
std.log.scoped(scope).err("Could not find function {s}", .{name});
}
fn functionMapEntryPoint(comptime name: []const u8) struct { []const u8, vk.PfnVoidFunction } {
const stroll_name = std.fmt.comptimePrint("stroll{s}", .{name[2..]});
return if (std.meta.hasFn(@This(), name))
.{ name, @as(vk.PfnVoidFunction, @ptrCast(&@field(@This(), name))) }
else if (std.meta.hasFn(@This(), stroll_name))
.{ name, @as(vk.PfnVoidFunction, @ptrCast(&@field(@This(), stroll_name))) }
else
@compileError("Invalid entry point name");
}
const icd_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapEntryPoint("vk_icdGetInstanceProcAddr"),
functionMapEntryPoint("vk_icdGetPhysicalDeviceProcAddr"),
functionMapEntryPoint("vk_icdNegotiateLoaderICDInterfaceVersion"),
});
const global_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapEntryPoint("vkCreateInstance"),
functionMapEntryPoint("vkGetInstanceProcAddr"),
functionMapEntryPoint("vkEnumerateInstanceExtensionProperties"),
functionMapEntryPoint("vkEnumerateInstanceVersion"),
});
const instance_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapEntryPoint("vkDestroyInstance"),
functionMapEntryPoint("vkEnumeratePhysicalDevices"),
functionMapEntryPoint("vkGetDeviceProcAddr"),
});
const physical_device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapEntryPoint("vkCreateDevice"),
functionMapEntryPoint("vkEnumerateDeviceExtensionProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceFormatProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceFeatures"),
functionMapEntryPoint("vkGetPhysicalDeviceImageFormatProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceMemoryProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceQueueFamilyProperties"),
functionMapEntryPoint("vkGetPhysicalDeviceSparseImageFormatProperties"),
});
const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapEntryPoint("vkAllocateCommandBuffers"),
functionMapEntryPoint("vkAllocateMemory"),
functionMapEntryPoint("vkCreateCommandPool"),
functionMapEntryPoint("vkCreateFence"),
functionMapEntryPoint("vkDestroyCommandPool"),
functionMapEntryPoint("vkDestroyFence"),
functionMapEntryPoint("vkDestroyDevice"),
functionMapEntryPoint("vkFreeMemory"),
functionMapEntryPoint("vkGetDeviceQueue"),
functionMapEntryPoint("vkGetFenceStatus"),
functionMapEntryPoint("vkMapMemory"),
functionMapEntryPoint("vkUnmapMemory"),
functionMapEntryPoint("vkResetFences"),
functionMapEntryPoint("vkQueueBindSparse"),
functionMapEntryPoint("vkQueueSubmit"),
functionMapEntryPoint("vkQueueWaitIdle"),
functionMapEntryPoint("vkWaitForFences"),
});
// ICD Interface =============================================================================================================================================
pub export fn stroll_icdNegotiateLoaderICDInterfaceVersion(p_version: *u32) callconv(vk.vulkan_call_conv) vk.Result {
p_version.* = 7;
return .success;
}
pub export fn vk_icdGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction {
if (p_name == null) return null;
const name = std.mem.span(p_name.?);
if (icd_pfn_map.get(name)) |pfn| return pfn;
return vkGetInstanceProcAddr(p_instance, p_name);
}
pub export fn stroll_icdGetPhysicalDeviceProcAddr(_: vk.Instance, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction {
if (p_name == null) return null;
const name = std.mem.span(p_name.?);
if (physical_device_pfn_map.get(name)) |pfn| return pfn;
entryPointNotFoundErrorLog(.vk_icdGetPhysicalDeviceProcAddr, name);
return null;
}
// Global functions ==========================================================================================================================================
pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction {
if (p_name == null) return null;
const name = std.mem.span(p_name.?);
if (global_pfn_map.get(name)) |pfn| return pfn;
if (p_instance == .null_handle) {
entryPointNotFoundErrorLog(.vkGetInstanceProcAddr, name);
return null;
}
if (instance_pfn_map.get(name)) |pfn| return pfn;
if (physical_device_pfn_map.get(name)) |pfn| return pfn;
if (device_pfn_map.get(name)) |pfn| return pfn;
entryPointNotFoundErrorLog(.vkGetInstanceProcAddr, name);
return null;
}
pub export fn strollCreateInstance(p_info: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_instance: *vk.Instance) callconv(vk.vulkan_call_conv) vk.Result {
const info = p_info orelse return .error_validation_failed;
if (info.s_type != .instance_create_info) {
return .error_validation_failed;
}
std.log.scoped(.vkCreateInstance).info("Creating VkInstance", .{});
logger.indent();
defer logger.unindent();
const allocator = VulkanAllocator.init(callbacks, .instance).allocator();
var instance: *lib.Instance = undefined;
if (!builtin.is_test) {
// Will call impl instead of interface as root refs the impl module
instance = root.Instance.create(allocator, info) catch |err| return toVkResult(err);
}
instance.requestPhysicalDevices(allocator) catch |err| return toVkResult(err);
p_instance.* = (Dispatchable(Instance).wrap(allocator, instance) catch |err| return toVkResult(err)).toVkHandle(vk.Instance);
return .success;
}
pub export fn strollEnumerateInstanceExtensionProperties(p_layer_name: ?[*:0]const u8, property_count: *u32, properties: ?*vk.ExtensionProperties) callconv(vk.vulkan_call_conv) vk.Result {
var name: ?[]const u8 = null;
if (p_layer_name) |layer_name| {
name = std.mem.span(layer_name);
}
Instance.enumerateExtensionProperties(name, property_count, properties) catch |err| return toVkResult(err);
return .success;
}
pub export fn strollEnumerateInstanceVersion(version: *u32) callconv(vk.vulkan_call_conv) vk.Result {
Instance.enumerateVersion(version) catch |err| return toVkResult(err);
return .success;
}
// Instance functions ========================================================================================================================================
pub export fn strollDestroyInstance(p_instance: vk.Instance, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void {
std.log.scoped(.vkDestroyInstance).info("Destroying VkInstance", .{});
logger.indent();
defer logger.unindent();
const allocator = VulkanAllocator.init(callbacks, .instance).allocator();
const dispatchable = Dispatchable(Instance).fromHandle(p_instance) catch return;
dispatchable.object.deinit(allocator) catch {};
dispatchable.destroy(allocator);
if (std.process.hasEnvVarConstant(lib.DRIVER_DEBUG_ALLOCATOR_ENV_NAME) or builtin.mode == std.builtin.OptimizeMode.Debug) {
// All host memory allocations should've been freed by now
if (!VulkanAllocator.debug_allocator.detectLeaks()) {
std.log.scoped(.vkDestroyInstance).debug("No memory leaks detected", .{});
}
}
}
pub export fn strollEnumeratePhysicalDevices(p_instance: vk.Instance, count: *u32, p_devices: ?[*]vk.PhysicalDevice) callconv(vk.vulkan_call_conv) vk.Result {
const self = Dispatchable(Instance).fromHandleObject(p_instance) catch |err| return toVkResult(err);
count.* = @intCast(self.physical_devices.items.len);
if (p_devices) |devices| {
for (0..count.*) |i| {
devices[i] = self.physical_devices.items[i].toVkHandle(vk.PhysicalDevice);
}
}
return .success;
}
// Physical Device functions =================================================================================================================================
pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, p_info: ?*const vk.DeviceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_device: *vk.Device) callconv(vk.vulkan_call_conv) vk.Result {
const info = p_info orelse return .error_validation_failed;
if (info.s_type != .device_create_info) {
return .error_validation_failed;
}
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();
defer logger.unindent();
const device = physical_device.createDevice(allocator, info) catch |err| return toVkResult(err);
p_device.* = (Dispatchable(Device).wrap(allocator, device) catch |err| return toVkResult(err)).toVkHandle(vk.Device);
return .success;
}
pub export fn strollEnumerateDeviceExtensionProperties(p_physical_device: vk.PhysicalDevice, p_layer_name: ?[*:0]const u8, property_count: *u32, properties: ?*vk.ExtensionProperties) callconv(vk.vulkan_call_conv) vk.Result {
var name: ?[]const u8 = null;
if (p_layer_name) |layer_name| {
name = std.mem.span(layer_name);
}
_ = p_physical_device;
property_count.* = 0;
_ = properties;
return .success;
}
pub export fn strollGetPhysicalDeviceFormatProperties(p_physical_device: vk.PhysicalDevice, format: vk.Format, properties: *vk.FormatProperties) callconv(vk.vulkan_call_conv) void {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
properties.* = self.getFormatProperties(format) catch return;
}
pub export fn strollGetPhysicalDeviceFeatures(p_physical_device: vk.PhysicalDevice, features: *vk.PhysicalDeviceFeatures) callconv(vk.vulkan_call_conv) void {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
features.* = self.features;
}
pub export fn strollGetPhysicalDeviceImageFormatProperties(p_physical_device: vk.PhysicalDevice, format: vk.Format, image_type: vk.ImageType, tiling: vk.ImageTiling, usage: vk.ImageUsageFlags, flags: vk.ImageCreateFlags, properties: *vk.ImageFormatProperties) callconv(vk.vulkan_call_conv) vk.Result {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err);
properties.* = self.getImageFormatProperties(format, image_type, tiling, usage, flags) catch |err| return toVkResult(err);
return .success;
}
pub export fn strollGetPhysicalDeviceProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceProperties) callconv(vk.vulkan_call_conv) void {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
properties.* = self.props;
}
pub export fn strollGetPhysicalDeviceMemoryProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceMemoryProperties) callconv(vk.vulkan_call_conv) void {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
properties.* = self.mem_props;
}
pub export fn strollGetPhysicalDeviceQueueFamilyProperties(p_physical_device: vk.PhysicalDevice, count: *u32, properties: ?[*]vk.QueueFamilyProperties) callconv(vk.vulkan_call_conv) void {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
count.* = @intCast(self.queue_family_props.items.len);
if (properties) |props| {
@memcpy(props[0..count.*], self.queue_family_props.items[0..count.*]);
}
}
pub export fn strollGetPhysicalDeviceSparseImageFormatProperties(
p_physical_device: vk.PhysicalDevice,
format: vk.Format,
image_type: vk.ImageType,
samples: vk.SampleCountFlags,
tiling: vk.ImageTiling,
usage: vk.ImageUsageFlags,
flags: vk.ImageCreateFlags,
properties: *vk.SparseImageFormatProperties,
) callconv(vk.vulkan_call_conv) vk.Result {
const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err);
properties.* = self.getSparseImageFormatProperties(format, image_type, samples, tiling, usage, flags) catch |err| return toVkResult(err);
return .success;
}
// Device functions ==========================================================================================================================================
pub export fn strollAllocateCommandBuffers(p_device: vk.Device, p_info: ?*const vk.CommandBufferAllocateInfo, p_cmds: [*]vk.CommandBuffer) callconv(vk.vulkan_call_conv) vk.Result {
const info = p_info orelse return .error_validation_failed;
if (info.s_type != .command_buffer_allocate_info) {
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);
}
return .success;
}
pub export fn strollAllocateMemory(p_device: vk.Device, p_info: ?*const vk.MemoryAllocateInfo, callbacks: ?*const vk.AllocationCallbacks, p_memory: *vk.DeviceMemory) callconv(vk.vulkan_call_conv) vk.Result {
const info = p_info orelse return .error_validation_failed;
if (info.s_type != .memory_allocate_info) {
return .error_validation_failed;
}
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);
return .success;
}
pub export fn strollCreateCommandPool(p_device: vk.Device, p_info: ?*const vk.CommandPoolCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_pool: *vk.CommandPool) callconv(vk.vulkan_call_conv) vk.Result {
const info = p_info orelse return .error_validation_failed;
if (info.s_type != .command_pool_create_info) {
return .error_validation_failed;
}
const allocator = VulkanAllocator.init(callbacks, .object).allocator();
const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err);
const pool = device.createCommandPool(allocator, info) catch |err| return toVkResult(err);
p_pool.* = (NonDispatchable(CommandPool).wrap(allocator, pool) catch |err| return toVkResult(err)).toVkHandle(vk.CommandPool);
return .success;
}
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, .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);
return .success;
}
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;
std.log.scoped(.vkDestroyDevice).info("Destroying VkDevice created from {s}", .{dispatchable.object.physical_device.props.device_name});
logger.indent();
defer logger.unindent();
dispatchable.object.destroy(allocator) catch return;
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;
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, .object).allocator();
const device = Dispatchable(Device).fromHandleObject(p_device) catch return;
const non_dispatchable_device_memory = NonDispatchable(DeviceMemory).fromHandle(p_memory) catch return;
device.freeMemory(allocator, non_dispatchable_device_memory.object) catch return;
non_dispatchable_device_memory.destroy(allocator);
}
pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction {
if (p_name == null) return null;
const name = std.mem.span(p_name.?);
if (p_device == .null_handle) return null;
if (device_pfn_map.get(name)) |pfn| return pfn;
entryPointNotFoundErrorLog(.vkGetDeviceProcAddr, name);
return null;
}
pub export fn strollGetDeviceQueue(p_device: vk.Device, queue_family_index: u32, queue_index: u32, p_queue: *vk.Queue) callconv(vk.vulkan_call_conv) void {
p_queue.* = .null_handle;
const device = Dispatchable(Device).fromHandleObject(p_device) catch return;
if (device.queues.get(queue_family_index)) |family| {
if (queue_index >= family.items.len) return;
const dispatchable_queue = family.items[queue_index];
const queue = dispatchable_queue.object;
// https://docs.vulkan.org/refpages/latest/refpages/source/vkGetDeviceQueue.html#VUID-vkGetDeviceQueue-flags-01841
if (queue.flags != @TypeOf(queue.flags){}) return;
p_queue.* = dispatchable_queue.toVkHandle(vk.Queue);
}
}
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);
pp_data.* = device.mapMemory(device_memory, offset, size) catch |err| return toVkResult(err);
return .success;
}
pub export fn strollUnmapMemory(p_device: vk.Device, p_memory: vk.DeviceMemory) callconv(vk.vulkan_call_conv) void {
const device = Dispatchable(Device).fromHandleObject(p_device) catch return;
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 strollQueueBindSparse(p_queue: vk.Queue, count: u32, info: [*]vk.BindSparseInfo, p_fence: vk.Fence) callconv(vk.vulkan_call_conv) vk.Result {
const queue = Dispatchable(Queue).fromHandleObject(p_queue) catch |err| return toVkResult(err);
const fence = if (p_fence != .null_handle) NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err) else null;
queue.bindSparse(info[0..count], fence) catch |err| return toVkResult(err);
return .success;
}
pub export fn strollQueueSubmit(p_queue: vk.Queue, count: u32, info: [*]const vk.SubmitInfo, p_fence: vk.Fence) callconv(vk.vulkan_call_conv) vk.Result {
const queue = Dispatchable(Queue).fromHandleObject(p_queue) catch |err| return toVkResult(err);
const fence = if (p_fence != .null_handle) NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err) else null;
queue.submit(info[0..count], fence) catch |err| return toVkResult(err);
return .success;
}
pub export fn strollQueueWaitIdle(p_queue: vk.Queue) callconv(vk.vulkan_call_conv) vk.Result {
const queue = Dispatchable(Queue).fromHandleObject(p_queue) catch |err| return toVkResult(err);
queue.waitIdle() 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;
}