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