improving architecture, adding logical device creation and destruction

This commit is contained in:
2025-11-04 13:02:47 +01:00
parent 0664c3e94b
commit 31c9234a99
13 changed files with 302 additions and 103 deletions

32
src/soft/Device.zig git.filemode.normal_file
View File

@@ -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);
}

View File

@@ -1,30 +1,54 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const soft_physical_device = @import("physical_device.zig"); const PhysicalDevice = @import("PhysicalDevice.zig");
const Dispatchable = base.Dispatchable; const Dispatchable = base.Dispatchable;
const VulkanAllocator = base.VulkanAllocator;
const VkError = base.VkError;
const Self = @This(); 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 { interface: Interface,
return realVkImplInstanceInit(base_instance, allocator.*, infos) catch return null;
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 // 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 { fn realVkImplInstanceInit(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) !?*Interface {
_ = 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));
const self = try allocator.create(Self); const self = try allocator.create(Self);
errdefer allocator.destroy(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);
} }

67
src/soft/PhysicalDevice.zig git.filemode.normal_file
View File

@@ -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);
}

View File

@@ -2,12 +2,16 @@ const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const Device = @import("Device.zig");
const Instance = @import("Instance.zig"); const Instance = @import("Instance.zig");
const PhysicalDevice = @import("PhysicalDevice.zig");
pub const VULKAN_VERSION = vk.makeApiVersion(0, 1, 0, 0); pub const VULKAN_VERSION = vk.makeApiVersion(0, 1, 0, 0);
pub const DRIVER_VERSION = vk.makeApiVersion(0, 0, 0, 1); pub const DRIVER_VERSION = vk.makeApiVersion(0, 0, 0, 1);
pub const DEVICE_ID = 0x600DCAFE; pub const DEVICE_ID = 0x600DCAFE;
pub const std_options = base.std_options;
comptime { comptime {
_ = base; _ = base;
_ = Instance; _ = Instance;

View File

@@ -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});
}

View File

@@ -1,15 +1,28 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const base = @import("base");
const VkError = @import("error_set.zig").VkError;
const PhysicalDevice = @import("PhysicalDevice.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .device; pub const ObjectType: vk.ObjectType = .device;
physical_device: *const PhysicalDevice, physical_device: *const PhysicalDevice,
dispatch_table: DispatchTable, dispatch_table: *const DispatchTable,
driver_data: ?*anyopaque,
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);
} }

View File

