From 446ac9c1f005cdf68ef87ebeb0bea19fd501f984 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Tue, 4 Nov 2025 00:11:15 +0100 Subject: [PATCH] big architectural rework --- src/soft/Instance.zig | 32 ++++------ src/soft/PhysicalDevice.zig | 44 ------------- src/soft/lib.zig | 2 - src/soft/physical_device.zig | 33 ++++++++++ src/vulkan/Dispatchable.zig | 78 +++++++++++++++++++++++ src/vulkan/Instance.zig | 66 ++++--------------- src/vulkan/PhysicalDevice.zig | 112 ++++++++------------------------- src/vulkan/VulkanAllocator.zig | 5 +- src/vulkan/dispatchable.zig | 50 --------------- src/vulkan/error_set.zig | 105 +++++++++++++++++++++++++++++++ src/vulkan/icd.zig | 31 --------- src/vulkan/lib.zig | 21 +++---- src/vulkan/lib_vulkan.zig | 75 ++++++++++++++++++++++ 13 files changed, 348 insertions(+), 306 deletions(-) delete mode 100644 src/soft/PhysicalDevice.zig create mode 100644 src/soft/physical_device.zig create mode 100644 src/vulkan/Dispatchable.zig delete mode 100644 src/vulkan/dispatchable.zig create mode 100644 src/vulkan/error_set.zig delete mode 100644 src/vulkan/icd.zig create mode 100644 src/vulkan/lib_vulkan.zig diff --git a/src/soft/Instance.zig b/src/soft/Instance.zig index a2db15b..d7dd536 100644 --- a/src/soft/Instance.zig +++ b/src/soft/Instance.zig @@ -1,40 +1,30 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const PhysicalDevice = @import("PhysicalDevice.zig"); +const soft_physical_device = @import("physical_device.zig"); -const dispatchable = base.dispatchable; +const Dispatchable = base.Dispatchable; const VulkanAllocator = base.VulkanAllocator; const Self = @This(); -export fn __vkImplInstanceInit(base_instance: *base.Instance, allocator: *const std.mem.Allocator) ?*anyopaque { - return realVkImplInstanceInit(base_instance, allocator.*) catch return null; +export fn __vkImplInstanceInit(base_instance: *base.Instance, allocator: *const std.mem.Allocator, infos: *const vk.InstanceCreateInfo) ?*anyopaque { + return realVkImplInstanceInit(base_instance, allocator.*, infos) catch return null; } // Pure Zig implementation to leverage `errdefer` and avoid memory leaks or complex resources handling -fn realVkImplInstanceInit(base_instance: *base.Instance, allocator: std.mem.Allocator) !?*anyopaque { - base_instance.dispatch_table = .{ - .destroyInstance = deinit, - .enumerateInstanceVersion = null, - //.enumerateInstanceLayerProperties = null, - .enumerateInstanceExtensionProperties = null, - }; +fn realVkImplInstanceInit(instance: *base.Instance, allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) !?*anyopaque { + _ = infos; // Software driver only has one physical device (the CPU) - const dispatchable_physical_device = try PhysicalDevice.init(base_instance, allocator); - errdefer dispatchable_physical_device.destroy(allocator); + const physical_device = try Dispatchable(base.PhysicalDevice).create(allocator, .{instance}); + errdefer physical_device.destroy(allocator); - try base_instance.physical_devices.append(allocator, @enumFromInt(dispatchable_physical_device.toHandle())); + try soft_physical_device.setup(allocator, physical_device.object); + + try instance.physical_devices.append(allocator, physical_device.toVkHandle(vk.PhysicalDevice)); const self = try allocator.create(Self); errdefer allocator.destroy(self); return @ptrCast(self); } - -pub fn deinit(base_instance: *const base.Instance, allocator: std.mem.Allocator) !void { - for (base_instance.physical_devices.items) |physical_device| { - const dispatchable_physical_device = try dispatchable.fromHandle(base.PhysicalDevice, @intFromEnum(physical_device)); - dispatchable_physical_device.destroy(allocator); - } -} diff --git a/src/soft/PhysicalDevice.zig b/src/soft/PhysicalDevice.zig deleted file mode 100644 index 2dcd7fc..0000000 --- a/src/soft/PhysicalDevice.zig +++ /dev/null @@ -1,44 +0,0 @@ -const std = @import("std"); -const vk = @import("vulkan"); -const Instance = @import("Instance.zig"); -const base = @import("base"); -const root = @import("lib.zig"); -const cpuinfo = @import("cpuinfo"); - -const dispatchable = base.dispatchable; - -const Self = @This(); - -pub fn init(instance: *const base.Instance, allocator: std.mem.Allocator) !*dispatchable.Dispatchable(base.PhysicalDevice) { - const dispatchable_physical_device = try base.PhysicalDevice.init(instance, allocator); - errdefer dispatchable_physical_device.destroy(allocator); - - const base_physical_device = dispatchable_physical_device.object; - - base_physical_device.props.api_version = @bitCast(root.VULKAN_VERSION); - base_physical_device.props.driver_version = @bitCast(root.DRIVER_VERSION); - base_physical_device.props.device_id = root.DEVICE_ID; - base_physical_device.props.device_type = .cpu; - - base_physical_device.mem_props.memory_type_count = 1; - base_physical_device.mem_props.memory_types[0] = .{ - .heap_index = 0, - .property_flags = .{ - .host_visible_bit = true, - .host_coherent_bit = true, - }, - }; - base_physical_device.mem_props.memory_heap_count = 1; - base_physical_device.mem_props.memory_heaps[0] = .{ - .size = std.process.totalSystemMemory() catch 0, - .flags = .{}, // Host memory - }; - - const info = try cpuinfo.get(allocator); - defer info.deinit(allocator); - - var writer = std.io.Writer.fixed(base_physical_device.props.device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); - try writer.print("{s} [Soft Vulkan Driver]", .{info.name}); - - return dispatchable_physical_device; -} diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 5fd34d1..8a108c1 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const Instance = @import("Instance.zig"); -const PhysicalDevice = @import("PhysicalDevice.zig"); pub const VULKAN_VERSION = vk.makeApiVersion(0, 1, 0, 0); pub const DRIVER_VERSION = vk.makeApiVersion(0, 0, 0, 1); @@ -12,5 +11,4 @@ pub const DEVICE_ID = 0x600DCAFE; comptime { _ = base; _ = Instance; - _ = PhysicalDevice; } diff --git a/src/soft/physical_device.zig b/src/soft/physical_device.zig new file mode 100644 index 0000000..f14643f --- /dev/null +++ b/src/soft/physical_device.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const Instance = @import("Instance.zig"); +const base = @import("base"); +const root = @import("lib.zig"); +const cpuinfo = @import("cpuinfo"); + +pub fn setup(allocator: std.mem.Allocator, physical_device: *base.PhysicalDevice) !void { + physical_device.props.api_version = @bitCast(root.VULKAN_VERSION); + physical_device.props.driver_version = @bitCast(root.DRIVER_VERSION); + physical_device.props.device_id = root.DEVICE_ID; + physical_device.props.device_type = .cpu; + + physical_device.mem_props.memory_type_count = 1; + physical_device.mem_props.memory_types[0] = .{ + .heap_index = 0, + .property_flags = .{ + .host_visible_bit = true, + .host_coherent_bit = true, + }, + }; + physical_device.mem_props.memory_heap_count = 1; + physical_device.mem_props.memory_heaps[0] = .{ + .size = std.process.totalSystemMemory() catch 0, + .flags = .{}, // Host memory + }; + + const info = try cpuinfo.get(allocator); + defer info.deinit(allocator); + + var writer = std.io.Writer.fixed(physical_device.props.device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); + try writer.print("{s} [Soft Vulkan Driver]", .{info.name}); +} diff --git a/src/vulkan/Dispatchable.zig b/src/vulkan/Dispatchable.zig new file mode 100644 index 0000000..5699678 --- /dev/null +++ b/src/vulkan/Dispatchable.zig @@ -0,0 +1,78 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const c = @cImport({ + @cInclude("vulkan/vk_icd.h"); +}); + +const VkError = @import("error_set.zig").VkError; + +pub fn Dispatchable(comptime T: type) type { + return extern struct { + const Self = @This(); + + loader_data: c.VK_LOADER_DATA, + object_type: vk.ObjectType, + object: *T, + + pub fn create(allocator: std.mem.Allocator, args: anytype) VkError!*Self { + comptime { + const ti = @typeInfo(@TypeOf(args)); + if (ti != .@"struct" or !ti.@"struct".is_tuple) { + @compileError("pass a tuple literal like .{...}"); + } + + if (!std.meta.hasMethod(T, "init")) { + @compileError("Dispatchable types are expected to have 'init' and 'deinit' methods."); + } + const init_params = @typeInfo(@TypeOf(T.init)).@"fn".params; + if (init_params.len < 1 or init_params[0].type != std.mem.Allocator) { + @compileError("Dispatchable types 'init' method should take a 'std.mem.Allocator' as its first parameter."); + } + } + + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + const object = allocator.create(T) catch return VkError.OutOfHostMemory; + object.* = try @call(.auto, T.init, .{allocator} ++ args); + + self.* = .{ + .loader_data = .{ .loaderMagic = c.ICD_LOADER_MAGIC }, + .object_type = T.ObjectType, + .object = object, + }; + return self; + } + + pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { + if (std.meta.hasMethod(T, "deinit")) { + self.object.deinit(allocator); + } + allocator.destroy(self.object); + allocator.destroy(self); + } + + pub inline fn toHandle(self: *Self) usize { + return @intFromPtr(self); + } + + pub inline fn toVkHandle(self: *Self, comptime VkT: type) VkT { + return @enumFromInt(@intFromPtr(self)); + } + + pub inline fn fromHandle(vk_handle: anytype) VkError!*Self { + const handle = @intFromEnum(vk_handle); + if (handle == 0) { + return VkError.Unknown; + } + const dispatchable: *Self = @ptrFromInt(handle); + if (dispatchable.object_type != T.ObjectType) { + return VkError.Unknown; + } + return dispatchable; + } + + pub inline fn fromHandleObject(handle: anytype) VkError!*T { + const dispatchable_handle = try Self.fromHandle(handle); + return dispatchable_handle.object; + } + }; +} diff --git a/src/vulkan/Instance.zig b/src/vulkan/Instance.zig index b82f2c7..55b5417 100644 --- a/src/vulkan/Instance.zig +++ b/src/vulkan/Instance.zig @@ -1,17 +1,13 @@ const std = @import("std"); const vk = @import("vulkan"); const root = @import("lib.zig"); -const dispatchable = @import("dispatchable.zig"); -const VulkanAllocator = @import("VulkanAllocator.zig"); -const PhysicalDevice = @import("PhysicalDevice.zig"); -const Dispatchable = dispatchable.Dispatchable; +const VkError = @import("error_set.zig").VkError; -extern fn __vkImplInstanceInit(*Self, *const std.mem.Allocator) ?*anyopaque; +extern fn __vkImplInstanceInit(*Self, *const std.mem.Allocator, *const vk.InstanceCreateInfo) ?*anyopaque; const Self = @This(); pub const ObjectType: vk.ObjectType = .instance; -alloc_callbacks: ?vk.AllocationCallbacks, physical_devices: std.ArrayList(vk.PhysicalDevice), dispatch_table: DispatchTable, driver_data: ?*anyopaque, @@ -20,63 +16,23 @@ pub const DispatchTable = struct { destroyInstance: ?*const fn (*const Self, std.mem.Allocator) anyerror!void = null, }; -pub fn create(p_infos: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_instance: *vk.Instance) callconv(vk.vulkan_call_conv) vk.Result { - const infos = p_infos orelse return .error_initialization_failed; - if (infos.s_type != .instance_create_info) { - return .error_initialization_failed; - } +pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!Self { + var self: Self = .{ + .dispatch_table = .{}, + .physical_devices = .empty, + .driver_data = null, + }; - const deref_callbacks = if (callbacks) |c| c.* else null; - - const allocator = VulkanAllocator.init(deref_callbacks, .instance).allocator(); - - const dispatchable_instance = Dispatchable(Self).create(allocator) catch return .error_out_of_host_memory; - const self = dispatchable_instance.object; - self.dispatch_table = .{}; - - self.alloc_callbacks = deref_callbacks; - self.physical_devices = .empty; - - self.driver_data = __vkImplInstanceInit(self, &allocator) orelse return .error_initialization_failed; + self.driver_data = __vkImplInstanceInit(&self, &allocator, infos) orelse return VkError.InitializationFailed; std.debug.assert(self.physical_devices.items.len != 0); - p_instance.* = @enumFromInt(dispatchable_instance.toHandle()); - return .success; + return self; } -pub fn destroy(p_instance: vk.Instance, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { - const allocator = VulkanAllocator.init(if (callbacks) |c| c.* else null, .instance).allocator(); - - const dispatchable_instance = dispatchable.fromHandle(Self, @intFromEnum(p_instance)) catch return; - defer dispatchable_instance.destroy(allocator); - - const self: *const Self = @ptrCast(dispatchable_instance.object); +pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { if (self.dispatch_table.destroyInstance) |pfnDestroyInstance| { pfnDestroyInstance(self, allocator) catch return; } else if (std.process.hasEnvVar(allocator, root.DRIVER_LOGS_ENV_NAME) catch false) { std.log.scoped(.vkDestroyInstance).warn("Missing dispatch implementation", .{}); } } - -pub fn enumeratePhysicalDevices(p_instance: vk.Instance, count: *u32, p_devices: ?[*]vk.PhysicalDevice) callconv(vk.vulkan_call_conv) vk.Result { - const self = dispatchable.fromHandleObject(Self, @intFromEnum(p_instance)) catch return .error_unknown; - count.* = @intCast(self.physical_devices.items.len); - if (p_devices) |devices| { - @memcpy(devices[0..self.physical_devices.items.len], self.physical_devices.items); - } - return .success; -} - -pub fn getProcAddr(name: []const u8) vk.PfnVoidFunction { - const allocator = std.heap.c_allocator; - - const KV = struct { []const u8, vk.PfnVoidFunction }; - const pfn_map = std.StaticStringMap(vk.PfnVoidFunction).init([_]KV{ - .{ "vkDestroyInstance", @ptrCast(&destroy) }, - .{ "vkEnumeratePhysicalDevices", @ptrCast(&enumeratePhysicalDevices) }, - }, allocator) catch return null; - defer pfn_map.deinit(allocator); - - // Falling back on PhysicalDevice's getProcAddr which will return null if not found - return if (pfn_map.get(name)) |pfn| pfn else PhysicalDevice.getProcAddr(name); -} diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index a85d992..dcbff30 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -2,11 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const root = @import("lib.zig"); const Instance = @import("Instance.zig"); -const Device = @import("Device.zig"); -const dispatchable = @import("dispatchable.zig"); -const VulkanAllocator = @import("VulkanAllocator.zig"); - -const Dispatchable = dispatchable.Dispatchable; +const VkError = @import("error_set.zig").VkError; const Self = @This(); pub const ObjectType: vk.ObjectType = .physical_device; @@ -17,88 +13,30 @@ instance: *const Instance, dispatch_table: DispatchTable, driver_data: ?*anyopaque, -pub const DispatchTable = struct { - createImplDevice: ?*const fn (*Self, vk.DeviceCreateInfo, std.mem.Allocator) anyerror!?*anyopaque, -}; +pub const DispatchTable = struct {}; -pub fn init(instance: *const Instance, allocator: std.mem.Allocator) !*Dispatchable(Self) { - const dispatchable_physical_device = try Dispatchable(Self).create(allocator); - errdefer dispatchable_physical_device.destroy(allocator); - - const self = dispatchable_physical_device.object; - - self.props = .{ - .api_version = undefined, - .driver_version = undefined, - .vendor_id = root.VULKAN_VENDOR_ID, - .device_id = undefined, - .device_type = undefined, - .device_name = [_]u8{0} ** vk.MAX_PHYSICAL_DEVICE_NAME_SIZE, - .pipeline_cache_uuid = undefined, - .limits = undefined, - .sparse_properties = undefined, +pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Self { + _ = allocator; + return .{ + .props = .{ + .api_version = undefined, + .driver_version = undefined, + .vendor_id = root.VULKAN_VENDOR_ID, + .device_id = undefined, + .device_type = undefined, + .device_name = [_]u8{0} ** vk.MAX_PHYSICAL_DEVICE_NAME_SIZE, + .pipeline_cache_uuid = undefined, + .limits = undefined, + .sparse_properties = undefined, + }, + .mem_props = .{ + .memory_type_count = 0, + .memory_types = undefined, + .memory_heap_count = 0, + .memory_heaps = undefined, + }, + .driver_data = null, + .instance = instance, + .dispatch_table = .{}, }; - - self.mem_props = .{ - .memory_type_count = 0, - .memory_types = undefined, - .memory_heap_count = 0, - .memory_heaps = undefined, - }; - - self.driver_data = null; - self.instance = instance; - self.dispatch_table = .{}; - - return dispatchable_physical_device; -} - -pub fn createDevice(p_physical_device: vk.PhysicalDevice, p_infos: ?*const vk.DeviceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_device: *vk.Device) callconv(vk.vulkan_call_conv) vk.Result { - const infos = p_infos orelse return .error_initialization_failed; - if (infos.s_type != .device_create_info) { - return .error_initialization_failed; - } - - const self = dispatchable.fromHandleObject(Self, @intFromEnum(p_physical_device)) catch return .error_unknown; - - const deref_callbacks = if (callbacks) |c| c.* else null; - - const allocator = VulkanAllocator.init(deref_callbacks, .instance).allocator(); - - const dispatchable_device = Dispatchable(Device).create(allocator) catch return .error_out_of_host_memory; - const device = dispatchable_device.object; - device.dispatch_table = .{}; - - if (self.dispatch_table.createImplDevice) |pfnCreateImplDevice| { - device.driver_data = pfnCreateImplDevice(self, infos, allocator) catch return .error_initialization_failed; - } else if (std.process.hasEnvVar(allocator, root.DRIVER_LOGS_ENV_NAME) catch false) { - std.log.scoped(.vkCreateDevice).warn("Missing dispatch implementation", .{}); - } - - p_device.* = @enumFromInt(dispatchable_device.toHandle()); - return .success; -} - -pub fn getProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceProperties) callconv(vk.vulkan_call_conv) void { - const self = dispatchable.fromHandleObject(Self, @intFromEnum(p_physical_device)) catch return; - properties.* = self.props; -} - -pub fn getMemoryProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceMemoryProperties) callconv(vk.vulkan_call_conv) void { - const self = dispatchable.fromHandleObject(Self, @intFromEnum(p_physical_device)) catch return; - properties.* = self.mem_props; -} - -pub fn getProcAddr(name: []const u8) vk.PfnVoidFunction { - const allocator = std.heap.c_allocator; - - const KV = struct { []const u8, vk.PfnVoidFunction }; - const pfn_map = std.StaticStringMap(vk.PfnVoidFunction).init([_]KV{ - .{ "vkCreateDevice", @ptrCast(&createDevice) }, - .{ "vkGetPhysicalDeviceProperties", @ptrCast(&getProperties) }, - .{ "vkGetPhysicalDeviceMemoryProperties", @ptrCast(&getMemoryProperties) }, - }, allocator) catch return null; - defer pfn_map.deinit(allocator); - - return if (pfn_map.get(name)) |pfn| pfn else null; } diff --git a/src/vulkan/VulkanAllocator.zig b/src/vulkan/VulkanAllocator.zig index 8e532dd..44aa655 100644 --- a/src/vulkan/VulkanAllocator.zig +++ b/src/vulkan/VulkanAllocator.zig @@ -11,9 +11,10 @@ const Self = @This(); callbacks: ?vk.AllocationCallbacks, scope: vk.SystemAllocationScope, -pub fn init(callbacks: ?vk.AllocationCallbacks, scope: vk.SystemAllocationScope) Self { +pub fn init(callbacks: ?*const vk.AllocationCallbacks, scope: vk.SystemAllocationScope) Self { + const deref_callbacks = if (callbacks) |c| c.* else null; return .{ - .callbacks = callbacks, + .callbacks = deref_callbacks, .scope = scope, }; } diff --git a/src/vulkan/dispatchable.zig b/src/vulkan/dispatchable.zig deleted file mode 100644 index 64802bf..0000000 --- a/src/vulkan/dispatchable.zig +++ /dev/null @@ -1,50 +0,0 @@ -const std = @import("std"); -const vk = @import("vulkan"); -const c = @cImport({ - @cInclude("vulkan/vk_icd.h"); -}); - -pub fn Dispatchable(comptime T: type) type { - return extern struct { - const Self = @This(); - - loader_data: c.VK_LOADER_DATA, - object_type: vk.ObjectType, - object: *T, - - pub fn create(allocator: std.mem.Allocator) !*Self { - const object = try allocator.create(Self); - object.* = .{ - .loader_data = .{ .loaderMagic = c.ICD_LOADER_MAGIC }, - .object_type = T.ObjectType, - .object = try allocator.create(T), - }; - return object; - } - - pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { - allocator.destroy(self.object); - allocator.destroy(self); - } - - pub inline fn toHandle(self: *Self) usize { - return @intFromPtr(self); - } - }; -} - -pub inline fn fromHandle(comptime T: type, handle: usize) !*Dispatchable(T) { - if (handle == 0) { - return error.NullHandle; - } - const dispatchable: *Dispatchable(T) = @ptrFromInt(handle); - if (dispatchable.object_type != T.ObjectType) { - return error.InvalidType; - } - return dispatchable; -} - -pub inline fn fromHandleObject(comptime T: type, handle: usize) !*T { - const dispatchable_handle = try fromHandle(T, handle); - return dispatchable_handle.object; -} diff --git a/src/vulkan/error_set.zig b/src/vulkan/error_set.zig new file mode 100644 index 0000000..fb17e86 --- /dev/null +++ b/src/vulkan/error_set.zig @@ -0,0 +1,105 @@ +const vk = @import("vulkan"); + +pub const VkError = error{ + NotReady, + Timeout, + EventSet, + EventReset, + Incomplete, + OutOfHostMemory, + OutOfDeviceMemory, + InitializationFailed, + DeviceLost, + MemoryMapFailed, + LayerNotPresent, + ExtensionNotPresent, + FeatureNotPresent, + IncompatibleDriver, + TooManyObjects, + FormatNotSupported, + FragmentedPool, + Unknown, + ValidationFailed, + OutOfPoolMemory, + InvalidExternalHandle, + InvalidOpaqueCaptureAddress, + Fragmentation, + PipelineCompileRequired, + NotPermitted, + SurfaceLostKhr, + NativeWindowInUseKhr, + SuboptimalKhr, + OutOfDateKhr, + IncompatibleDisplayKhr, + InvalidShaderNv, + ImageUsageNotSupportedKhr, + VideoPictureLayoutNotSupportedKhr, + VideoProfileOperationNotSupportedKhr, + VideoProfileFormatNotSupportedKhr, + VideoProfileCodecNotSupportedKhr, + VideoStdVersionNotSupportedKhr, + InvalidDrmFormatModifierPlaneLayoutExt, + FullScreenExclusiveModeLostExt, + ThreadIdleKhr, + ThreadDoneKhr, + OperationDeferredKhr, + OperationNotDeferredKhr, + InvalidVideoStdParametersKhr, + CompressionExhaustedExt, + IncompatibleShaderBinaryExt, + PipelineBinaryMissingKhr, + NotEnoughSpaceKhr, +}; + +pub inline fn toVkResult(err: VkError) vk.Result { + return switch (err) { + VkError.NotReady => .not_ready, + VkError.Timeout => .timeout, + VkError.EventSet => .event_set, + VkError.EventReset => .event_reset, + VkError.Incomplete => .incomplete, + VkError.OutOfHostMemory => .error_out_of_host_memory, + VkError.OutOfDeviceMemory => .error_out_of_device_memory, + VkError.InitializationFailed => .error_initialization_failed, + VkError.DeviceLost => .error_device_lost, + VkError.MemoryMapFailed => .error_memory_map_failed, + VkError.LayerNotPresent => .error_layer_not_present, + VkError.ExtensionNotPresent => .error_extension_not_present, + VkError.FeatureNotPresent => .error_feature_not_present, + VkError.IncompatibleDriver => .error_incompatible_driver, + VkError.TooManyObjects => .error_too_many_objects, + VkError.FormatNotSupported => .error_format_not_supported, + VkError.FragmentedPool => .error_fragmented_pool, + VkError.Unknown => .error_unknown, + VkError.ValidationFailed => .error_validation_failed, + VkError.OutOfPoolMemory => .error_out_of_pool_memory, + VkError.InvalidExternalHandle => .error_invalid_external_handle, + VkError.InvalidOpaqueCaptureAddress => .error_invalid_opaque_capture_address, + VkError.Fragmentation => .error_fragmentation, + VkError.PipelineCompileRequired => .pipeline_compile_required, + VkError.NotPermitted => .error_not_permitted, + VkError.SurfaceLostKhr => .error_surface_lost_khr, + VkError.NativeWindowInUseKhr => .error_native_window_in_use_khr, + VkError.SuboptimalKhr => .suboptimal_khr, + VkError.OutOfDateKhr => .error_out_of_date_khr, + VkError.IncompatibleDisplayKhr => .error_incompatible_display_khr, + VkError.InvalidShaderNv => .error_invalid_shader_nv, + VkError.ImageUsageNotSupportedKhr => .error_image_usage_not_supported_khr, + VkError.VideoPictureLayoutNotSupportedKhr => .error_video_picture_layout_not_supported_khr, + VkError.VideoProfileOperationNotSupportedKhr => .error_video_profile_operation_not_supported_khr, + VkError.VideoProfileFormatNotSupportedKhr => .error_video_profile_format_not_supported_khr, + VkError.VideoProfileCodecNotSupportedKhr => .error_video_profile_codec_not_supported_khr, + VkError.VideoStdVersionNotSupportedKhr => .error_video_std_version_not_supported_khr, + VkError.InvalidDrmFormatModifierPlaneLayoutExt => .error_invalid_drm_format_modifier_plane_layout_ext, + VkError.FullScreenExclusiveModeLostExt => .error_full_screen_exclusive_mode_lost_ext, + VkError.ThreadIdleKhr => .thread_idle_khr, + VkError.ThreadDoneKhr => .thread_done_khr, + VkError.OperationDeferredKhr => .operation_deferred_khr, + VkError.OperationNotDeferredKhr => .operation_not_deferred_khr, + VkError.InvalidVideoStdParametersKhr => .error_invalid_video_std_parameters_khr, + VkError.CompressionExhaustedExt => .error_compression_exhausted_ext, + VkError.IncompatibleShaderBinaryExt => .incompatible_shader_binary_ext, + VkError.PipelineBinaryMissingKhr => .pipeline_binary_missing_khr, + VkError.NotEnoughSpaceKhr => .error_not_enough_space_khr, + }; +} diff --git a/src/vulkan/icd.zig b/src/vulkan/icd.zig deleted file mode 100644 index 07c8a91..0000000 --- a/src/vulkan/icd.zig +++ /dev/null @@ -1,31 +0,0 @@ -const std = @import("std"); -const vk = @import("vulkan"); -const root = @import("lib.zig"); -const c = @cImport({ - @cInclude("vulkan/vk_icd.h"); -}); - -const Instance = @import("Instance.zig"); -const dispatchable = @import("dispatchable.zig"); - -pub fn getInstanceProcAddr(global_pfn_map: std.StaticStringMap(vk.PfnVoidFunction), p_instance: vk.Instance, name: []const u8) vk.PfnVoidFunction { - const allocator = std.heap.c_allocator; - const get_proc_log = std.log.scoped(.vkGetInstanceProcAddr); - - if (std.process.hasEnvVar(allocator, root.DRIVER_LOGS_ENV_NAME) catch false) { - get_proc_log.info("Loading {s}...", .{name}); - } - - if (global_pfn_map.get(name)) |pfn| { - return pfn; - } - - // Checks if instance is NULL - _ = dispatchable.fromHandle(Instance, @intFromEnum(p_instance)) catch |e| { - if (std.process.hasEnvVar(allocator, root.DRIVER_LOGS_ENV_NAME) catch false) { - get_proc_log.err("{any}", .{e}); - } - return null; - }; - return Instance.getProcAddr(name); -} diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 6a4f63e..44c4001 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -1,13 +1,15 @@ const std = @import("std"); const vk = @import("vulkan"); -pub const icd = @import("icd.zig"); -pub const dispatchable = @import("dispatchable.zig"); +pub const lib_vulkan = @import("lib_vulkan.zig"); + +pub const Dispatchable = @import("Dispatchable.zig").Dispatchable; +pub const VkError = @import("error_set.zig").VkError; pub const Instance = @import("Instance.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const VulkanAllocator = @import("VulkanAllocator.zig"); -pub const Device = @import("Device.zig"); +//pub const Device = @import("Device.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 = "DRIVER_LOGS"; @@ -36,17 +38,8 @@ pub fn retrieveDriverDataAs(handle: anytype, comptime T: type) !*T { return @ptrCast(@alignCast(@field(handle, "driver_data"))); } -const global_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - .{ "vkGetInstanceProcAddr", @as(vk.PfnVoidFunction, @ptrCast(&icd.getInstanceProcAddr)) }, - .{ "vkCreateInstance", @as(vk.PfnVoidFunction, @ptrCast(&Instance.create)) }, -}); - -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.?); - return icd.getInstanceProcAddr(global_pfn_map, p_instance, name); +comptime { + _ = lib_vulkan; } test { diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig new file mode 100644 index 0000000..6fcf387 --- /dev/null +++ b/src/vulkan/lib_vulkan.zig @@ -0,0 +1,75 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const root = @import("lib.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 VulkanAllocator = @import("VulkanAllocator.zig"); + +const Instance = @import("Instance.zig"); +const PhysicalDevice = @import("PhysicalDevice.zig"); + +pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction { + const global_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ + .{ "vkGetInstanceProcAddr", @as(vk.PfnVoidFunction, @ptrCast(&vkGetInstanceProcAddr)) }, + .{ "vkCreateInstance", @as(vk.PfnVoidFunction, @ptrCast(&vkCreateInstance)) }, + }); + + const instance_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ + .{ "vkDestroyInstance", @as(vk.PfnVoidFunction, @ptrCast(&vkDestroyInstance)) }, + .{ "vkEnumeratePhysicalDevices", @as(vk.PfnVoidFunction, @ptrCast(&vkEnumeratePhysicalDevices)) }, + .{ "vkGetPhysicalDeviceProperties", @as(vk.PfnVoidFunction, @ptrCast(&vkGetPhysicalDeviceProperties)) }, + .{ "vkGetPhysicalDeviceProperties", @as(vk.PfnVoidFunction, @ptrCast(&vkGetPhysicalDeviceMemoryProperties)) }, + }); + + if (p_name == null) { + return null; + } + const name = std.mem.span(p_name.?); + + if (std.process.hasEnvVarConstant(root.DRIVER_LOGS_ENV_NAME)) { + std.log.scoped(.vkGetInstanceProcAddr).info("Loading {s}...", .{name}); + } + + if (global_pfn_map.get(name)) |pfn| return pfn; + if (p_instance == .null_handle) return null; + return if (instance_pfn_map.get(name)) |pfn| pfn else null; +} + +pub export fn vkCreateInstance(p_infos: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_instance: *vk.Instance) callconv(vk.vulkan_call_conv) vk.Result { + const infos = p_infos orelse return .error_initialization_failed; + if (infos.s_type != .instance_create_info) { + return .error_initialization_failed; + } + const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); + p_instance.* = (Dispatchable(Instance).create(allocator, .{infos}) catch |err| return toVkResult(err)).toVkHandle(vk.Instance); + return .success; +} + +pub export fn vkDestroyInstance(p_instance: vk.Instance, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); + (Dispatchable(Instance).fromHandle(p_instance) catch return).destroy(allocator); +} + +pub export fn vkEnumeratePhysicalDevices(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| { + @memcpy(devices[0..self.physical_devices.items.len], self.physical_devices.items); + } + return .success; +} + +pub export fn vkGetPhysicalDeviceProperties(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 vkGetPhysicalDeviceMemoryProperties(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; +}