diff --git a/.gdb_history b/.gdb_history index ed32b5d..0eec23d 100644 --- a/.gdb_history +++ b/.gdb_history @@ -97,3 +97,26 @@ q run bt q +run +bt +q +run +b +bt +q +run +bt +q +run +bt +q +run +bt +q +run +bt +q +run +bt +q +q diff --git a/build.zig b/build.zig index 692cd43..09c6134 100644 --- a/build.zig +++ b/build.zig @@ -15,33 +15,25 @@ const implementations = [_]ImplementationDesc{ }, }; -pub fn build(b: *std.Build) !void { +pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const common_mod = b.createModule(.{ + const base_mod = b.createModule(.{ .root_source_file = b.path("src/vulkan/lib.zig"), .target = target, .optimize = optimize, .link_libc = true, }); - const interface_dependency = b.dependency("interface", .{ - .target = target, - .optimize = optimize, - }); - const vulkan_headers = b.dependency("vulkan_headers", .{}); const vulkan = b.dependency("vulkan_zig", .{ .registry = vulkan_headers.path("registry/vk.xml"), }).module("vulkan-zig"); - const interface_mod = interface_dependency.module("interface"); - - common_mod.addImport("vulkan", vulkan); - common_mod.addImport("interface", interface_mod); - common_mod.addSystemIncludePath(vulkan_headers.path("include")); + base_mod.addImport("vulkan", vulkan); + base_mod.addSystemIncludePath(vulkan_headers.path("include")); for (implementations) |impl| { const lib_mod = b.createModule(.{ @@ -50,16 +42,15 @@ pub fn build(b: *std.Build) !void { .link_libc = true, .optimize = optimize, .imports = &.{ - .{ .name = "common", .module = common_mod }, + .{ .name = "base", .module = base_mod }, .{ .name = "vulkan", .module = vulkan }, - .{ .name = "interface", .module = interface_mod }, }, }); lib_mod.addSystemIncludePath(vulkan_headers.path("include")); if (impl.custom) |custom| { - try custom(b, lib_mod); + custom(b, lib_mod) catch continue; } const lib = b.addLibrary(.{ diff --git a/build.zig.zon b/build.zig.zon index 3113675..4991a0b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -18,10 +18,6 @@ .hash = "cpuinfo-0.1.0-V7dMLcghAADJuG7dkd3MnwDPZ232pBK_8uGjxY43eP5u", .lazy = true, }, - .interface = .{ - .url = "git+https://github.com/nilslice/zig-interface#19f2c937b77e42b15bc8cacaa2894ce5b783d94d", - .hash = "interface-0.0.2-GFlWJ7KOAQAkHikqZU0XV86AhX7R9jCyGza85lTIqcEU", - }, }, .paths = .{ diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..e69de29 diff --git a/src/soft/Instance.zig b/src/soft/Instance.zig index f781807..a2db15b 100644 --- a/src/soft/Instance.zig +++ b/src/soft/Instance.zig @@ -1,55 +1,40 @@ const std = @import("std"); const vk = @import("vulkan"); -const common = @import("common"); +const base = @import("base"); const PhysicalDevice = @import("PhysicalDevice.zig"); -const dispatchable = common.dispatchable; +const dispatchable = base.dispatchable; +const VulkanAllocator = base.VulkanAllocator; const Self = @This(); -pub const ObjectType: vk.ObjectType = .instance; -common_instance: common.Instance, -physical_device: vk.PhysicalDevice, // Software driver only has one physical device (CPU) +export fn __vkImplInstanceInit(base_instance: *base.Instance, allocator: *const std.mem.Allocator) ?*anyopaque { + return realVkImplInstanceInit(base_instance, allocator.*) catch return 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 allocator = std.heap.c_allocator; - - const dispatchable_instance = dispatchable.Dispatchable(Self).create(allocator) catch return .error_out_of_host_memory; - const instance = dispatchable_instance.object; - common.Instance.init(&instance.common_instance, p_infos, callbacks) catch return .error_initialization_failed; - - instance.common_instance.vtable = .{ - .destroyInstance = destroy, - .enumeratePhysicalDevices = enumeratePhysicalDevices, +// 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, - .getPhysicalDeviceProperties = PhysicalDevice.getProperties, }; - const dispatchable_physical_device = dispatchable.Dispatchable(PhysicalDevice).create(allocator) catch return .error_out_of_host_memory; - PhysicalDevice.init(dispatchable_physical_device.object) catch return .error_initialization_failed; - instance.physical_device = @enumFromInt(dispatchable_physical_device.toHandle()); + // 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); - p_instance.* = @enumFromInt(dispatchable_instance.toHandle()); - return .success; + try base_instance.physical_devices.append(allocator, @enumFromInt(dispatchable_physical_device.toHandle())); + + const self = try allocator.create(Self); + errdefer allocator.destroy(self); + return @ptrCast(self); } -pub fn enumeratePhysicalDevices(p_instance: vk.Instance, count: *u32, p_devices: ?[*]vk.PhysicalDevice) callconv(vk.vulkan_call_conv) vk.Result { - const instance = dispatchable.fromHandleObject(Self, @intFromEnum(p_instance)) catch return .error_initialization_failed; - count.* = 1; - if (p_devices) |devices| { - devices[0] = instance.physical_device; +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); } - return .success; -} - -pub fn destroy(p_instance: vk.Instance, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { - const allocator = std.heap.c_allocator; - _ = callbacks; - - const dispatchable_instance = dispatchable.fromHandle(Self, @intFromEnum(p_instance)) catch return; - const dispatchable_physical_device = dispatchable.fromHandle(PhysicalDevice, @intFromEnum(dispatchable_instance.object.physical_device)) catch return; - dispatchable_physical_device.destroy(allocator); - dispatchable_instance.destroy(allocator); } diff --git a/src/soft/PhysicalDevice.zig b/src/soft/PhysicalDevice.zig index 6ae70b0..d61423f 100644 --- a/src/soft/PhysicalDevice.zig +++ b/src/soft/PhysicalDevice.zig @@ -1,41 +1,30 @@ const std = @import("std"); const vk = @import("vulkan"); const Instance = @import("Instance.zig"); -const common = @import("common"); +const base = @import("base"); const root = @import("root"); const cpuinfo = @import("cpuinfo"); -const dispatchable = common.dispatchable; +const dispatchable = base.dispatchable; const Self = @This(); -pub const ObjectType: vk.ObjectType = .physical_device; -instance: *const Instance, -common_physical_device: common.PhysicalDevice, +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); -pub fn init(self: *Self) !void { - const allocator = std.heap.c_allocator; + const base_physical_device = dispatchable_physical_device.object; - self.common_physical_device.props = .{ - .api_version = @bitCast(root.VULKAN_VERSION), - .driver_version = @bitCast(root.DRIVER_VERSION), - .vendor_id = common.VULKAN_VENDOR_ID, - .device_id = root.DEVICE_ID, - .device_type = .cpu, - .device_name = [_]u8{0} ** vk.MAX_PHYSICAL_DEVICE_NAME_SIZE, - .pipeline_cache_uuid = undefined, - .limits = undefined, - .sparse_properties = undefined, - }; + 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; const info = try cpuinfo.get(allocator); defer info.deinit(allocator); - var writer = std.io.Writer.fixed(self.common_physical_device.props.device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); + 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}); -} -pub fn getProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceProperties) callconv(vk.vulkan_call_conv) void { - const physical_device = dispatchable.fromHandleObject(Self, @intFromEnum(p_physical_device)) catch return; - properties.* = physical_device.common_physical_device.props; + return dispatchable_physical_device; } diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 202ad78..8a108c1 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -1,6 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const common = @import("common"); +const base = @import("base"); const Instance = @import("Instance.zig"); @@ -8,15 +8,7 @@ pub const VULKAN_VERSION = vk.makeApiVersion(0, 1, 0, 0); pub const DRIVER_VERSION = vk.makeApiVersion(0, 0, 0, 1); pub const DEVICE_ID = 0x600DCAFE; -const global_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - .{ "vkGetInstanceProcAddr", @as(vk.PfnVoidFunction, @ptrCast(&common.icd.getInstanceProcAddr)) }, - .{ "vkCreateInstance", @as(vk.PfnVoidFunction, @ptrCast(&Instance.create)) }, -}); - -pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, pName: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction { - if (pName == null) { - return null; - } - const name = std.mem.span(pName.?); - return common.icd.getInstanceProcAddr(global_pfn_map, p_instance, name); +comptime { + _ = base; + _ = Instance; } diff --git a/src/vulkan/Instance.zig b/src/vulkan/Instance.zig index e53045f..843b073 100644 --- a/src/vulkan/Instance.zig +++ b/src/vulkan/Instance.zig @@ -1,48 +1,85 @@ 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"); + +extern fn __vkImplInstanceInit(*Self, *const std.mem.Allocator) ?*anyopaque; const Self = @This(); pub const ObjectType: vk.ObjectType = .instance; -alloc_callbacks: vk.AllocationCallbacks, +alloc_callbacks: ?vk.AllocationCallbacks, +physical_devices: std.ArrayList(vk.PhysicalDevice), +dispatch_table: DispatchTable, +driver_data: ?*anyopaque, -vtable: VTable, +pub const DispatchTable = struct { + destroyInstance: ?*const fn (*const Self, std.mem.Allocator) anyerror!void = null, + enumerateInstanceVersion: ?vk.PfnEnumerateInstanceVersion = null, + //enumerateInstanceLayerProperties: vk.PfnEnumerateInstanceProperties = null, + enumerateInstanceExtensionProperties: ?vk.PfnEnumerateInstanceExtensionProperties = null, +}; -pub fn init(self: *Self, p_infos: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks) !void { - const infos = p_infos orelse return error.NullCreateInfos; +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.InvalidCreateInfos; + return .error_initialization_failed; } - self.vtable = .{}; + const deref_callbacks = if (callbacks) |c| c.* else null; - if (callbacks) |c| { - self.alloc_callbacks = c.*; + const allocator = VulkanAllocator.init(deref_callbacks, .instance).allocator(); + + const dispatchable_instance = dispatchable.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; + std.debug.assert(self.physical_devices.items.len != 0); + + p_instance.* = @enumFromInt(dispatchable_instance.toHandle()); + return .success; +} + +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); + 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 getProcAddr(self: *const Self, name: []const u8) vk.PfnVoidFunction { +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(self.vtable.destroyInstance) }, - .{ "vkEnumeratePhysicalDevices", @ptrCast(self.vtable.enumeratePhysicalDevices) }, - .{ "vkEnumerateInstanceVersion", @ptrCast(self.vtable.enumerateInstanceVersion) }, - .{ "vkEnumerateInstanceExtensionProperties", @ptrCast(self.vtable.enumerateInstanceExtensionProperties) }, - .{ "vkGetPhysicalDeviceProperties", @ptrCast(self.vtable.getPhysicalDeviceProperties) }, + .{ "vkDestroyInstance", @ptrCast(&destroy) }, + .{ "vkEnumeratePhysicalDevices", @ptrCast(&enumeratePhysicalDevices) }, + //.{ "vkGetPhysicalDeviceProperties", @ptrCast(self.dispatch_table.getPhysicalDeviceProperties) }, }, allocator) catch return null; defer pfn_map.deinit(allocator); - return if (pfn_map.get(name)) |pfn| pfn else null; + // 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); } - -pub const VTable = struct { - destroyInstance: ?vk.PfnDestroyInstance = null, - enumeratePhysicalDevices: ?vk.PfnEnumeratePhysicalDevices = null, - enumerateInstanceVersion: ?vk.PfnEnumerateInstanceVersion = null, - //enumerateInstanceLayerProperties: vk.PfnEnumerateInstanceProperties = null, - enumerateInstanceExtensionProperties: ?vk.PfnEnumerateInstanceExtensionProperties = null, - getPhysicalDeviceProperties: ?vk.PfnGetPhysicalDeviceProperties = null, -}; diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index 7808061..fcfb2f2 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -1,8 +1,57 @@ +const std = @import("std"); const vk = @import("vulkan"); +const root = @import("lib.zig"); const Instance = @import("Instance.zig"); +const dispatchable = @import("dispatchable.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .physical_device; props: vk.PhysicalDeviceProperties, -queue_families: [3]vk.QueueFamilyProperties, +instance: *const Instance, +dispatch_table: DispatchTable, +driver_data: ?*anyopaque, + +pub const DispatchTable = struct {}; + +pub fn init(instance: *const Instance, allocator: std.mem.Allocator) !*dispatchable.Dispatchable(Self) { + const dispatchable_physical_device = try dispatchable.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, + }; + + self.driver_data = null; + self.instance = instance; + self.dispatch_table = .{}; + + return dispatchable_physical_device; +} + +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 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{ + .{ "vkGetPhysicalDeviceProperties", @ptrCast(&getProperties) }, + }, 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 new file mode 100644 index 0000000..8e532dd --- /dev/null +++ b/src/vulkan/VulkanAllocator.zig @@ -0,0 +1,65 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const Allocator = std.mem.Allocator; +const Alignment = std.mem.Alignment; + +/// A Zig allocator from VkAllocationCallbacks. +/// Falls back on c_allocator if callbacks passed are null +const Self = @This(); + +callbacks: ?vk.AllocationCallbacks, +scope: vk.SystemAllocationScope, + +pub fn init(callbacks: ?vk.AllocationCallbacks, scope: vk.SystemAllocationScope) Self { + return .{ + .callbacks = callbacks, + .scope = scope, + }; +} + +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 = &.{ + .alloc = alloc, + .resize = resize, + .remap = remap, + .free = free, + }, + }; +} + +fn alloc(context: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 { + const self: *Self = @ptrCast(@alignCast(context)); + if (self.callbacks.?.pfn_allocation) |pfn_allocation| { + return @ptrCast(pfn_allocation(self.callbacks.?.p_user_data, len, alignment.toByteUnits(), self.scope)); + } + @panic("Null PFN_vkAllocationFunction passed to VkAllocationCallbacks"); +} + +fn resize(context: *anyopaque, ptr: []u8, alignment: Alignment, new_len: usize, _: usize) bool { + _ = alignment; + _ = context; + return new_len <= ptr.len; +} + +fn remap(context: *anyopaque, ptr: []u8, alignment: Alignment, new_len: usize, _: usize) ?[*]u8 { + const self: *Self = @ptrCast(@alignCast(context)); + if (self.callbacks.?.pfn_reallocation) |pfn_reallocation| { + return @ptrCast(pfn_reallocation(self.callbacks.?.p_user_data, ptr.ptr, new_len, alignment.toByteUnits(), self.scope)); + } + @panic("Null PFN_vkReallocationFunction passed to VkAllocationCallbacks"); +} + +fn free(context: *anyopaque, ptr: []u8, alignment: Alignment, _: usize) void { + _ = alignment; + const self: *Self = @ptrCast(@alignCast(context)); + if (self.callbacks.?.pfn_free) |pfn_free| { + return pfn_free(self.callbacks.?.p_user_data, ptr.ptr); + } + @panic("Null PFN_vkFreeFunction passed to VkAllocationCallbacks"); +} diff --git a/src/vulkan/icd.zig b/src/vulkan/icd.zig index b290dad..07c8a91 100644 --- a/src/vulkan/icd.zig +++ b/src/vulkan/icd.zig @@ -1,5 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); +const root = @import("lib.zig"); const c = @cImport({ @cInclude("vulkan/vk_icd.h"); }); @@ -11,18 +12,20 @@ pub fn getInstanceProcAddr(global_pfn_map: std.StaticStringMap(vk.PfnVoidFunctio const allocator = std.heap.c_allocator; const get_proc_log = std.log.scoped(.vkGetInstanceProcAddr); - if (std.process.hasEnvVar(allocator, "DRIVER_LOGS") catch false) { + 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; } - const instance = dispatchable.fromHandle(Instance, @intFromEnum(p_instance)) catch |e| { - if (std.process.hasEnvVar(allocator, "DRIVER_LOGS") catch false) { + + // 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.object.getProcAddr(name); + return Instance.getProcAddr(name); } diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 4e554ea..214cf90 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -6,8 +6,10 @@ pub const dispatchable = @import("dispatchable.zig"); pub const Instance = @import("Instance.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); +pub const VulkanAllocator = @import("VulkanAllocator.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"; pub const std_options: std.Options = .{ .log_level = .info, @@ -23,6 +25,29 @@ pub fn logFn(comptime level: std.log.Level, comptime scope: @Type(.enum_literal) nosuspend stderr.print(format ++ "\n", args) catch return; } +pub fn retrieveDriverDataAs(handle: anytype, comptime T: type) !*T { + comptime { + switch (@typeInfo(@TypeOf(handle))) { + .pointer => |p| std.debug.assert(@hasField(p.child, "driver_data")), + else => @compileError("Invalid type passed to 'retrieveDriverDataAs': " ++ @typeName(@TypeOf(handle))), + } + } + 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, pName: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction { + if (pName == null) { + return null; + } + const name = std.mem.span(pName.?); + return icd.getInstanceProcAddr(global_pfn_map, p_instance, name); +} + test { std.testing.refAllDeclsRecursive(@This()); } diff --git a/test/c/main.c b/test/c/main.c index a441d1b..b1cb463 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -21,8 +21,13 @@ int main(void) { - puts("openning ./zig-out/lib/lib" LIBVK ".so"); void* lib = dlopen("./zig-out/lib/lib" LIBVK ".so", RTLD_NOW | RTLD_LOCAL); + if(!lib) + { + fprintf(stderr, "Could not open driver lib: %s\n", dlerror()); + exit(EXIT_FAILURE); + } + puts("openned ./zig-out/lib/lib" LIBVK ".so"); PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dlsym(lib, "vkGetInstanceProcAddr");