From 1d447177605ed69f473d042e9477ae3f4e7c585b Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Thu, 6 Nov 2025 23:10:26 +0100 Subject: [PATCH] adding debug logs levels, implementing some physical device functions --- README.md | 4 +- src/soft/PhysicalDevice.zig | 74 ++++++++++++++++++++++++++++ src/vulkan/PhysicalDevice.zig | 34 ++++++++++++- src/vulkan/lib.zig | 25 ++++++---- src/vulkan/lib_vulkan.zig | 90 +++++++++++++++++------------------ src/vulkan/logger.zig | 17 ++++--- 6 files changed, 175 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 55f7065..cd2488d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ To understand Vulkan — not as a humble API mere mortals call upon, but as a la It does not seek to produce a performant or production-worthy driver. \ *The gods are merciful, but not that merciful.* -# Build +## Build If thou art truly determined: ``` @@ -26,7 +26,7 @@ The precise ritual varies by system — consult the tomes of your operating syst Use at your own risk. If thy machine shudders, weeps, or attempts to flee — know that it was warned. -# License +## License Released unto the world as MIT for study, experimentation, and the occasional horrified whisper. Do with it as thou wilt, but accept the consequences as thine own. diff --git a/src/soft/PhysicalDevice.zig b/src/soft/PhysicalDevice.zig index 02ad7d1..90d46e5 100644 --- a/src/soft/PhysicalDevice.zig +++ b/src/soft/PhysicalDevice.zig @@ -22,6 +22,9 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr interface.dispatch_table = &.{ .createDevice = createDevice, + .getFormatProperties = getFormatProperties, + .getImageFormatProperties = getImageFormatProperties, + .getSparseImageFormatProperties = getSparseImageFormatProperties, .release = destroy, }; @@ -44,6 +47,35 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr .flags = .{}, // Host memory }; + interface.features = .{ + .robust_buffer_access = .true, + .shader_float_64 = .true, + .shader_int_64 = .true, + .shader_int_16 = .true, + }; + + var queue_family_props = [_]vk.QueueFamilyProperties{ + .{ + .queue_flags = .{ .graphics_bit = true, .compute_bit = true, .transfer_bit = true }, + .queue_count = 1, + .timestamp_valid_bits = 0, + .min_image_transfer_granularity = .{ .width = 1, .height = 1, .depth = 1 }, + }, + .{ + .queue_flags = .{ .graphics_bit = true }, + .queue_count = 1, + .timestamp_valid_bits = 0, + .min_image_transfer_granularity = .{ .width = 1, .height = 1, .depth = 1 }, + }, + .{ + .queue_flags = .{ .transfer_bit = true }, + .queue_count = 1, + .timestamp_valid_bits = 0, + .min_image_transfer_granularity = .{ .width = 1, .height = 1, .depth = 1 }, + }, + }; + interface.queue_family_props = std.ArrayList(vk.QueueFamilyProperties).fromOwnedSlice(queue_family_props[0..]); + const info = cpuinfo.get(allocator) catch return VkError.InitializationFailed; defer info.deinit(allocator); @@ -61,6 +93,48 @@ pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos: return &device.interface; } +pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.FormatProperties { + _ = interface; + _ = format; + return .{}; +} + +pub fn getImageFormatProperties( + interface: *Interface, + format: vk.Format, + image_type: vk.ImageType, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + flags: vk.ImageCreateFlags, +) VkError!vk.ImageFormatProperties { + _ = interface; + _ = format; + _ = image_type; + _ = tiling; + _ = usage; + _ = flags; + return VkError.FormatNotSupported; +} + +pub fn getSparseImageFormatProperties( + interface: *Interface, + format: vk.Format, + image_type: vk.ImageType, + samples: vk.SampleCountFlags, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + flags: vk.ImageCreateFlags, +) VkError!vk.SparseImageFormatProperties { + _ = interface; + _ = format; + _ = image_type; + _ = samples; + _ = tiling; + _ = usage; + _ = flags; + return VkError.FormatNotSupported; +} + pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); allocator.destroy(self); diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index f4e40d4..9381203 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -11,13 +11,16 @@ pub const ObjectType: vk.ObjectType = .physical_device; props: vk.PhysicalDeviceProperties, mem_props: vk.PhysicalDeviceMemoryProperties, -format_props: vk.FormatProperties, features: vk.PhysicalDeviceFeatures, +queue_family_props: std.ArrayList(vk.QueueFamilyProperties), instance: *const Instance, dispatch_table: *const DispatchTable, pub const DispatchTable = struct { createDevice: *const fn (*Self, std.mem.Allocator, *const vk.DeviceCreateInfo) VkError!*Device, + getFormatProperties: *const fn (*Self, vk.Format) VkError!vk.FormatProperties, + getImageFormatProperties: *const fn (*Self, vk.Format, vk.ImageType, vk.ImageTiling, vk.ImageUsageFlags, vk.ImageCreateFlags) VkError!vk.ImageFormatProperties, + getSparseImageFormatProperties: *const fn (*Self, vk.Format, vk.ImageType, vk.SampleCountFlags, vk.ImageTiling, vk.ImageUsageFlags, vk.ImageCreateFlags) VkError!vk.SparseImageFormatProperties, release: *const fn (*Self, std.mem.Allocator) VkError!void, }; @@ -41,7 +44,7 @@ pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Sel .memory_heap_count = 0, .memory_heaps = undefined, }, - .format_props = .{}, + .queue_family_props = .empty, .features = .{}, .instance = instance, .dispatch_table = undefined, @@ -52,6 +55,33 @@ pub fn createDevice(self: *Self, allocator: std.mem.Allocator, infos: *const vk. return try self.dispatch_table.createDevice(self, allocator, infos); } +pub fn getFormatProperties(self: *Self, format: vk.Format) VkError!vk.FormatProperties { + return try self.dispatch_table.getFormatProperties(self, format); +} + +pub fn getImageFormatProperties( + self: *Self, + format: vk.Format, + image_type: vk.ImageType, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + flags: vk.ImageCreateFlags, +) VkError!vk.ImageFormatProperties { + return try self.dispatch_table.getImageFormatProperties(self, format, image_type, tiling, usage, flags); +} + +pub fn getSparseImageFormatProperties( + self: *Self, + format: vk.Format, + image_type: vk.ImageType, + samples: vk.SampleCountFlags, + tiling: vk.ImageTiling, + usage: vk.ImageUsageFlags, + flags: vk.ImageCreateFlags, +) VkError!vk.SparseImageFormatProperties { + return try self.dispatch_table.getSparseImageFormatProperties(self, format, image_type, samples, tiling, usage, flags); +} + pub fn releasePhysicalDevice(self: *Self, allocator: std.mem.Allocator) VkError!void { try self.dispatch_table.release(self, allocator); } diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 77d0628..190806b 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -13,21 +13,28 @@ pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const VulkanAllocator = @import("VulkanAllocator.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"; +pub const DRIVER_LOGS_ENV_NAME = "STROLL_LOGS_LEVEL"; pub const std_options: std.Options = .{ .log_level = .debug, .logFn = logger.log, }; -pub fn retrieveDriverDataAs(handle: anytype, comptime T: type) !*T { - comptime { - switch (@typeInfo(@TypeOf(handle))) { - .pointer => |p| std.debug.assert(@hasField(p.child, "driver_data")), - else => @compileError("Invalid type passed to 'retrieveDriverDataAs': " ++ @typeName(@TypeOf(handle))), - } - } - return @ptrCast(@alignCast(@field(handle, "driver_data"))); +pub const LogVerboseLevel = enum { + None, + Standard, + High, +}; + +pub inline fn getLogVerboseLevel() LogVerboseLevel { + const allocator = std.heap.page_allocator; + const level = std.process.getEnvVarOwned(allocator, DRIVER_LOGS_ENV_NAME) catch return .None; + return if (std.mem.eql(u8, level, "none")) + .None + else if (std.mem.eql(u8, level, "all")) + .High + else + .Standard; } comptime { diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index e1e45e4..d46db0c 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -1,6 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); const root = @import("root"); +const lib = @import("lib.zig"); const logger = @import("logger.zig"); const error_set = @import("error_set.zig"); @@ -17,7 +18,12 @@ const PhysicalDevice = @import("PhysicalDevice.zig"); // This file contains all exported Vulkan entrypoints. -fn functionMapElement(comptime name: []const u8) struct { []const u8, vk.PfnVoidFunction } { +fn entryPointNotFoundErrorLog(comptime scope: @Type(.enum_literal), name: []const u8) void { + if (lib.getLogVerboseLevel() != .High) return; + std.log.scoped(scope).err("Could not find function {s}", .{name}); +} + +fn functionMapEntryPoint(comptime name: []const u8) struct { []const u8, vk.PfnVoidFunction } { const stroll_name = std.fmt.comptimePrint("stroll{s}", .{name[2..]}); return if (std.meta.hasFn(@This(), name)) @@ -29,38 +35,38 @@ fn functionMapElement(comptime name: []const u8) struct { []const u8, vk.PfnVoid } const icd_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - functionMapElement("vk_icdGetInstanceProcAddr"), - functionMapElement("vk_icdGetPhysicalDeviceProcAddr"), - functionMapElement("vk_icdNegotiateLoaderICDInterfaceVersion"), + functionMapEntryPoint("vk_icdGetInstanceProcAddr"), + functionMapEntryPoint("vk_icdGetPhysicalDeviceProcAddr"), + functionMapEntryPoint("vk_icdNegotiateLoaderICDInterfaceVersion"), }); const global_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - functionMapElement("vkCreateInstance"), - functionMapElement("vkGetInstanceProcAddr"), - functionMapElement("vkEnumerateInstanceExtensionProperties"), - functionMapElement("vkEnumerateInstanceVersion"), + functionMapEntryPoint("vkCreateInstance"), + functionMapEntryPoint("vkGetInstanceProcAddr"), + functionMapEntryPoint("vkEnumerateInstanceExtensionProperties"), + functionMapEntryPoint("vkEnumerateInstanceVersion"), }); const instance_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - functionMapElement("vkDestroyInstance"), - functionMapElement("vkEnumeratePhysicalDevices"), - functionMapElement("vkGetDeviceProcAddr"), + functionMapEntryPoint("vkDestroyInstance"), + functionMapEntryPoint("vkEnumeratePhysicalDevices"), + functionMapEntryPoint("vkGetDeviceProcAddr"), }); const physical_device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - functionMapElement("vkCreateDevice"), - functionMapElement("vkEnumerateDeviceExtensionProperties"), - functionMapElement("vkGetPhysicalDeviceFormatProperties"), - functionMapElement("vkGetPhysicalDeviceFeatures"), - functionMapElement("vkGetPhysicalDeviceImageFormatProperties"), - functionMapElement("vkGetPhysicalDeviceProperties"), - functionMapElement("vkGetPhysicalDeviceMemoryProperties"), - functionMapElement("vkGetPhysicalDeviceQueueFamilyProperties"), - functionMapElement("vkGetPhysicalDeviceSparseImageFormatProperties"), + functionMapEntryPoint("vkCreateDevice"), + functionMapEntryPoint("vkEnumerateDeviceExtensionProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceFormatProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceFeatures"), + functionMapEntryPoint("vkGetPhysicalDeviceImageFormatProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceMemoryProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceQueueFamilyProperties"), + functionMapEntryPoint("vkGetPhysicalDeviceSparseImageFormatProperties"), }); const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ - functionMapElement("vkDestroyDevice"), + functionMapEntryPoint("vkDestroyDevice"), }); // ICD Interface ============================================================================================================================================= @@ -84,7 +90,7 @@ pub export fn stroll_icdGetPhysicalDeviceProcAddr(_: vk.Instance, p_name: ?[*:0] if (physical_device_pfn_map.get(name)) |pfn| return pfn; - std.log.scoped(.vk_icdGetPhysicalDeviceProcAddr).err("Could not find function {s}", .{name}); + entryPointNotFoundErrorLog(.vk_icdGetPhysicalDeviceProcAddr, name); return null; } @@ -96,14 +102,14 @@ pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const if (global_pfn_map.get(name)) |pfn| return pfn; if (p_instance == .null_handle) { - std.log.scoped(.vkGetInstanceProcAddr).err("Could not find global entrypoint {s}", .{name}); + entryPointNotFoundErrorLog(.vkGetInstanceProcAddr, name); return null; } if (instance_pfn_map.get(name)) |pfn| return pfn; if (physical_device_pfn_map.get(name)) |pfn| return pfn; if (device_pfn_map.get(name)) |pfn| return pfn; - std.log.scoped(.vkGetInstanceProcAddr).err("Could not find entrypoint {s}", .{name}); + entryPointNotFoundErrorLog(.vkGetInstanceProcAddr, name); return null; } @@ -194,9 +200,8 @@ pub export fn strollEnumerateDeviceExtensionProperties(p_physical_device: vk.Phy } pub export fn strollGetPhysicalDeviceFormatProperties(p_physical_device: vk.PhysicalDevice, format: vk.Format, properties: *vk.FormatProperties) callconv(vk.vulkan_call_conv) void { - _ = format; const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return; - properties.* = self.format_props; + properties.* = self.getFormatProperties(format) catch return; } pub export fn strollGetPhysicalDeviceFeatures(p_physical_device: vk.PhysicalDevice, features: *vk.PhysicalDeviceFeatures) callconv(vk.vulkan_call_conv) void { @@ -205,14 +210,9 @@ pub export fn strollGetPhysicalDeviceFeatures(p_physical_device: vk.PhysicalDevi } pub export fn strollGetPhysicalDeviceImageFormatProperties(p_physical_device: vk.PhysicalDevice, format: vk.Format, image_type: vk.ImageType, tiling: vk.ImageTiling, usage: vk.ImageUsageFlags, flags: vk.ImageCreateFlags, properties: *vk.ImageFormatProperties) callconv(vk.vulkan_call_conv) vk.Result { - _ = p_physical_device; - _ = format; - _ = image_type; - _ = tiling; - _ = usage; - _ = flags; - _ = properties; - return .error_format_not_supported; + const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err); + properties.* = self.getImageFormatProperties(format, image_type, tiling, usage, flags) catch |err| return toVkResult(err); + return .success; } pub export fn strollGetPhysicalDeviceProperties(p_physical_device: vk.PhysicalDevice, properties: *vk.PhysicalDeviceProperties) callconv(vk.vulkan_call_conv) void { @@ -226,9 +226,11 @@ pub export fn strollGetPhysicalDeviceMemoryProperties(p_physical_device: vk.Phys } pub export fn strollGetPhysicalDeviceQueueFamilyProperties(p_physical_device: vk.PhysicalDevice, count: *u32, properties: ?[*]vk.QueueFamilyProperties) callconv(vk.vulkan_call_conv) void { - _ = p_physical_device; - _ = properties; - count.* = 0; + const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch return; + count.* = @intCast(self.queue_family_props.items.len); + if (properties) |props| { + @memcpy(props[0..count.*], self.queue_family_props.items[0..count.*]); + } } pub export fn strollGetPhysicalDeviceSparseImageFormatProperties( @@ -241,15 +243,9 @@ pub export fn strollGetPhysicalDeviceSparseImageFormatProperties( flags: vk.ImageCreateFlags, properties: *vk.SparseImageFormatProperties, ) callconv(vk.vulkan_call_conv) vk.Result { - _ = p_physical_device; - _ = format; - _ = image_type; - _ = samples; - _ = tiling; - _ = usage; - _ = flags; - _ = properties; - return .error_format_not_supported; + const self = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err); + properties.* = self.getSparseImageFormatProperties(format, image_type, samples, tiling, usage, flags) catch |err| return toVkResult(err); + return .success; } // Device functions ========================================================================================================================================== @@ -272,6 +268,6 @@ pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u if (p_device == .null_handle) return null; if (device_pfn_map.get(name)) |pfn| return pfn; - std.log.scoped(.vkGetDeviceProcAddr).err("Could not find entrypoint {s}", .{name}); + entryPointNotFoundErrorLog(.vkGetDeviceProcAddr, name); return null; } diff --git a/src/vulkan/logger.zig b/src/vulkan/logger.zig index 4883bc6..1efd818 100644 --- a/src/vulkan/logger.zig +++ b/src/vulkan/logger.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const zdt = @import("zdt"); const root = @import("root"); +const lib = @import("lib.zig"); comptime { if (!@hasDecl(root, "DRIVER_NAME")) { @@ -12,11 +13,6 @@ comptime { } } -const is_posix = switch (builtin.os.tag) { - .windows, .uefi, .wasi => false, - else => true, -}; - var indent_level: usize = 0; pub fn indent() void { @@ -34,7 +30,7 @@ pub fn unindent() void { } pub fn log(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)) { + if (lib.getLogVerboseLevel() == .None) { return; } @@ -65,13 +61,16 @@ pub fn log(comptime level: std.log.Level, comptime scope: @Type(.enum_literal), var writer: *std.Io.Writer = &stderr_writer.interface; var out_config = std.Io.tty.Config.detect(stderr_file); - const timezone = zdt.Timezone.tzLocal(std.heap.page_allocator) catch zdt.Timezone.UTC; + var timezone = zdt.Timezone.tzLocal(std.heap.page_allocator) catch zdt.Timezone.UTC; + defer timezone.deinit(); const now = zdt.Datetime.now(.{ .tz = &timezone }) catch return; out_config.setColor(writer, .magenta) catch {}; - writer.print("[" ++ root.DRIVER_NAME ++ " StrollDriver ", .{}) catch return; + writer.print("[StrollDriver ", .{}) catch return; + out_config.setColor(writer, .cyan) catch {}; + writer.print(root.DRIVER_NAME, .{}) catch return; out_config.setColor(writer, .yellow) catch {}; - writer.print("{d:02}:{d:02}:{d:02}.{d:03}", .{ now.hour, now.minute, now.second, @divFloor(now.nanosecond, std.time.ns_per_ms) }) catch return; + writer.print(" {d:02}:{d:02}:{d:02}.{d:03}", .{ now.hour, now.minute, now.second, @divFloor(now.nanosecond, std.time.ns_per_ms) }) catch return; out_config.setColor(writer, .magenta) catch {}; writer.print("]", .{}) catch return;