@@ -13,6 +13,7 @@ pub fn Dispatchable(comptime T: type) type {
loader_data: c.VK_LOADER_DATA, loader_data: c.VK_LOADER_DATA,
object_type: vk.ObjectType, object_type: vk.ObjectType,
object: *T, object: *T,
is_owner: bool = false,
pub fn create(allocator: std.mem.Allocator, args: anytype) VkError!*Self { pub fn create(allocator: std.mem.Allocator, args: anytype) VkError!*Self {
comptime { comptime {
@@ -33,7 +34,12 @@ pub fn Dispatchable(comptime T: type) type {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
const object = allocator.create(T) catch return VkError.OutOfHostMemory; const object = allocator.create(T) catch return VkError.OutOfHostMemory;
object.* = try @call(.auto, T.init, .{allocator} ++ args); 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.* = .{ self.* = .{
.loader_data = .{ .loaderMagic = c.ICD_LOADER_MAGIC }, .loader_data = .{ .loaderMagic = c.ICD_LOADER_MAGIC },
.object_type = T.ObjectType, .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 { pub fn destroy(self: *Self, allocator: std.mem.Allocator) void {
if (std.meta.hasMethod(T, "deinit")) { if (self.is_owner) {
self.object.deinit(allocator);
}
allocator.destroy(self.object); allocator.destroy(self.object);
}
allocator.destroy(self); allocator.destroy(self);
} }

View File

@@ -1,38 +1,31 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const root = @import("lib.zig");
const VkError = @import("error_set.zig").VkError; const VkError = @import("error_set.zig").VkError;
const Dispatchable = @import("Dispatchable.zig").Dispatchable;
extern fn __vkImplInstanceInit(*Self, *const std.mem.Allocator, *const vk.InstanceCreateInfo) ?*anyopaque; const PhysicalDevice = @import("PhysicalDevice.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .instance; pub const ObjectType: vk.ObjectType = .instance;
physical_devices: std.ArrayList(vk.PhysicalDevice), physical_devices: std.ArrayList(*Dispatchable(PhysicalDevice)),
dispatch_table: DispatchTable, dispatch_table: *const DispatchTable,
driver_data: ?*anyopaque,
pub const DispatchTable = struct { 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 { pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!Self {
var self: Self = .{ _ = allocator;
.dispatch_table = .{}, _ = infos;
return .{
.physical_devices = .empty, .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 { pub fn deinit(self: *Self, allocator: std.mem.Allocator) VkError!void {
if (self.dispatch_table.destroyInstance) |pfnDestroyInstance| { try self.dispatch_table.releasePhysicalDevices(self, allocator);
pfnDestroyInstance(self, allocator) catch return; try self.dispatch_table.destroyInstance(self, allocator);
} else if (std.process.hasEnvVar(allocator, root.DRIVER_LOGS_ENV_NAME) catch false) {
std.log.scoped(.vkDestroyInstance).warn("Missing dispatch implementation", .{});
}
} }

View File

@@ -1,8 +1,10 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const root = @import("lib.zig"); const root = @import("lib.zig");
const Instance = @import("Instance.zig"); const Instance = @import("Instance.zig");
const VkError = @import("error_set.zig").VkError; const VkError = @import("error_set.zig").VkError;
const Device = @import("Device.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .physical_device; pub const ObjectType: vk.ObjectType = .physical_device;
@@ -10,10 +12,12 @@ pub const ObjectType: vk.ObjectType = .physical_device;
props: vk.PhysicalDeviceProperties, props: vk.PhysicalDeviceProperties,
mem_props: vk.PhysicalDeviceMemoryProperties, mem_props: vk.PhysicalDeviceMemoryProperties,
instance: *const Instance, instance: *const Instance,
dispatch_table: DispatchTable, dispatch_table: *const DispatchTable,
driver_data: ?*anyopaque,
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 { pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Self {
_ = allocator; _ = allocator;
@@ -35,8 +39,15 @@ pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Sel
.memory_heap_count = 0, .memory_heap_count = 0,
.memory_heaps = undefined, .memory_heaps = undefined,
}, },
.driver_data = null,
.instance = instance, .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);
}

View File

@@ -2,11 +2,13 @@ const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
pub const lib_vulkan = @import("lib_vulkan.zig"); pub const lib_vulkan = @import("lib_vulkan.zig");
pub const logs = @import("logs.zig");
pub const Dispatchable = @import("Dispatchable.zig").Dispatchable; pub const Dispatchable = @import("Dispatchable.zig").Dispatchable;
pub const VkError = @import("error_set.zig").VkError; pub const VkError = @import("error_set.zig").VkError;
pub const Instance = @import("Instance.zig"); pub const Instance = @import("Instance.zig");
pub const Device = @import("Device.zig");
pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig");
pub const VulkanAllocator = @import("VulkanAllocator.zig"); pub const VulkanAllocator = @import("VulkanAllocator.zig");
//pub const Device = @import("Device.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 DRIVER_LOGS_ENV_NAME = "DRIVER_LOGS";
pub const std_options: std.Options = .{ pub const std_options: std.Options = .{
.log_level = .info, .log_level = .debug,
.logFn = logFn, .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 { pub fn retrieveDriverDataAs(handle: anytype, comptime T: type) !*T {
comptime { comptime {
switch (@typeInfo(@TypeOf(handle))) { switch (@typeInfo(@TypeOf(handle))) {

View File

@@ -11,11 +11,14 @@ const Dispatchable = @import("Dispatchable.zig").Dispatchable;
const VulkanAllocator = @import("VulkanAllocator.zig"); const VulkanAllocator = @import("VulkanAllocator.zig");
const Instance = @import("Instance.zig"); const Instance = @import("Instance.zig");
const Device = @import("Device.zig");
const PhysicalDevice = @import("PhysicalDevice.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 } { fn functionMapElement(name: []const u8) struct { []const u8, vk.PfnVoidFunction } {
if (!std.meta.hasFn(@This(), name)) { 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, null };
} }
return .{ name, @as(vk.PfnVoidFunction, @ptrCast(&@field(@This(), name))) }; 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(.{ const instance_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapElement("vkCreateDevice"),
functionMapElement("vkDestroyInstance"), functionMapElement("vkDestroyInstance"),
functionMapElement("vkEnumeratePhysicalDevices"), functionMapElement("vkEnumeratePhysicalDevices"),
functionMapElement("vkGetPhysicalDeviceProperties"), functionMapElement("vkGetPhysicalDeviceProperties"),
functionMapElement("vkGetPhysicalDeviceProperties"), functionMapElement("vkGetPhysicalDeviceProperties"),
}); });
const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
functionMapElement("vkDestroyDevice"),
});
if (p_name == null) { if (p_name == null) {
return null; return null;
} }
const name = std.mem.span(p_name.?); 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 (global_pfn_map.get(name)) |pfn| return pfn;
if (p_instance == .null_handle) return null; 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 { 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; return .error_initialization_failed;
} }
const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); 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; return .success;
} }
pub export fn vkDestroyInstance(p_instance: vk.Instance, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { 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(); 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 { 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); const self = Dispatchable(Instance).fromHandleObject(p_instance) catch |err| return toVkResult(err);
count.* = @intCast(self.physical_devices.items.len); count.* = @intCast(self.physical_devices.items.len);
if (p_devices) |devices| { 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; 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; const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return;
properties.* = self.mem_props; 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);
}

48
src/vulkan/logs.zig git.filemode.normal_file
View File

@@ -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;
}
}

View File

@@ -47,6 +47,8 @@ int main(void)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) VULKAN_INSTANCE_FUNCTION(vkDestroyInstance)
VULKAN_INSTANCE_FUNCTION(vkCreateDevice)
VULKAN_INSTANCE_FUNCTION(vkDestroyDevice)
uint32_t count; uint32_t count;
vkEnumeratePhysicalDevices(instance, &count, NULL); vkEnumeratePhysicalDevices(instance, &count, NULL);
@@ -58,6 +60,14 @@ int main(void)
vkGetPhysicalDeviceProperties(physical_devices[0], &props); vkGetPhysicalDeviceProperties(physical_devices[0], &props);
printf("VkPhysicalDevice name %s\n", props.deviceName); 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); vkDestroyInstance(instance, NULL);
free(physical_devices); free(physical_devices);