adding queues and debug allocators
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Debug = std.builtin.OptimizeMode.Debug;
|
||||
|
||||
const SoftDeviceMemory = @import("SoftDeviceMemory.zig");
|
||||
const SoftFence = @import("SoftFence.zig");
|
||||
const SoftQueue = @import("SoftQueue.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
|
||||
@@ -13,7 +17,7 @@ pub const Interface = base.Device;
|
||||
const SpawnError = std.Thread.SpawnError;
|
||||
|
||||
interface: Interface,
|
||||
device_allocator: std.heap.ThreadSafeAllocator,
|
||||
device_allocator: if (builtin.mode == Debug) std.heap.DebugAllocator(.{}) else std.heap.ThreadSafeAllocator,
|
||||
workers: std.Thread.Pool,
|
||||
|
||||
pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
|
||||
@@ -22,6 +26,11 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato
|
||||
|
||||
var interface = try Interface.init(allocator, physical_device, info);
|
||||
|
||||
interface.vtable = &.{
|
||||
.createQueue = SoftQueue.create,
|
||||
.destroyQueue = SoftQueue.destroy,
|
||||
};
|
||||
|
||||
interface.dispatch_table = &.{
|
||||
.allocateMemory = allocateMemory,
|
||||
.createFence = createFence,
|
||||
@@ -35,20 +44,30 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
.device_allocator = .{ .child_allocator = std.heap.c_allocator }, // TODO: better device allocator
|
||||
.device_allocator = if (builtin.mode == Debug) .init else .{ .child_allocator = std.heap.c_allocator }, // TODO: better device allocator
|
||||
.workers = undefined,
|
||||
};
|
||||
|
||||
self.workers.init(.{ .allocator = self.interface.host_allocator.allocator() }) catch |err| return switch (err) {
|
||||
self.workers.init(.{ .allocator = self.device_allocator.allocator() }) catch |err| return switch (err) {
|
||||
SpawnError.OutOfMemory, SpawnError.LockedMemoryLimitExceeded => VkError.OutOfDeviceMemory,
|
||||
else => VkError.Unknown,
|
||||
};
|
||||
|
||||
try self.interface.createQueues(allocator, info);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
self.workers.deinit();
|
||||
|
||||
if (builtin.mode == Debug) {
|
||||
// All device memory allocations should've been freed by now
|
||||
if (!self.device_allocator.detectLeaks()) {
|
||||
std.log.scoped(.vkDestroyDevice).debug("No device memory leaks detected", .{});
|
||||
}
|
||||
}
|
||||
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@ pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo)
|
||||
|
||||
self.interface = try base.Instance.init(allocator, infos);
|
||||
self.interface.dispatch_table = &.{
|
||||
.destroyInstance = destroyInstance,
|
||||
};
|
||||
self.interface.vtable = &.{
|
||||
.requestPhysicalDevices = requestPhysicalDevices,
|
||||
.releasePhysicalDevices = releasePhysicalDevices,
|
||||
.destroyInstance = destroyInstance,
|
||||
};
|
||||
return &self.interface;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr
|
||||
.timestamp_valid_bits = 0,
|
||||
.min_image_transfer_granularity = .{ .width = 1, .height = 1, .depth = 1 },
|
||||
},
|
||||
// TODO: maybe add a compute specialized queue
|
||||
};
|
||||
interface.queue_family_props = std.ArrayList(vk.QueueFamilyProperties).fromOwnedSlice(queue_family_props[0..]);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ pub const Interface = base.Queue;
|
||||
interface: Interface,
|
||||
mutex: std.Thread.Mutex,
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, device: *const base.Device, index: u32, family_index: u32, flags: vk.DeviceQueueCreateFlags) VkError!*Self {
|
||||
pub fn create(allocator: std.mem.Allocator, device: *const base.Device, index: u32, family_index: u32, flags: vk.DeviceQueueCreateFlags) VkError!*Interface {
|
||||
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
@@ -29,7 +29,12 @@ pub fn create(allocator: std.mem.Allocator, device: *const base.Device, index: u
|
||||
.interface = interface,
|
||||
.mutex = .{},
|
||||
};
|
||||
return self;
|
||||
return &self.interface;
|
||||
}
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn bindSparse(interface: *Interface, info: []*const vk.BindSparseInfo, fence: ?*base.Fence) VkError!void {
|
||||
|
||||
@@ -13,10 +13,16 @@ const Self = @This();
|
||||
pub const ObjectType: vk.ObjectType = .device;
|
||||
|
||||
physical_device: *const PhysicalDevice,
|
||||
dispatch_table: *const DispatchTable,
|
||||
host_allocator: VulkanAllocator,
|
||||
queues: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(*Dispatchable(Queue))),
|
||||
|
||||
dispatch_table: *const DispatchTable,
|
||||
vtable: *const VTable,
|
||||
|
||||
pub const VTable = struct {
|
||||
createQueue: *const fn (std.mem.Allocator, *const Self, u32, u32, vk.DeviceQueueCreateFlags) VkError!*Queue,
|
||||
destroyQueue: *const fn (*Queue, std.mem.Allocator) VkError!void,
|
||||
};
|
||||
|
||||
pub const DispatchTable = struct {
|
||||
allocateMemory: *const fn (*Self, std.mem.Allocator, *const vk.MemoryAllocateInfo) VkError!*DeviceMemory,
|
||||
createFence: *const fn (*Self, std.mem.Allocator, *const vk.FenceCreateInfo) VkError!*Fence,
|
||||
@@ -29,15 +35,14 @@ pub const DispatchTable = struct {
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice, info: *const vk.DeviceCreateInfo) VkError!Self {
|
||||
const vulkan_allocator: *VulkanAllocator = @ptrCast(@alignCast(allocator.ptr));
|
||||
var self: Self = .{
|
||||
_ = allocator;
|
||||
_ = info;
|
||||
return .{
|
||||
.physical_device = physical_device,
|
||||
.dispatch_table = undefined,
|
||||
.host_allocator = vulkan_allocator.*,
|
||||
.queues = .empty,
|
||||
.dispatch_table = undefined,
|
||||
.vtable = undefined,
|
||||
};
|
||||
try self.createQueues(allocator, info);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createQueues(self: *Self, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!void {
|
||||
@@ -46,22 +51,31 @@ pub fn createQueues(self: *Self, allocator: std.mem.Allocator, info: *const vk.D
|
||||
} else if (info.p_queue_create_infos == null) {
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
var family_sizes: std.AutoHashMap(u32, usize) = .empty;
|
||||
defer family_sizes.deinit(allocator);
|
||||
|
||||
for (0..info.queue_create_info_count) |i| {
|
||||
const queue_info = info.p_queue_create_infos.?[i];
|
||||
const value = family_sizes.getOrPut(allocator, queue_info.queue_family_index) catch return VkError.OutOfHostMemory;
|
||||
value.value_ptr.* += @intCast(queue_info.queue_count);
|
||||
}
|
||||
const res = (self.queues.getOrPut(allocator, queue_info.queue_family_index) catch return VkError.OutOfHostMemory);
|
||||
const family_ptr = res.value_ptr;
|
||||
if (!res.found_existing) {
|
||||
family_ptr.* = .empty;
|
||||
}
|
||||
|
||||
var it = family_sizes.iterator();
|
||||
while (it.next()) |entry| {
|
||||
self.queues.put(allocator, entry.key_ptr.*, std.ArrayListUnmanaged(*Dispatchable(Queue)).initCapacity(allocator, entry.value_ptr.*)) catch return VkError.OutOfHostMemory;
|
||||
const queue = try self.vtable.createQueue(allocator, self, queue_info.queue_family_index, @intCast(family_ptr.items.len), queue_info.flags);
|
||||
const dispatchable_queue = try Dispatchable(Queue).wrap(allocator, queue);
|
||||
family_ptr.append(allocator, dispatchable_queue) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void {
|
||||
var it = self.queues.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const family = entry.value_ptr;
|
||||
for (family.items) |dispatchable_queue| {
|
||||
try self.vtable.destroyQueue(dispatchable_queue.object, allocator);
|
||||
dispatchable_queue.destroy(allocator);
|
||||
}
|
||||
family.deinit(allocator);
|
||||
}
|
||||
self.queues.deinit(allocator);
|
||||
try self.dispatch_table.destroy(self, allocator);
|
||||
}
|
||||
|
||||
@@ -20,11 +20,15 @@ pub const ObjectType: vk.ObjectType = .instance;
|
||||
|
||||
physical_devices: std.ArrayListUnmanaged(*Dispatchable(PhysicalDevice)),
|
||||
dispatch_table: *const DispatchTable,
|
||||
vtable: *const VTable,
|
||||
|
||||
pub const VTable = struct {
|
||||
releasePhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
requestPhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
};
|
||||
|
||||
pub const DispatchTable = struct {
|
||||
destroyInstance: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
releasePhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
requestPhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!Self {
|
||||
@@ -33,11 +37,12 @@ pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) V
|
||||
return .{
|
||||
.physical_devices = .empty,
|
||||
.dispatch_table = undefined,
|
||||
.vtable = undefined,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) VkError!void {
|
||||
try self.dispatch_table.releasePhysicalDevices(self, allocator);
|
||||
try self.releasePhysicalDevices(allocator);
|
||||
try self.dispatch_table.destroyInstance(self, allocator);
|
||||
}
|
||||
|
||||
@@ -61,11 +66,11 @@ pub fn enumerateVersion(version: *u32) VkError!void {
|
||||
}
|
||||
|
||||
pub fn releasePhysicalDevices(self: *Self, allocator: std.mem.Allocator) VkError!void {
|
||||
try self.dispatch_table.releasePhysicalDevices(self, allocator);
|
||||
try self.vtable.releasePhysicalDevices(self, allocator);
|
||||
}
|
||||
|
||||
pub fn requestPhysicalDevices(self: *Self, allocator: std.mem.Allocator) VkError!void {
|
||||
try self.dispatch_table.requestPhysicalDevices(self, allocator);
|
||||
try self.vtable.requestPhysicalDevices(self, allocator);
|
||||
if (self.physical_devices.items.len == 0) {
|
||||
std.log.scoped(.vkCreateInstance).info("No VkPhysicalDevice found", .{});
|
||||
return;
|
||||
|
||||
@@ -22,6 +22,7 @@ pub const DispatchTable = struct {
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, device: *const Device, index: u32, family_index: u32, flags: vk.DeviceQueueCreateFlags) VkError!Self {
|
||||
std.log.scoped(.vkCreateDevice).info("Creating device queue with family index {d} and index {d}", .{ family_index, index });
|
||||
_ = allocator;
|
||||
return .{
|
||||
.owner = device,
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const builtin = @import("builtin");
|
||||
const DRIVER_DEBUG_ALLOCATOR_ENV_NAME = @import("lib.zig").DRIVER_DEBUG_ALLOCATOR_ENV_NAME;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Alignment = std.mem.Alignment;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
|
||||
|
||||
callbacks: ?vk.AllocationCallbacks,
|
||||
scope: vk.SystemAllocationScope,
|
||||
|
||||
@@ -21,22 +25,22 @@ pub fn init(callbacks: ?*const vk.AllocationCallbacks, scope: vk.SystemAllocatio
|
||||
}
|
||||
|
||||
pub fn allocator(self: *const Self) Allocator {
|
||||
if (self.callbacks == null) {
|
||||
if (self.callbacks != null) {
|
||||
return .{
|
||||
.ptr = @constCast(self),
|
||||
.vtable = std.heap.c_allocator.vtable,
|
||||
.vtable = &.{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.remap = remap,
|
||||
.free = free,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return .{
|
||||
.ptr = @constCast(self),
|
||||
.vtable = &.{
|
||||
.alloc = alloc,
|
||||
.resize = resize,
|
||||
.remap = remap,
|
||||
.free = free,
|
||||
},
|
||||
};
|
||||
return if (std.process.hasEnvVarConstant(DRIVER_DEBUG_ALLOCATOR_ENV_NAME) or builtin.mode == std.builtin.OptimizeMode.Debug)
|
||||
debug_allocator.allocator()
|
||||
else
|
||||
std.heap.c_allocator;
|
||||
}
|
||||
|
||||
fn alloc(context: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 {
|
||||
|
||||
@@ -18,7 +18,9 @@ pub const DeviceMemory = @import("DeviceMemory.zig");
|
||||
pub const Fence = @import("Fence.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 = "STROLL_LOGS_LEVEL";
|
||||
pub const DRIVER_DEBUG_ALLOCATOR_ENV_NAME = "STROLL_DEBUG_ALLOCATOR";
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
.log_level = .debug,
|
||||
|
||||
@@ -75,6 +75,7 @@ const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{
|
||||
functionMapEntryPoint("vkDestroyDevice"),
|
||||
functionMapEntryPoint("vkCreateFence"),
|
||||
functionMapEntryPoint("vkFreeMemory"),
|
||||
functionMapEntryPoint("vkGetDeviceQueue"),
|
||||
functionMapEntryPoint("vkGetFenceStatus"),
|
||||
functionMapEntryPoint("vkMapMemory"),
|
||||
functionMapEntryPoint("vkUnmapMemory"),
|
||||
@@ -173,6 +174,13 @@ pub export fn strollDestroyInstance(p_instance: vk.Instance, callbacks: ?*const
|
||||
const dispatchable = Dispatchable(Instance).fromHandle(p_instance) catch return;
|
||||
dispatchable.object.deinit(allocator) catch {};
|
||||
dispatchable.destroy(allocator);
|
||||
|
||||
if (std.process.hasEnvVarConstant(lib.DRIVER_DEBUG_ALLOCATOR_ENV_NAME) or builtin.mode == std.builtin.OptimizeMode.Debug) {
|
||||
// All host memory allocations should've been freed by now
|
||||
if (!VulkanAllocator.debug_allocator.detectLeaks()) {
|
||||
std.log.scoped(.vkDestroyInstance).debug("No memory leaks detected", .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub export fn strollEnumeratePhysicalDevices(p_instance: vk.Instance, count: *u32, p_devices: ?[*]vk.PhysicalDevice) callconv(vk.vulkan_call_conv) vk.Result {
|
||||
@@ -330,6 +338,22 @@ pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u
|
||||
return null;
|
||||
}
|
||||
|
||||
pub export fn strollGetDeviceQueue(p_device: vk.Device, queue_family_index: u32, queue_index: u32, p_queue: *vk.Queue) callconv(vk.vulkan_call_conv) void {
|
||||
p_queue.* = .null_handle;
|
||||
const device = Dispatchable(Device).fromHandleObject(p_device) catch return;
|
||||
if (device.queues.get(queue_family_index)) |family| {
|
||||
if (queue_index >= family.items.len) return;
|
||||
|
||||
const dispatchable_queue = family.items[queue_index];
|
||||
const queue = dispatchable_queue.object;
|
||||
|
||||
// https://docs.vulkan.org/refpages/latest/refpages/source/vkGetDeviceQueue.html#VUID-vkGetDeviceQueue-flags-01841
|
||||
if (queue.flags != @TypeOf(queue.flags){}) return;
|
||||
|
||||
p_queue.* = dispatchable_queue.toVkHandle(vk.Queue);
|
||||
}
|
||||
}
|
||||
|
||||
pub export fn strollGetFenceStatus(p_device: vk.Device, p_fence: vk.Fence) callconv(vk.vulkan_call_conv) vk.Result {
|
||||
const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err);
|
||||
const fence = NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err);
|
||||
|
||||
@@ -45,10 +45,9 @@ pub fn log(comptime level: std.log.Level, comptime scope: @Type(.enum_literal),
|
||||
const prefix = std.fmt.comptimePrint("{s: <8}", .{"[" ++ comptime level.asText() ++ "] "});
|
||||
|
||||
const level_color: std.Io.tty.Color = switch (level) {
|
||||
.info => .blue,
|
||||
.info, .debug => .blue,
|
||||
.warn => .yellow,
|
||||
.err => .red,
|
||||
.debug => .blue,
|
||||
};
|
||||
|
||||
std.debug.lockStdErr();
|
||||
|
||||
@@ -69,20 +69,29 @@ int main(void)
|
||||
vkGetPhysicalDeviceProperties(physical_devices[0], &props);
|
||||
printf("VkPhysicalDevice name %s\n", props.deviceName);
|
||||
|
||||
VkDeviceQueueCreateInfo queue_create_infos = {0};
|
||||
queue_create_infos.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_create_infos.queueFamilyIndex = 1;
|
||||
queue_create_infos.queueCount = 1;
|
||||
|
||||
VkDeviceCreateInfo device_create_info = {0};
|
||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
device_create_info.queueCreateInfoCount = 1;
|
||||
device_create_info.pQueueCreateInfos = &queue_create_infos;
|
||||
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
CheckVk(vkCreateDevice(physical_devices[0], &device_create_info, NULL, &device));
|
||||
|
||||
volkLoadDevice(device);
|
||||
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
vkGetDeviceQueue(device, 1, 0, &queue);
|
||||
printf("VkQueue %p\n", queue);
|
||||
|
||||
VkFenceCreateInfo fence_info = {};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
CheckVk(vkCreateFence(device, &fence_info, NULL, &fence));
|
||||
printf("VkFence %p\n", fence);
|
||||
|
||||
vkDestroyFence(device, fence, NULL);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user