From 31c9234a998268cd1e8d35a82d779be7facb0b1e Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Tue, 4 Nov 2025 13:02:47 +0100 Subject: [PATCH] improving architecture, adding logical device creation and destruction --- src/soft/Device.zig | 32 +++++++++++++++++ src/soft/Instance.zig | 56 ++++++++++++++++++++--------- src/soft/PhysicalDevice.zig | 67 +++++++++++++++++++++++++++++++++++ src/soft/lib.zig | 4 +++ src/soft/physical_device.zig | 33 ----------------- src/vulkan/Device.zig | 23 +++++++++--- src/vulkan/Dispatchable.zig | 11 ++++-- src/vulkan/Instance.zig | 35 ++++++++---------- src/vulkan/PhysicalDevice.zig | 21 ++++++++--- src/vulkan/lib.zig | 15 +++----- src/vulkan/lib_vulkan.zig | 50 +++++++++++++++++++++----- src/vulkan/logs.zig | 48 +++++++++++++++++++++++++ test/c/main.c | 10 ++++++ 13 files changed, 302 insertions(+), 103 deletions(-) create mode 100644 src/soft/Device.zig create mode 100644 src/soft/PhysicalDevice.zig delete mode 100644 src/soft/physical_device.zig create mode 100644 src/vulkan/logs.zig diff --git a/src/soft/Device.zig b/src/soft/Device.zig new file mode 100644 index 0000000..ae48507 --- /dev/null +++ b/src/soft/Device.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const Instance = @import("Instance.zig"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.Device; + +interface: Interface, + +pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, infos: *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); + + interface.dispatch_table = &.{ + .destroy = destroy, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/soft/Instance.zig b/src/soft/Instance.zig index d7dd536..4ce54da 100644 --- a/src/soft/Instance.zig +++ b/src/soft/Instance.zig @@ -1,30 +1,54 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const soft_physical_device = @import("physical_device.zig"); +const PhysicalDevice = @import("PhysicalDevice.zig"); const Dispatchable = base.Dispatchable; -const VulkanAllocator = base.VulkanAllocator; + +const VkError = base.VkError; const Self = @This(); +pub const Interface = base.Instance; -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; +interface: Interface, + +export fn __vkImplCreateInstance(allocator: *const std.mem.Allocator, infos: *const vk.InstanceCreateInfo) ?*Interface { + return realVkImplInstanceInit(allocator.*, infos) catch return null; } // Pure Zig implementation to leverage `errdefer` and avoid memory leaks or complex resources handling -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 physical_device = try Dispatchable(base.PhysicalDevice).create(allocator, .{instance}); - errdefer physical_device.destroy(allocator); - - try soft_physical_device.setup(allocator, physical_device.object); - - try instance.physical_devices.append(allocator, physical_device.toVkHandle(vk.PhysicalDevice)); - +fn realVkImplInstanceInit(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) !?*Interface { const self = try allocator.create(Self); errdefer allocator.destroy(self); - return @ptrCast(self); + + self.interface = try base.Instance.init(allocator, infos); + self.interface.dispatch_table = &.{ + .requestPhysicalDevices = requestPhysicalDevices, + .releasePhysicalDevices = releasePhysicalDevices, + .destroyInstance = destroyInstance, + }; + return &self.interface; +} + +fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + // Software driver only has one physical device (the CPU) + const physical_device = try PhysicalDevice.create(allocator, interface); + errdefer physical_device.interface.releasePhysicalDevice(allocator) catch {}; + interface.physical_devices.append(allocator, try Dispatchable(PhysicalDevice.Interface).wrap(allocator, &physical_device.interface)) catch return VkError.OutOfHostMemory; +} + +fn releasePhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + defer { + interface.physical_devices.deinit(allocator); + interface.physical_devices = .empty; + } + + const physical_device = interface.physical_devices.getLast(); + try physical_device.object.releasePhysicalDevice(allocator); + physical_device.destroy(allocator); +} + +fn destroyInstance(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); } diff --git a/src/soft/PhysicalDevice.zig b/src/soft/PhysicalDevice.zig new file mode 100644 index 0000000..fcfa5bc --- /dev/null +++ b/src/soft/PhysicalDevice.zig @@ -0,0 +1,67 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const root = @import("lib.zig"); +const cpuinfo = @import("cpuinfo"); + +const Device = @import("Device.zig"); +const Instance = @import("Instance.zig"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.PhysicalDevice; + +interface: Interface, + +pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(allocator, instance); + + interface.dispatch_table = &.{ + .createDevice = createDevice, + .release = destroy, + }; + + interface.props.api_version = @bitCast(root.VULKAN_VERSION); + interface.props.driver_version = @bitCast(root.DRIVER_VERSION); + interface.props.device_id = root.DEVICE_ID; + interface.props.device_type = .cpu; + + interface.mem_props.memory_type_count = 1; + interface.mem_props.memory_types[0] = .{ + .heap_index = 0, + .property_flags = .{ + .host_visible_bit = true, + .host_coherent_bit = true, + }, + }; + interface.mem_props.memory_heap_count = 1; + interface.mem_props.memory_heaps[0] = .{ + .size = std.process.totalSystemMemory() catch 0, + .flags = .{}, // Host memory + }; + + const info = cpuinfo.get(allocator) catch return VkError.InitializationFailed; + defer info.deinit(allocator); + + var writer = std.io.Writer.fixed(interface.props.device_name[0 .. vk.MAX_PHYSICAL_DEVICE_NAME_SIZE - 1]); + writer.print("{s} [Soft Vulkan Driver]", .{info.name}) catch return VkError.InitializationFailed; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*Device.Interface { + const device = try Device.create(interface, allocator, infos); + return &device.interface; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 8a108c1..516ac76 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -2,12 +2,16 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const Device = @import("Device.zig"); 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); pub const DEVICE_ID = 0x600DCAFE; +pub const std_options = base.std_options; + comptime { _ = base; _ = Instance; diff --git a/src/soft/physical_device.zig b/src/soft/physical_device.zig deleted file mode 100644 index f14643f..0000000 --- a/src/soft/physical_device.zig +++ /dev/null @@ -1,33 +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"); - -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/Device.zig b/src/vulkan/Device.zig index e31e516..6b3b72e 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -1,15 +1,28 @@ const std = @import("std"); const vk = @import("vulkan"); -const base = @import("base"); + +const VkError = @import("error_set.zig").VkError; +const PhysicalDevice = @import("PhysicalDevice.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .device; physical_device: *const PhysicalDevice, -dispatch_table: DispatchTable, -driver_data: ?*anyopaque, +dispatch_table: *const DispatchTable, -pub const DispatchTable = struct {}; +pub const DispatchTable = struct { + destroy: *const fn (*Self, std.mem.Allocator) VkError!void, +}; -pub fn createImplDevice(physical_device: *base.PhysicalDevice, infos: vk.DeviceCreateInfo, allocator: std.mem.Allocator) !*anyopaque { +pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice, infos: *const vk.DeviceCreateInfo) VkError!Self { + _ = allocator; + _ = infos; + return .{ + .physical_device = physical_device, + .dispatch_table = undefined, + }; +} + +pub fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void { + try self.dispatch_table.destroy(self, allocator); } diff --git a/src/vulkan/Dispatchable.zig b/src/vulkan/Dispatchable.zig index 5699678..c55b20e 100644 --- a/src/vulkan/Dispatchable.zig +++ b/src/vulkan/Dispatchable.zig @@ -13,6 +13,7 @@ pub fn Dispatchable(comptime T: type) type { loader_data: c.VK_LOADER_DATA, object_type: vk.ObjectType, object: *T, + is_owner: bool = false, pub fn create(allocator: std.mem.Allocator, args: anytype) VkError!*Self { comptime { @@ -33,7 +34,12 @@ pub fn Dispatchable(comptime T: type) type { 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.is_owner = true; + return self.wrap(object); + } + pub fn wrap(allocator: std.mem.Allocator, object: *T) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; self.* = .{ .loader_data = .{ .loaderMagic = c.ICD_LOADER_MAGIC }, .object_type = T.ObjectType, @@ -43,10 +49,9 @@ pub fn Dispatchable(comptime T: type) type { } pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { - if (std.meta.hasMethod(T, "deinit")) { - self.object.deinit(allocator); + if (self.is_owner) { + allocator.destroy(self.object); } - allocator.destroy(self.object); allocator.destroy(self); } diff --git a/src/vulkan/Instance.zig b/src/vulkan/Instance.zig index 55b5417..715d028 100644 --- a/src/vulkan/Instance.zig +++ b/src/vulkan/Instance.zig @@ -1,38 +1,31 @@ const std = @import("std"); const vk = @import("vulkan"); -const root = @import("lib.zig"); const VkError = @import("error_set.zig").VkError; - -extern fn __vkImplInstanceInit(*Self, *const std.mem.Allocator, *const vk.InstanceCreateInfo) ?*anyopaque; +const Dispatchable = @import("Dispatchable.zig").Dispatchable; +const PhysicalDevice = @import("PhysicalDevice.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .instance; -physical_devices: std.ArrayList(vk.PhysicalDevice), -dispatch_table: DispatchTable, -driver_data: ?*anyopaque, +physical_devices: std.ArrayList(*Dispatchable(PhysicalDevice)), +dispatch_table: *const DispatchTable, pub const DispatchTable = struct { - destroyInstance: ?*const fn (*const Self, std.mem.Allocator) anyerror!void = null, + requestPhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void, + releasePhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void, + destroyInstance: *const fn (*Self, std.mem.Allocator) VkError!void, }; pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!Self { - var self: Self = .{ - .dispatch_table = .{}, + _ = allocator; + _ = infos; + return .{ .physical_devices = .empty, - .driver_data = null, + .dispatch_table = undefined, }; - - self.driver_data = __vkImplInstanceInit(&self, &allocator, infos) orelse return VkError.InitializationFailed; - std.debug.assert(self.physical_devices.items.len != 0); - - return self; } -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 deinit(self: *Self, allocator: std.mem.Allocator) VkError!void { + try self.dispatch_table.releasePhysicalDevices(self, allocator); + try self.dispatch_table.destroyInstance(self, allocator); } diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index dcbff30..afe54e9 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -1,8 +1,10 @@ const std = @import("std"); const vk = @import("vulkan"); const root = @import("lib.zig"); + const Instance = @import("Instance.zig"); const VkError = @import("error_set.zig").VkError; +const Device = @import("Device.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .physical_device; @@ -10,10 +12,12 @@ pub const ObjectType: vk.ObjectType = .physical_device; props: vk.PhysicalDeviceProperties, mem_props: vk.PhysicalDeviceMemoryProperties, instance: *const Instance, -dispatch_table: DispatchTable, -driver_data: ?*anyopaque, +dispatch_table: *const DispatchTable, -pub const DispatchTable = struct {}; +pub const DispatchTable = struct { + createDevice: *const fn (*Self, std.mem.Allocator, *const vk.DeviceCreateInfo) VkError!*Device, + release: *const fn (*Self, std.mem.Allocator) VkError!void, +}; pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Self { _ = allocator; @@ -35,8 +39,15 @@ pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Sel .memory_heap_count = 0, .memory_heaps = undefined, }, - .driver_data = null, .instance = instance, - .dispatch_table = .{}, + .dispatch_table = undefined, }; } + +pub fn createDevice(self: *Self, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*Device { + return try self.dispatch_table.createDevice(self, allocator, infos); +} + +pub fn releasePhysicalDevice(self: *Self, allocator: std.mem.Allocator) VkError!void { + try self.dispatch_table.release(self, allocator); +} diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 44c4001..0d7a8d7 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -2,11 +2,13 @@ const std = @import("std"); const vk = @import("vulkan"); pub const lib_vulkan = @import("lib_vulkan.zig"); +pub const logs = @import("logs.zig"); pub const Dispatchable = @import("Dispatchable.zig").Dispatchable; pub const VkError = @import("error_set.zig").VkError; pub const Instance = @import("Instance.zig"); +pub const Device = @import("Device.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const VulkanAllocator = @import("VulkanAllocator.zig"); //pub const Device = @import("Device.zig"); @@ -15,19 +17,10 @@ pub const VULKAN_VENDOR_ID = @typeInfo(vk.VendorId).@"enum".fields[@typeInfo(vk. pub const DRIVER_LOGS_ENV_NAME = "DRIVER_LOGS"; pub const std_options: std.Options = .{ - .log_level = .info, - .logFn = logFn, + .log_level = .debug, + .logFn = logs.logger, }; -pub fn logFn(comptime level: std.log.Level, comptime scope: @Type(.enum_literal), comptime format: []const u8, args: anytype) void { - _ = level; - _ = scope; - std.debug.lockStdErr(); - defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().deprecatedWriter(); - nosuspend stderr.print(format ++ "\n", args) catch return; -} - pub fn retrieveDriverDataAs(handle: anytype, comptime T: type) !*T { comptime { switch (@typeInfo(@TypeOf(handle))) { diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index a650a3c..0bc0243 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -11,11 +11,14 @@ const Dispatchable = @import("Dispatchable.zig").Dispatchable; const VulkanAllocator = @import("VulkanAllocator.zig"); const Instance = @import("Instance.zig"); +const Device = @import("Device.zig"); const PhysicalDevice = @import("PhysicalDevice.zig"); +extern fn __vkImplCreateInstance(*const std.mem.Allocator, *const vk.InstanceCreateInfo) ?*Instance; + fn functionMapElement(name: []const u8) struct { []const u8, vk.PfnVoidFunction } { if (!std.meta.hasFn(@This(), name)) { - std.log.scoped(.functionMapElement).err("Could not find function {s}", .{name}); + std.log.scoped(.vkGetInstanceProcAddr).err("Could not find function {s}", .{name}); return .{ name, null }; } return .{ name, @as(vk.PfnVoidFunction, @ptrCast(&@field(@This(), name))) }; @@ -28,24 +31,27 @@ pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const }); const instance_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ + functionMapElement("vkCreateDevice"), functionMapElement("vkDestroyInstance"), functionMapElement("vkEnumeratePhysicalDevices"), functionMapElement("vkGetPhysicalDeviceProperties"), functionMapElement("vkGetPhysicalDeviceProperties"), }); + const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ + functionMapElement("vkDestroyDevice"), + }); + 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}); - } + 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; + if (instance_pfn_map.get(name)) |pfn| return pfn; + return if (device_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 { @@ -54,20 +60,27 @@ pub export fn vkCreateInstance(p_infos: ?*const vk.InstanceCreateInfo, callbacks 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); + const handler = __vkImplCreateInstance(&allocator, infos) orelse return .error_initialization_failed; + handler.dispatch_table.requestPhysicalDevices(handler, allocator) catch |err| return toVkResult(err); + + p_instance.* = (Dispatchable(Instance).wrap(allocator, handler) 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); + const dispatchable = Dispatchable(Instance).fromHandle(p_instance) catch return; + dispatchable.object.deinit(allocator) catch {}; + dispatchable.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); + for (0..count.*) |i| { + devices[i] = self.physical_devices.items[i].toVkHandle(vk.PhysicalDevice); + } } return .success; } @@ -81,3 +94,22 @@ pub export fn vkGetPhysicalDeviceMemoryProperties(p_physical_device: vk.Physical const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return; properties.* = self.mem_props; } + +pub export fn vkCreateDevice(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 allocator = VulkanAllocator.init(callbacks, .instance).allocator(); + const physical_device = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err); + const device = physical_device.createDevice(allocator, infos) 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 vkDestroyDevice(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; + dispatchable.object.destroy(allocator) catch return; + dispatchable.destroy(allocator); +} diff --git a/src/vulkan/logs.zig b/src/vulkan/logs.zig new file mode 100644 index 0000000..52e16dc --- /dev/null +++ b/src/vulkan/logs.zig @@ -0,0 +1,48 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const root = @import("lib.zig"); + +const is_posix = switch (builtin.os.tag) { + .windows, .uefi, .wasi => false, + else => true, +}; + +pub fn logger(comptime level: std.log.Level, comptime scope: @Type(.enum_literal), comptime format: []const u8, args: anytype) void { + if (!std.process.hasEnvVarConstant(root.DRIVER_LOGS_ENV_NAME)) { + return; + } + const scope_prefix = "(" ++ @tagName(scope) ++ "): "; + const prefix = "[" ++ comptime level.asText() ++ "] "; + + const level_color: std.Io.tty.Color = switch (level) { + .info => .blue, + .warn => .yellow, + .err => .red, + .debug => .blue, + }; + + const instant = std.time.Instant.now() catch return; + const now = if (is_posix) instant.timestamp.nsec else instant.timestamp; + + std.debug.lockStdErr(); + defer std.debug.unlockStdErr(); + + var stderr_buffer: [512]u8 = undefined; + var stderr_file = std.fs.File.stderr(); + var stderr_writer = stderr_file.writer(&stderr_buffer); + var writer: *std.Io.Writer = &stderr_writer.interface; + + var out_config = std.Io.tty.Config.detect(stderr_file); + nosuspend { + out_config.setColor(writer, .magenta) catch {}; + writer.print("[Driver log {}:{}:{}]", .{ @divFloor(now, std.time.ns_per_min), @divFloor(now, std.time.ns_per_s), @divFloor(now, std.time.ns_per_ms) }) catch return; + out_config.setColor(writer, level_color) catch {}; + writer.print(prefix, .{}) catch return; + out_config.setColor(writer, .green) catch {}; + writer.print(scope_prefix, .{}) catch return; + out_config.setColor(writer, .reset) catch {}; + + writer.print(format ++ "\n", args) catch return; + writer.flush() catch return; + } +} diff --git a/test/c/main.c b/test/c/main.c index fb0d2ee..bd440c1 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -47,6 +47,8 @@ int main(void) VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) + VULKAN_INSTANCE_FUNCTION(vkCreateDevice) + VULKAN_INSTANCE_FUNCTION(vkDestroyDevice) uint32_t count; vkEnumeratePhysicalDevices(instance, &count, NULL); @@ -58,6 +60,14 @@ int main(void) vkGetPhysicalDeviceProperties(physical_devices[0], &props); printf("VkPhysicalDevice name %s\n", props.deviceName); + VkDeviceCreateInfo device_create_info = {0}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + + VkDevice device = VK_NULL_HANDLE; + CheckVk(vkCreateDevice(physical_devices[0], &device_create_info, NULL, &device)); + printf("VkDevice %p\n", device); + + vkDestroyDevice(device, NULL); vkDestroyInstance(instance, NULL); free(physical_devices);