improving architecture, adding logical device creation and destruction
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
48
src/vulkan/logs.zig
git.filemode.normal_file
48
src/vulkan/logs.zig
git.filemode.normal_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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user