diff --git a/.gitignore b/.gitignore index dcd4970..6f74ebc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,6 @@ scripts/__pycache__/ *.o .gdb_history *.json -*.png -!logo.png *.bin *.qpa *.xml diff --git a/build.zig b/build.zig index 97ea782..7d2f78a 100644 --- a/build.zig +++ b/build.zig @@ -175,7 +175,13 @@ pub fn build(b: *std.Build) !void { const install_step = b.step(impl.name, b.fmt("Build libvulkan_{s}", .{impl.name})); install_step.dependOn(&lib_install.step); - const lib_tests = b.addTest(.{ .root_module = lib_mod }); + const lib_tests = b.addTest(.{ + .root_module = lib_mod, + .test_runner = .{ + .path = b.path("test/test_runner.zig"), + .mode = .simple, + }, + }); const run_tests = b.addRunArtifact(lib_tests); const test_step = b.step(b.fmt("test-{s}", .{impl.name}), b.fmt("Run libvulkan_{s} tests", .{impl.name})); diff --git a/src/ape/ApeInstance.zig b/src/ape/ApeInstance.zig index 8dd8efd..96e8de6 100644 --- a/src/ape/ApeInstance.zig +++ b/src/ape/ApeInstance.zig @@ -6,7 +6,6 @@ const soft = @import("soft"); const flint = @import("flint"); const phi = @import("phi"); -const Dispatchable = base.Dispatchable; const VkError = base.VkError; const Self = @This(); @@ -37,15 +36,15 @@ pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) }; const soft_instance = try soft.Instance.create(allocator, infos); - errdefer soft_instance.deinit(allocator) catch {}; + errdefer soft_instance.deinit(allocator) catch @panic("Caught an error while handling an error"); self.backend_instances.append(allocator, soft_instance) catch return VkError.OutOfHostMemory; const flint_instance = try flint.Instance.create(allocator, infos); - errdefer flint_instance.deinit(allocator) catch {}; + errdefer flint_instance.deinit(allocator) catch @panic("Caught an error while handling an error"); self.backend_instances.append(allocator, flint_instance) catch return VkError.OutOfHostMemory; const phi_instance = try phi.Instance.create(allocator, infos); - errdefer phi_instance.deinit(allocator) catch {}; + errdefer phi_instance.deinit(allocator) catch @panic("Caught an error while handling an error"); self.backend_instances.append(allocator, phi_instance) catch return VkError.OutOfHostMemory; return &self.interface; @@ -68,7 +67,7 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _ fn appendBackendPhysicalDevices(self: *Self, allocator: std.mem.Allocator, backend: *Interface) VkError!void { try backend.requestPhysicalDevices(allocator); - errdefer backend.releasePhysicalDevices(allocator) catch {}; + errdefer backend.releasePhysicalDevices(allocator) catch @panic("Caught an error while handling an error"); self.interface.physical_devices.appendSlice(allocator, backend.physical_devices.items) catch return VkError.OutOfHostMemory; backend.physical_devices.deinit(allocator); diff --git a/src/intel/FlintBinarySemaphore.zig b/src/intel/FlintBinarySemaphore.zig index 4e0dfc9..80e4ea7 100644 --- a/src/intel/FlintBinarySemaphore.zig +++ b/src/intel/FlintBinarySemaphore.zig @@ -4,7 +4,6 @@ const base = @import("base"); const kmd = @import("kmd.zig"); const VkError = base.VkError; -const Device = base.Device; const FlintDevice = @import("FlintDevice.zig"); const drm_syncobj_create = 0xbf; @@ -159,5 +158,5 @@ fn destroyHandle(device: *FlintDevice, io: std.Io, handle: u32) void { io, kmd.drmIoctlIowr(drm_syncobj_destroy, SyncObjDestroy), &destroy_info, - ) catch {}; + ) catch @panic("Caught an error while handling an error"); } diff --git a/src/intel/FlintBuffer.zig b/src/intel/FlintBuffer.zig index ccdce50..1bc22b5 100644 --- a/src/intel/FlintBuffer.zig +++ b/src/intel/FlintBuffer.zig @@ -2,10 +2,8 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const lib = @import("lib.zig"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Buffer; diff --git a/src/intel/FlintBufferView.zig b/src/intel/FlintBufferView.zig index 046a07a..2b2b66b 100644 --- a/src/intel/FlintBufferView.zig +++ b/src/intel/FlintBufferView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.BufferView; diff --git a/src/intel/FlintCommandBuffer.zig b/src/intel/FlintCommandBuffer.zig index d2914a2..0c99444 100644 --- a/src/intel/FlintCommandBuffer.zig +++ b/src/intel/FlintCommandBuffer.zig @@ -5,8 +5,6 @@ const kmd = @import("kmd.zig"); const VkError = base.VkError; const FlintDevice = @import("FlintDevice.zig"); -const FlintDeviceMemory = @import("FlintDeviceMemory.zig"); -const FlintImage = @import("FlintImage.zig"); const MemoryRange = @import("MemoryRange.zig"); @@ -96,7 +94,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn submitGpuBatch(self: *Self, syncs: []const kmd.SyncDependency) VkError!void { try self.interface.submit(); - defer self.interface.finish() catch {}; + defer self.interface.finish() catch @panic("Caught an error while handling an error"); if (self.batch.items.len == 0) return; diff --git a/src/intel/FlintCommandPool.zig b/src/intel/FlintCommandPool.zig index f44b947..df4146f 100644 --- a/src/intel/FlintCommandPool.zig +++ b/src/intel/FlintCommandPool.zig @@ -2,9 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const NonDispatchable = base.NonDispatchable; const VkError = base.VkError; -const Device = base.Device; const FlintCommandBuffer = @import("FlintCommandBuffer.zig"); diff --git a/src/intel/FlintDescriptorPool.zig b/src/intel/FlintDescriptorPool.zig index c390577..6640041 100644 --- a/src/intel/FlintDescriptorPool.zig +++ b/src/intel/FlintDescriptorPool.zig @@ -3,9 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const VulkanAllocator = base.VulkanAllocator; - -const Device = base.Device; const Self = @This(); pub const Interface = base.DescriptorPool; diff --git a/src/intel/FlintDescriptorSetLayout.zig b/src/intel/FlintDescriptorSetLayout.zig index b2d706e..079b64b 100644 --- a/src/intel/FlintDescriptorSetLayout.zig +++ b/src/intel/FlintDescriptorSetLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.DescriptorSetLayout; diff --git a/src/intel/FlintEvent.zig b/src/intel/FlintEvent.zig index 68b9b0e..94858e9 100644 --- a/src/intel/FlintEvent.zig +++ b/src/intel/FlintEvent.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Event; diff --git a/src/intel/FlintFence.zig b/src/intel/FlintFence.zig index 16659f8..e07fc25 100644 --- a/src/intel/FlintFence.zig +++ b/src/intel/FlintFence.zig @@ -170,7 +170,7 @@ fn destroyHandle(device: *FlintDevice, io: std.Io, handle: u32) void { io, kmd.drmIoctlIowr(drm_syncobj_destroy, SyncObjDestroy), &destroy_info, - ) catch {}; + ) catch @panic("ioctl failed"); } fn absoluteTimeout(io: std.Io, timeout: u64) i64 { diff --git a/src/intel/FlintImageView.zig b/src/intel/FlintImageView.zig index db0956b..86da242 100644 --- a/src/intel/FlintImageView.zig +++ b/src/intel/FlintImageView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.ImageView; diff --git a/src/intel/FlintInstance.zig b/src/intel/FlintInstance.zig index 9a101b2..93fa669 100644 --- a/src/intel/FlintInstance.zig +++ b/src/intel/FlintInstance.zig @@ -80,17 +80,17 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, d defer version.deinit(allocator); const kmd_type: lib.KmdType = if (std.mem.eql(u8, version.name, "i915")) - .I915 + .i915 else if (std.mem.eql(u8, version.name, "xe")) - .Xe + .xe else - .Invalid; + .invalid; - if (kmd_type == .Invalid) + if (kmd_type == .invalid) continue; const physical_device = try FlintPhysicalDevice.create(allocator, interface, &drm_device, kmd_type); - errdefer physical_device.interface.release(allocator) catch {}; + errdefer physical_device.interface.release(allocator) catch @panic("Caught an error while handling an error"); const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface); errdefer dispatchable.destroy(allocator); diff --git a/src/intel/FlintPhysicalDevice.zig b/src/intel/FlintPhysicalDevice.zig index cc47b2b..db4865f 100644 --- a/src/intel/FlintPhysicalDevice.zig +++ b/src/intel/FlintPhysicalDevice.zig @@ -9,7 +9,6 @@ const pci_ids = @import("pci_ids.zig").map; const FlintDevice = @import("FlintDevice.zig"); const VkError = base.VkError; -const VulkanAllocator = base.VulkanAllocator; const SurfaceKHR = base.SurfaceKHR; const Self = @This(); @@ -79,7 +78,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device break; } - interface.props.pipeline_cache_uuid = undefined; + interface.props.pipeline_cache_uuid = @splat(0); interface.props.limits = .{ .max_image_dimension_1d = 4096, .max_image_dimension_2d = 4096, @@ -867,10 +866,10 @@ fn cpuid(leaf_id: u32, subleaf_id: u32) CpuidRegs { } } - var eax: u32 = undefined; - var ebx: u32 = undefined; - var ecx: u32 = undefined; - var edx: u32 = undefined; + var eax: u32 = 0; + var ebx: u32 = 0; + var ecx: u32 = 0; + var edx: u32 = 0; asm volatile ("cpuid" : [_] "={eax}" (eax), diff --git a/src/intel/FlintPipelineLayout.zig b/src/intel/FlintPipelineLayout.zig index 3f0bfc7..f867936 100644 --- a/src/intel/FlintPipelineLayout.zig +++ b/src/intel/FlintPipelineLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.PipelineLayout; diff --git a/src/intel/FlintQueryPool.zig b/src/intel/FlintQueryPool.zig index eca39ba..4f8523d 100644 --- a/src/intel/FlintQueryPool.zig +++ b/src/intel/FlintQueryPool.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.QueryPool; diff --git a/src/intel/FlintRenderPass.zig b/src/intel/FlintRenderPass.zig index cf56459..68063a9 100644 --- a/src/intel/FlintRenderPass.zig +++ b/src/intel/FlintRenderPass.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.RenderPass; diff --git a/src/intel/blitter.zig b/src/intel/blitter.zig index 78109b4..8618850 100644 --- a/src/intel/blitter.zig +++ b/src/intel/blitter.zig @@ -1,7 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const kmd = @import("kmd.zig"); const VkError = base.VkError; const FlintImage = @import("FlintImage.zig"); @@ -158,7 +157,7 @@ fn bitwiseCompatibleFormats(src: vk.Format, dst: vk.Format) bool { fn nearestBlitCoordinate(src_0: i32, src_1: i32, dst_0: i32, dst_1: i32, dst: i32, extent: u32) usize { const numerator = @as(i64, 2 * (dst - dst_0) + 1) * @as(i64, src_1 - src_0); - const denominator = @as(i64, 2 * (dst_1 - dst_0)); + const denominator: i64 = 2 * (dst_1 - dst_0); const coordinate = @as(i64, src_0) + @divFloor(numerator, denominator); return @intCast(std.math.clamp(coordinate, 0, @as(i64, extent) - 1)); } diff --git a/src/intel/i915/drm.zig b/src/intel/i915/i915.zig similarity index 72% rename from src/intel/i915/drm.zig rename to src/intel/i915/i915.zig index fddd156..b07bb47 100644 --- a/src/intel/i915/drm.zig +++ b/src/intel/i915/i915.zig @@ -1,19 +1,18 @@ -const vk = @import("vulkan"); pub const command_base = 0x40; -pub const i915_gem_create = 0x1b; -pub const i915_gem_mmap_gtt = 0x24; -pub const i915_gem_set_domain = 0x1f; -pub const i915_gem_execbuffer2 = 0x29; +pub const gem_create = 0x1b; +pub const gem_mmap_gtt = 0x24; +pub const gem_set_domain = 0x1f; +pub const gem_execbuffer2 = 0x29; pub const gem_close = 0x09; -pub const i915_mmap_offset_wb = 2; -pub const i915_gem_domain_cpu = 0x00000001; -pub const i915_gem_domain_gtt = 0x00000040; -pub const i915_exec_blt = 3 << 0; -pub const i915_exec_fence_array: u64 = 1 << 19; -pub const i915_exec_fence_wait: u32 = 1 << 0; -pub const i915_exec_fence_signal: u32 = 1 << 1; +pub const mmap_offset_wb = 2; +pub const gem_domain_cpu = 0x00000001; +pub const gem_domain_gtt = 0x00000040; +pub const exec_blt = 3 << 0; +pub const exec_fence_array: u64 = 1 << 19; +pub const exec_fence_wait: u32 = 1 << 0; +pub const exec_fence_signal: u32 = 1 << 1; pub const exec_object_write = 1 << 2; pub const mi_flush_dw: u32 = (0x26 << 23) | 3; diff --git a/src/intel/i915/kmd.zig b/src/intel/i915/kmd.zig index 39931e8..b5064ae 100644 --- a/src/intel/i915/kmd.zig +++ b/src/intel/i915/kmd.zig @@ -2,13 +2,11 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const drm = @import("drm.zig"); +const _i915 = @import("i915.zig"); const common_kmd = @import("../kmd.zig"); const VkError = base.VkError; -const IOCTL = std.os.linux.IOCTL; - const Mapping = struct { bytes: []align(std.heap.page_size_min) u8, @@ -33,12 +31,17 @@ pub const Device = struct { } pub fn allocateMemory(self: *Device, io: std.Io, size: vk.DeviceSize) VkError!Memory { - var create = drm.GemCreate{ + var create = _i915.GemCreate{ .size = size, .handle = 0, .pad = 0, }; - base.utils.ioctl(self.card.handle, io, common_kmd.drmIoctlIowr(drm.command_base + drm.i915_gem_create, drm.GemCreate), &create) catch return VkError.OutOfDeviceMemory; + base.utils.ioctl( + self.card.handle, + io, + common_kmd.drmIoctlIowr(_i915.command_base + _i915.gem_create, _i915.GemCreate), + &create, + ) catch return VkError.OutOfDeviceMemory; var memory = Memory{ .handle = create.handle, @@ -47,7 +50,7 @@ pub const Device = struct { }; errdefer memory.deinit(self, io); - try memory.setDomain(self, io, drm.i915_gem_domain_cpu, 0); + try memory.setDomain(self, io, _i915.gem_domain_cpu, 0); return memory; } @@ -61,7 +64,7 @@ pub const Device = struct { const batch_map = try batch.map(self, io, 0, batch_size); const batch_words = std.mem.bytesAsSlice(u32, batch_map); @memcpy(batch_words[0..commands.len], commands); - batch_words[commands.len + 0] = drm.mi_flush_dw; + batch_words[commands.len + 0] = _i915.mi_flush_dw; batch_words[commands.len + 1] = 0; batch_words[commands.len + 2] = 0; batch_words[commands.len + 3] = 0; @@ -71,7 +74,7 @@ pub const Device = struct { } try batch.flushRange(self, io, 0, batch_size); - var objects = std.ArrayList(drm.ExecObject2).empty; + var objects = std.ArrayList(_i915.ExecObject2).empty; defer objects.deinit(allocator); var object_handles = std.ArrayList(u32).empty; @@ -86,17 +89,17 @@ pub const Device = struct { .relocs_ptr = 0, .alignment = 0, .offset = 0, - .flags = if (relocation.write) drm.exec_object_write else 0, + .flags = if (relocation.write) _i915.exec_object_write else 0, .rsvd1 = 0, .rsvd2 = 0, }) catch return VkError.OutOfHostMemory; } else if (relocation.write) { const index = std.mem.indexOfScalar(u32, object_handles.items, relocation.target_handle).?; - objects.items[index].flags |= drm.exec_object_write; + objects.items[index].flags |= _i915.exec_object_write; } } - var i915_relocations = std.ArrayList(drm.RelocationEntry).empty; + var i915_relocations = std.ArrayList(_i915.RelocationEntry).empty; defer i915_relocations.deinit(allocator); for (relocations) |relocation| { @@ -121,17 +124,16 @@ pub const Device = struct { .rsvd2 = 0, }) catch return VkError.OutOfHostMemory; - var exec_fences = std.ArrayList(drm.ExecFence).empty; + var exec_fences = std.ArrayList(_i915.ExecFence).empty; defer exec_fences.deinit(allocator); for (syncs) |sync| { exec_fences.append(allocator, .{ .handle = sync.handle, - .flags = (if (sync.wait) drm.i915_exec_fence_wait else 0) | - (if (sync.signal) drm.i915_exec_fence_signal else 0), + .flags = (if (sync.wait) _i915.exec_fence_wait else 0) | (if (sync.signal) _i915.exec_fence_signal else 0), }) catch return VkError.OutOfHostMemory; } - var execbuffer = drm.ExecBuffer2{ + var execbuffer = _i915.ExecBuffer2{ .buffers_ptr = @intFromPtr(objects.items.ptr), .buffer_count = @intCast(objects.items.len), .batch_start_offset = 0, @@ -140,11 +142,16 @@ pub const Device = struct { .DR4 = 0, .num_cliprects = @intCast(exec_fences.items.len), .cliprects_ptr = if (exec_fences.items.len == 0) 0 else @intFromPtr(exec_fences.items.ptr), - .flags = drm.i915_exec_blt | (if (exec_fences.items.len == 0) 0 else drm.i915_exec_fence_array), + .flags = _i915.exec_blt | (if (exec_fences.items.len == 0) 0 else _i915.exec_fence_array), .rsvd1 = 0, .rsvd2 = 0, }; - base.utils.ioctl(self.card.handle, io, common_kmd.drmIoctlIowr(drm.command_base + drm.i915_gem_execbuffer2, drm.ExecBuffer2), &execbuffer) catch return VkError.DeviceLost; + base.utils.ioctl( + self.card.handle, + io, + common_kmd.drmIoctlIowr(_i915.command_base + _i915.gem_execbuffer2, _i915.ExecBuffer2), + &execbuffer, + ) catch return VkError.DeviceLost; } }; @@ -156,11 +163,11 @@ pub const Memory = struct { pub fn deinit(self: *Memory, device: *Device, io: std.Io) void { self.unmap(); - var close = drm.GemClose{ + var close = _i915.GemClose{ .handle = self.handle, .pad = 0, }; - base.utils.ioctl(device.card.handle, io, common_kmd.drmIoctlIow(drm.gem_close, drm.GemClose), &close) catch {}; + base.utils.ioctl(device.card.handle, io, common_kmd.drmIoctlIow(_i915.gem_close, _i915.GemClose), &close) catch @panic("Caught an error while handling an error"); self.* = undefined; } @@ -176,14 +183,19 @@ pub const Memory = struct { return mapping.slice(offset, map_size); } - var mmap_offset = drm.GemMmapOffset{ + var mmap_offset = _i915.GemMmapOffset{ .handle = self.handle, .pad = 0, .offset = 0, - .flags = drm.i915_mmap_offset_wb, + .flags = _i915.mmap_offset_wb, .extensions = 0, }; - base.utils.ioctl(device.card.handle, io, common_kmd.drmIoctlIowr(drm.command_base + drm.i915_gem_mmap_gtt, drm.GemMmapOffset), &mmap_offset) catch return VkError.MemoryMapFailed; + base.utils.ioctl( + device.card.handle, + io, + common_kmd.drmIoctlIowr(_i915.command_base + _i915.gem_mmap_gtt, _i915.GemMmapOffset), + &mmap_offset, + ) catch return VkError.MemoryMapFailed; if (self.size > std.math.maxInt(usize)) return VkError.MemoryMapFailed; const full_size: usize = @intCast(self.size); @@ -210,21 +222,26 @@ pub const Memory = struct { pub fn flushRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { _ = offset; _ = size; - try self.setDomain(device, io, drm.i915_gem_domain_cpu, 0); + try self.setDomain(device, io, _i915.gem_domain_cpu, 0); } pub fn invalidateRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { _ = offset; _ = size; - try self.setDomain(device, io, drm.i915_gem_domain_cpu, 0); + try self.setDomain(device, io, _i915.gem_domain_cpu, 0); } fn setDomain(self: *Memory, device: *Device, io: std.Io, read_domains: u32, write_domain: u32) VkError!void { - var domain = drm.GemSetDomain{ + var domain = _i915.GemSetDomain{ .handle = self.handle, .read_domains = read_domains, .write_domain = write_domain, }; - base.utils.ioctl(device.card.handle, io, common_kmd.drmIoctlIow(drm.command_base + drm.i915_gem_set_domain, drm.GemSetDomain), &domain) catch return VkError.DeviceLost; + base.utils.ioctl( + device.card.handle, + io, + common_kmd.drmIoctlIow(_i915.command_base + _i915.gem_set_domain, _i915.GemSetDomain), + &domain, + ) catch return VkError.DeviceLost; } }; diff --git a/src/intel/kmd.zig b/src/intel/kmd.zig index 43afdb0..299b775 100644 --- a/src/intel/kmd.zig +++ b/src/intel/kmd.zig @@ -1,7 +1,8 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const lib = @import("lib.zig"); + +const KmdType = @import("lib.zig").KmdType; const FlintPhysicalDevice = @import("FlintPhysicalDevice.zig"); const i915_kmd = @import("i915/kmd.zig"); @@ -32,128 +33,128 @@ pub const SyncDependency = struct { signal: bool = false, }; -pub const Device = union(lib.KmdType) { - Invalid: void, - I915: i915_kmd.Device, - Xe: xe.Device, +pub const Device = union(KmdType) { + invalid: void, + i915: i915_kmd.Device, + xe: xe.Device, pub fn open(io: std.Io, physical_device: *const FlintPhysicalDevice) VkError!Device { return switch (physical_device.kmd_type) { - .I915 => .{ .I915 = try i915_kmd.Device.open(io, physical_device.getNodePath()) }, - .Xe => .{ .Xe = try xe.Device.open(io, physical_device.getNodePath()) }, - .Invalid => VkError.InitializationFailed, + .i915 => .{ .i915 = try i915_kmd.Device.open(io, physical_device.getNodePath()) }, + .xe => .{ .xe = try xe.Device.open(io, physical_device.getNodePath()) }, + .invalid => VkError.InitializationFailed, }; } pub fn close(self: *Device, io: std.Io) void { switch (self.*) { - .I915 => |*device| device.close(io), - .Xe => |*device| device.close(io), - .Invalid => {}, + .i915 => |*device| device.close(io), + .xe => |*device| device.close(io), + .invalid => {}, } - self.* = .{ .Invalid = {} }; + self.* = .{ .invalid = {} }; } pub fn allocateMemory(self: *Device, io: std.Io, size: vk.DeviceSize) VkError!Memory { return switch (self.*) { - .I915 => |*device| .{ .I915 = try device.allocateMemory(io, size) }, - .Xe => |*device| .{ .Xe = try device.allocateMemory(io, size) }, - .Invalid => VkError.OutOfDeviceMemory, + .i915 => |*device| .{ .i915 = try device.allocateMemory(io, size) }, + .xe => |*device| .{ .xe = try device.allocateMemory(io, size) }, + .invalid => VkError.OutOfDeviceMemory, }; } pub fn submitBatch(self: *Device, io: std.Io, allocator: std.mem.Allocator, commands: []const u32, relocations: []const Relocation, syncs: []const SyncDependency) VkError!void { return switch (self.*) { - .I915 => |*device| device.submitBatch(io, allocator, commands, relocations, syncs), - .Xe => |*device| device.submitBatch(io, allocator, commands, relocations, syncs), - .Invalid => VkError.DeviceLost, + .i915 => |*device| device.submitBatch(io, allocator, commands, relocations, syncs), + .xe => |*device| device.submitBatch(io, allocator, commands, relocations, syncs), + .invalid => VkError.DeviceLost, }; } pub fn file(self: *Device) VkError!std.Io.File { return switch (self.*) { - .I915 => |*device| device.card.handle, - .Xe => |*device| device.card.handle, - .Invalid => VkError.DeviceLost, + .i915 => |*device| device.card.handle, + .xe => |*device| device.card.handle, + .invalid => VkError.DeviceLost, }; } }; -pub const Memory = union(lib.KmdType) { - Invalid: void, - I915: i915_kmd.Memory, - Xe: xe.Memory, +pub const Memory = union(KmdType) { + invalid: void, + i915: i915_kmd.Memory, + xe: xe.Memory, pub fn deinit(self: *Memory, device: *Device, io: std.Io) void { switch (self.*) { - .I915 => |*memory| switch (device.*) { - .I915 => |*adapter| memory.deinit(adapter, io), + .i915 => |*memory| switch (device.*) { + .i915 => |*adapter| memory.deinit(adapter, io), else => {}, }, - .Xe => |*memory| switch (device.*) { - .Xe => |*adapter| memory.deinit(adapter, io), + .xe => |*memory| switch (device.*) { + .xe => |*adapter| memory.deinit(adapter, io), else => {}, }, - .Invalid => {}, + .invalid => {}, } - self.* = .{ .Invalid = {} }; + self.* = .{ .invalid = {} }; } pub fn map(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 { return switch (self.*) { - .I915 => |*memory| switch (device.*) { - .I915 => |*adapter| memory.map(adapter, io, offset, size), + .i915 => |*memory| switch (device.*) { + .i915 => |*adapter| memory.map(adapter, io, offset, size), else => VkError.MemoryMapFailed, }, - .Xe => |*memory| switch (device.*) { - .Xe => |*adapter| memory.map(adapter, io, offset, size), + .xe => |*memory| switch (device.*) { + .xe => |*adapter| memory.map(adapter, io, offset, size), else => VkError.MemoryMapFailed, }, - .Invalid => VkError.MemoryMapFailed, + .invalid => VkError.MemoryMapFailed, }; } pub fn unmap(self: *Memory) void { switch (self.*) { - .I915 => |*memory| memory.unmap(), - .Xe => |*memory| memory.unmap(), - .Invalid => {}, + .i915 => |*memory| memory.unmap(), + .xe => |*memory| memory.unmap(), + .invalid => {}, } } pub fn flushRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { return switch (self.*) { - .I915 => |*memory| switch (device.*) { - .I915 => |*adapter| memory.flushRange(adapter, io, offset, size), + .i915 => |*memory| switch (device.*) { + .i915 => |*adapter| memory.flushRange(adapter, io, offset, size), else => VkError.InvalidDeviceMemoryDrv, }, - .Xe => |*memory| switch (device.*) { - .Xe => |*adapter| memory.flushRange(adapter, io, offset, size), + .xe => |*memory| switch (device.*) { + .xe => |*adapter| memory.flushRange(adapter, io, offset, size), else => VkError.InvalidDeviceMemoryDrv, }, - .Invalid => VkError.InvalidDeviceMemoryDrv, + .invalid => VkError.InvalidDeviceMemoryDrv, }; } pub fn invalidateRange(self: *Memory, device: *Device, io: std.Io, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!void { return switch (self.*) { - .I915 => |*memory| switch (device.*) { - .I915 => |*adapter| memory.invalidateRange(adapter, io, offset, size), + .i915 => |*memory| switch (device.*) { + .i915 => |*adapter| memory.invalidateRange(adapter, io, offset, size), else => VkError.InvalidDeviceMemoryDrv, }, - .Xe => |*memory| switch (device.*) { - .Xe => |*adapter| memory.invalidateRange(adapter, io, offset, size), + .xe => |*memory| switch (device.*) { + .xe => |*adapter| memory.invalidateRange(adapter, io, offset, size), else => VkError.InvalidDeviceMemoryDrv, }, - .Invalid => VkError.InvalidDeviceMemoryDrv, + .invalid => VkError.InvalidDeviceMemoryDrv, }; } pub fn handle(self: *const Memory) VkError!u32 { return switch (self.*) { - .I915 => |*memory| memory.handle, - .Xe => VkError.FeatureNotPresent, - .Invalid => VkError.InvalidDeviceMemoryDrv, + .i915 => |*memory| memory.handle, + .xe => VkError.FeatureNotPresent, + .invalid => VkError.InvalidDeviceMemoryDrv, }; } }; diff --git a/src/intel/lib.zig b/src/intel/lib.zig index 1ed52f1..c5532d1 100644 --- a/src/intel/lib.zig +++ b/src/intel/lib.zig @@ -52,9 +52,9 @@ pub const VULKAN_VERSION = vk.makeApiVersion( pub const IMAGE_MEMORY_ALIGNMENT = std.heap.page_size_max; pub const KmdType = enum { - Invalid, - I915, - Xe, + invalid, + i915, + xe, }; pub const std_options = base.std_options; diff --git a/src/intel/pci_ids.zig b/src/intel/pci_ids.zig index 36cd3a3..7401e1a 100644 --- a/src/intel/pci_ids.zig +++ b/src/intel/pci_ids.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - const PciInfo = struct { id: u16, name: []const u8, diff --git a/src/phi/PhiBinarySemaphore.zig b/src/phi/PhiBinarySemaphore.zig index 421d048..ce29589 100644 --- a/src/phi/PhiBinarySemaphore.zig +++ b/src/phi/PhiBinarySemaphore.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.BinarySemaphore; diff --git a/src/phi/PhiBuffer.zig b/src/phi/PhiBuffer.zig index 07e1df8..12ae038 100644 --- a/src/phi/PhiBuffer.zig +++ b/src/phi/PhiBuffer.zig @@ -2,10 +2,8 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const lib = @import("lib.zig"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Buffer; diff --git a/src/phi/PhiBufferView.zig b/src/phi/PhiBufferView.zig index 046a07a..2b2b66b 100644 --- a/src/phi/PhiBufferView.zig +++ b/src/phi/PhiBufferView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.BufferView; diff --git a/src/phi/PhiCommandPool.zig b/src/phi/PhiCommandPool.zig index b70e6e3..d09f5a5 100644 --- a/src/phi/PhiCommandPool.zig +++ b/src/phi/PhiCommandPool.zig @@ -2,9 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const NonDispatchable = base.NonDispatchable; const VkError = base.VkError; -const Device = base.Device; const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); diff --git a/src/phi/PhiDescriptorPool.zig b/src/phi/PhiDescriptorPool.zig index c390577..9c2afbf 100644 --- a/src/phi/PhiDescriptorPool.zig +++ b/src/phi/PhiDescriptorPool.zig @@ -3,9 +3,7 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const VulkanAllocator = base.VulkanAllocator; -const Device = base.Device; const Self = @This(); pub const Interface = base.DescriptorPool; diff --git a/src/phi/PhiDescriptorSetLayout.zig b/src/phi/PhiDescriptorSetLayout.zig index b2d706e..079b64b 100644 --- a/src/phi/PhiDescriptorSetLayout.zig +++ b/src/phi/PhiDescriptorSetLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.DescriptorSetLayout; diff --git a/src/phi/PhiDevice.zig b/src/phi/PhiDevice.zig index 279c250..94a2b01 100644 --- a/src/phi/PhiDevice.zig +++ b/src/phi/PhiDevice.zig @@ -229,7 +229,7 @@ fn uploadAndLaunchDaemon(instance: *base.Instance, allocator: std.mem.Allocator, const local_path = std.fmt.allocPrint(allocator, "/tmp/ape_phi_device_{d}_{d}.mic", .{ std.os.linux.getpid(), mic_device_num }) catch return VkError.OutOfHostMemory; defer allocator.free(local_path); - defer std.Io.Dir.deleteFileAbsolute(io, local_path) catch {}; + defer std.Io.Dir.deleteFileAbsolute(io, local_path) catch @panic("Caught an error while handling an error"); std.Io.Dir.writeFile(.cwd(), io, .{ .sub_path = local_path, diff --git a/src/phi/PhiDeviceMemory.zig b/src/phi/PhiDeviceMemory.zig index de54f96..11aba74 100644 --- a/src/phi/PhiDeviceMemory.zig +++ b/src/phi/PhiDeviceMemory.zig @@ -46,7 +46,7 @@ pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceS .flags = 0, }; - var reply: proto.PhiAllocMemoryReply = undefined; + var reply = std.mem.zeroes(proto.PhiAllocMemoryReply); try device.transport.request(proto.PHI_PACKET_ALLOC_MEMORY, std.mem.asBytes(&alloc_request), std.mem.asBytes(&reply)); if (reply.result.status != proto.PHI_STATUS_OK) { diff --git a/src/phi/PhiEvent.zig b/src/phi/PhiEvent.zig index 68b9b0e..94858e9 100644 --- a/src/phi/PhiEvent.zig +++ b/src/phi/PhiEvent.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Event; diff --git a/src/phi/PhiImage.zig b/src/phi/PhiImage.zig index 4c65234..88e411d 100644 --- a/src/phi/PhiImage.zig +++ b/src/phi/PhiImage.zig @@ -1,7 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const lib = @import("lib.zig"); const VkError = base.VkError; diff --git a/src/phi/PhiImageView.zig b/src/phi/PhiImageView.zig index db0956b..86da242 100644 --- a/src/phi/PhiImageView.zig +++ b/src/phi/PhiImageView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.ImageView; diff --git a/src/phi/PhiInstance.zig b/src/phi/PhiInstance.zig index fbec076..637ceeb 100644 --- a/src/phi/PhiInstance.zig +++ b/src/phi/PhiInstance.zig @@ -98,7 +98,7 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _ defer device.deinit(); const physical_device = try PhiPhysicalDevice.create(allocator, interface, device, device_num); - errdefer physical_device.interface.release(allocator) catch {}; + errdefer physical_device.interface.release(allocator) catch @panic("Caught an error while handling an error"); const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface); errdefer dispatchable.destroy(allocator); diff --git a/src/phi/PhiPhysicalDevice.zig b/src/phi/PhiPhysicalDevice.zig index d0bc429..b325022 100644 --- a/src/phi/PhiPhysicalDevice.zig +++ b/src/phi/PhiPhysicalDevice.zig @@ -10,7 +10,6 @@ const pci_ids = @import("pci_ids.zig").map; const PhiDevice = @import("PhiDevice.zig"); const VkError = base.VkError; -const VulkanAllocator = base.VulkanAllocator; const SurfaceKHR = base.SurfaceKHR; const Self = @This(); @@ -87,7 +86,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device return VkError.InitializationFailed; } - interface.props.pipeline_cache_uuid = undefined; + interface.props.pipeline_cache_uuid = @splat(0); interface.props.limits = .{ .max_image_dimension_1d = 4096, .max_image_dimension_2d = 4096, @@ -872,10 +871,10 @@ fn cpuid(leaf_id: u32, subleaf_id: u32) CpuidRegs { } } - var eax: u32 = undefined; - var ebx: u32 = undefined; - var ecx: u32 = undefined; - var edx: u32 = undefined; + var eax: u32 = 0; + var ebx: u32 = 0; + var ecx: u32 = 0; + var edx: u32 = 0; asm volatile ("cpuid" : [_] "={eax}" (eax), diff --git a/src/phi/PhiPipelineLayout.zig b/src/phi/PhiPipelineLayout.zig index 3f0bfc7..f867936 100644 --- a/src/phi/PhiPipelineLayout.zig +++ b/src/phi/PhiPipelineLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.PipelineLayout; diff --git a/src/phi/PhiQueryPool.zig b/src/phi/PhiQueryPool.zig index eca39ba..4f8523d 100644 --- a/src/phi/PhiQueryPool.zig +++ b/src/phi/PhiQueryPool.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.QueryPool; diff --git a/src/phi/PhiQueue.zig b/src/phi/PhiQueue.zig index 01b504d..a1444bb 100644 --- a/src/phi/PhiQueue.zig +++ b/src/phi/PhiQueue.zig @@ -66,7 +66,7 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*bas @memcpy(payload[@sizeOf(proto.PhiWorkExecutionRequest)..], phi_command_buffer.commands.items); // Synchronous queues for now - var reply: proto.PhiWorkExecutionReply = undefined; + var reply = std.mem.zeroes(proto.PhiWorkExecutionReply); try device.transport.request(proto.PHI_PACKET_WORK_EXECUTION, payload, std.mem.asBytes(&reply)); if (reply.result.status != proto.PHI_STATUS_OK) { diff --git a/src/phi/PhiRenderPass.zig b/src/phi/PhiRenderPass.zig index cf56459..68063a9 100644 --- a/src/phi/PhiRenderPass.zig +++ b/src/phi/PhiRenderPass.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.RenderPass; diff --git a/src/phi/PhiTransport.zig b/src/phi/PhiTransport.zig index fdcdd27..7ff4a82 100644 --- a/src/phi/PhiTransport.zig +++ b/src/phi/PhiTransport.zig @@ -68,6 +68,7 @@ pub fn request(self: *Self, command: c_uint, payload: []const u8, reply_payload: try self.writeAll(std.mem.asBytes(&header)); try self.writeAll(payload); + // SAFETY: will be entirely written with the readAll var reply_header: proto.PhiMessageHeader = undefined; try self.readAll(std.mem.asBytes(&reply_header)); @@ -119,6 +120,8 @@ fn handshake(self: *Self) VkError!void { .host_protocol_version = proto.PHI_PROTOCOL_VERSION, .reserved = 0, }; + + // SAFETY: will be entirely written by the request var reply: proto.PhiHelloReply = undefined; try self.request(proto.PHI_PACKET_HELLO, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)); if (reply.result.status != proto.PHI_STATUS_OK) { diff --git a/src/phi/pci_ids.zig b/src/phi/pci_ids.zig index a40f957..36e2308 100644 --- a/src/phi/pci_ids.zig +++ b/src/phi/pci_ids.zig @@ -1,4 +1,3 @@ -const std = @import("std"); const PciInfo = struct { id: u16, diff --git a/src/phi/scif.zig b/src/phi/scif.zig index 2e249ab..b8e3c5e 100644 --- a/src/phi/scif.zig +++ b/src/phi/scif.zig @@ -13,12 +13,18 @@ pub const PortId = extern struct { pub const SEND_BLOCK = 1; pub const RECV_BLOCK = 1; +// SAFETY: load assigns every function pointer before the public wrappers can be used. var scif_open: *const fn () callconv(.c) epd_t = undefined; +// SAFETY: load assigns every function pointer before the public wrappers can be used. var scif_close: *const fn (epd: epd_t) callconv(.c) c_int = undefined; +// SAFETY: load assigns every function pointer before the public wrappers can be used. var scif_connect: *const fn (epd: epd_t, dst: *const PortId) callconv(.c) c_int = undefined; +// SAFETY: load assigns every function pointer before the public wrappers can be used. var scif_send: *const fn (epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined; +// SAFETY: load assigns every function pointer before the public wrappers can be used. var scif_recv: *const fn (epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined; +// SAFETY: load initializes the module before it can be closed or queried. var module: std.DynLib = undefined; var ref_count = std.atomic.Value(usize).init(0); var load_mutex: base.SpinMutex = .{}; diff --git a/src/software/SoftBinarySemaphore.zig b/src/software/SoftBinarySemaphore.zig index 7fe5aca..9616d5d 100644 --- a/src/software/SoftBinarySemaphore.zig +++ b/src/software/SoftBinarySemaphore.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.BinarySemaphore; diff --git a/src/software/SoftBuffer.zig b/src/software/SoftBuffer.zig index dfc8c2d..28eb2d7 100644 --- a/src/software/SoftBuffer.zig +++ b/src/software/SoftBuffer.zig @@ -5,7 +5,6 @@ const base = @import("base"); const lib = @import("lib.zig"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Buffer; diff --git a/src/software/SoftBufferView.zig b/src/software/SoftBufferView.zig index 046a07a..2b2b66b 100644 --- a/src/software/SoftBufferView.zig +++ b/src/software/SoftBufferView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.BufferView; diff --git a/src/software/SoftCommandBuffer.zig b/src/software/SoftCommandBuffer.zig index ce17372..f4153ee 100644 --- a/src/software/SoftCommandBuffer.zig +++ b/src/software/SoftCommandBuffer.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const lib = @import("lib.zig"); -const Device = base.Device; const VkError = base.VkError; const SoftBuffer = @import("SoftBuffer.zig"); @@ -129,10 +128,9 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v self.* = .{ .interface = interface, - .command_allocator = undefined, + .command_allocator = .init(interface.host_allocator.allocator()), .commands = .empty, }; - self.command_allocator = .init(self.interface.host_allocator.allocator()); return self; } @@ -144,7 +142,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn execute(self: *Self, device: *ExecutionDevice) VkError!void { try self.interface.submit(); - defer self.interface.finish() catch {}; + defer self.interface.finish() catch @panic("Caught an error while handling an error"); for (self.commands.items) |command| { command.vtable.execute(@ptrCast(command.ptr), device) catch |err| { @@ -1063,7 +1061,11 @@ pub fn endRenderPass(interface: *Interface) VkError!void { } }; - self.commands.append(allocator, .{ .ptr = undefined, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory; + self.commands.append(allocator, .{ + // SAFETY: this command's execute callback does not inspect its context pointer. + .ptr = undefined, + .vtable = &.{ .execute = CommandImpl.execute }, + }) catch return VkError.OutOfHostMemory; } pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void { diff --git a/src/software/SoftCommandPool.zig b/src/software/SoftCommandPool.zig index 15cfc81..c3c60df 100644 --- a/src/software/SoftCommandPool.zig +++ b/src/software/SoftCommandPool.zig @@ -2,9 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const NonDispatchable = base.NonDispatchable; const VkError = base.VkError; -const Device = base.Device; const SoftCommandBuffer = @import("SoftCommandBuffer.zig"); diff --git a/src/software/SoftDescriptorPool.zig b/src/software/SoftDescriptorPool.zig index 7eec0de..37698a3 100644 --- a/src/software/SoftDescriptorPool.zig +++ b/src/software/SoftDescriptorPool.zig @@ -5,7 +5,6 @@ const base = @import("base"); const VkError = base.VkError; const VulkanAllocator = base.VulkanAllocator; -const Device = base.Device; const SoftDescriptorSet = @import("SoftDescriptorSet.zig"); diff --git a/src/software/SoftDescriptorSet.zig b/src/software/SoftDescriptorSet.zig index a07b8d9..91e96f5 100644 --- a/src/software/SoftDescriptorSet.zig +++ b/src/software/SoftDescriptorSet.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Buffer = base.Buffer; const BufferView = base.BufferView; const ImageView = base.ImageView; diff --git a/src/software/SoftDescriptorSetLayout.zig b/src/software/SoftDescriptorSetLayout.zig index b2d706e..079b64b 100644 --- a/src/software/SoftDescriptorSetLayout.zig +++ b/src/software/SoftDescriptorSetLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.DescriptorSetLayout; diff --git a/src/software/SoftDevice.zig b/src/software/SoftDevice.zig index a8599dc..b6d4d03 100644 --- a/src/software/SoftDevice.zig +++ b/src/software/SoftDevice.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const builtin = @import("builtin"); -const config = base.config; const SoftQueue = @import("SoftQueue.zig"); @@ -33,8 +31,6 @@ const VkError = base.VkError; const Self = @This(); pub const Interface = base.Device; -const SpawnError = std.Thread.SpawnError; - interface: Interface, pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { @@ -42,7 +38,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a var initialized = false; errdefer { if (initialized) { - self.interface.destroy(allocator) catch {}; + self.interface.destroy(allocator) catch @panic("Caught an error while handling an error"); } else { allocator.destroy(self); } diff --git a/src/software/SoftDeviceMemory.zig b/src/software/SoftDeviceMemory.zig index 9d15268..db000ce 100644 --- a/src/software/SoftDeviceMemory.zig +++ b/src/software/SoftDeviceMemory.zig @@ -2,7 +2,6 @@ const std = @import("std"); const vk = @import("vulkan"); const SoftDevice = @import("SoftDevice.zig"); const base = @import("base"); -const lib = @import("lib.zig"); const VkError = base.VkError; diff --git a/src/software/SoftEvent.zig b/src/software/SoftEvent.zig index ced8ed4..fff63a6 100644 --- a/src/software/SoftEvent.zig +++ b/src/software/SoftEvent.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.Event; diff --git a/src/software/SoftFramebuffer.zig b/src/software/SoftFramebuffer.zig index a28d9a9..d28d584 100644 --- a/src/software/SoftFramebuffer.zig +++ b/src/software/SoftFramebuffer.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const blitter = @import("device/blitter.zig"); diff --git a/src/software/SoftImage.zig b/src/software/SoftImage.zig index 63bf4e5..4aa47a5 100644 --- a/src/software/SoftImage.zig +++ b/src/software/SoftImage.zig @@ -61,10 +61,8 @@ const F32x4 = blitter.F32x4; const U32x4 = blitter.U32x4; const VkError = base.VkError; -const Device = base.Device; const SoftBuffer = @import("SoftBuffer.zig"); -const SoftDevice = @import("SoftDevice.zig"); const Self = @This(); pub const Interface = base.Image; diff --git a/src/software/SoftImageView.zig b/src/software/SoftImageView.zig index db0956b..86da242 100644 --- a/src/software/SoftImageView.zig +++ b/src/software/SoftImageView.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.ImageView; diff --git a/src/software/SoftInstance.zig b/src/software/SoftInstance.zig index fc6de28..6a20c7f 100644 --- a/src/software/SoftInstance.zig +++ b/src/software/SoftInstance.zig @@ -1,7 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const lib = @import("lib.zig"); const SoftPhysicalDevice = @import("SoftPhysicalDevice.zig"); const Dispatchable = base.Dispatchable; @@ -63,7 +62,7 @@ fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _: []base.drm.Card) VkError!void { // Software driver has only one physical device (the CPU) const physical_device = try SoftPhysicalDevice.create(allocator, interface); - errdefer physical_device.interface.release(allocator) catch {}; + errdefer physical_device.interface.release(allocator) catch @panic("Caught an error while handling an error"); const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface); errdefer dispatchable.destroy(allocator); interface.physical_devices.append(allocator, dispatchable) catch return VkError.OutOfHostMemory; diff --git a/src/software/SoftPhysicalDevice.zig b/src/software/SoftPhysicalDevice.zig index 1dc6a16..0eb9e33 100644 --- a/src/software/SoftPhysicalDevice.zig +++ b/src/software/SoftPhysicalDevice.zig @@ -925,10 +925,10 @@ fn cpuid(leaf_id: u32, subleaf_id: u32) CpuidRegs { } } - var eax: u32 = undefined; - var ebx: u32 = undefined; - var ecx: u32 = undefined; - var edx: u32 = undefined; + var eax: u32 = 0; + var ebx: u32 = 0; + var ecx: u32 = 0; + var edx: u32 = 0; asm volatile ("cpuid" : [_] "={eax}" (eax), diff --git a/src/software/SoftPipeline.zig b/src/software/SoftPipeline.zig index 30d2394..c1d8d84 100644 --- a/src/software/SoftPipeline.zig +++ b/src/software/SoftPipeline.zig @@ -7,7 +7,6 @@ const zm = base.zm; const blitter = @import("device/blitter.zig"); -const Device = base.Device; const VkError = base.VkError; const SpvRuntimeError = spv.Runtime.RuntimeError; @@ -31,7 +30,6 @@ pub threadlocal var current_framebuffer_attachment_count: usize = 0; const NonDispatchable = base.NonDispatchable; const ShaderModule = base.ShaderModule; -const SoftDevice = @import("SoftDevice.zig"); const SoftBuffer = @import("SoftBuffer.zig"); const SoftBufferView = @import("SoftBufferView.zig"); const SoftImage = @import("SoftImage.zig"); diff --git a/src/software/SoftPipelineCache.zig b/src/software/SoftPipelineCache.zig index bab0295..cae117d 100644 --- a/src/software/SoftPipelineCache.zig +++ b/src/software/SoftPipelineCache.zig @@ -4,7 +4,6 @@ const base = @import("base"); const spv = @import("spv"); const VkError = base.VkError; -const SoftDevice = @import("SoftDevice.zig"); const SoftShaderModule = @import("SoftShaderModule.zig"); const Self = @This(); diff --git a/src/software/SoftPipelineLayout.zig b/src/software/SoftPipelineLayout.zig index 3f0bfc7..f867936 100644 --- a/src/software/SoftPipelineLayout.zig +++ b/src/software/SoftPipelineLayout.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.PipelineLayout; diff --git a/src/software/SoftQueryPool.zig b/src/software/SoftQueryPool.zig index eca39ba..4f8523d 100644 --- a/src/software/SoftQueryPool.zig +++ b/src/software/SoftQueryPool.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.QueryPool; diff --git a/src/software/SoftQueue.zig b/src/software/SoftQueue.zig index d112a80..d21a973 100644 --- a/src/software/SoftQueue.zig +++ b/src/software/SoftQueue.zig @@ -3,9 +3,7 @@ const vk = @import("vulkan"); const base = @import("base"); const ExecutionDevice = @import("device/Device.zig"); -const Dispatchable = base.Dispatchable; -const CommandBuffer = base.CommandBuffer; const SoftDevice = @import("SoftDevice.zig"); const SoftCommandBuffer = @import("SoftCommandBuffer.zig"); @@ -109,6 +107,7 @@ fn executeSubmitInfo(soft_device: *SoftDevice, info: Interface.SubmitInfo) VkErr try semaphore.wait(); } + // SAFETY: setup initializes every field before execution_device is read. var execution_device: ExecutionDevice = undefined; execution_device.setup(soft_device); defer execution_device.deinit(soft_device.interface.device_allocator.allocator()); diff --git a/src/software/SoftRenderPass.zig b/src/software/SoftRenderPass.zig index cf56459..68063a9 100644 --- a/src/software/SoftRenderPass.zig +++ b/src/software/SoftRenderPass.zig @@ -3,7 +3,6 @@ const vk = @import("vulkan"); const base = @import("base"); const VkError = base.VkError; -const Device = base.Device; const Self = @This(); pub const Interface = base.RenderPass; diff --git a/src/software/SoftSampler.zig b/src/software/SoftSampler.zig index c694000..6b1f23e 100644 --- a/src/software/SoftSampler.zig +++ b/src/software/SoftSampler.zig @@ -6,7 +6,6 @@ const zm = base.zm; const blitter = @import("device/blitter.zig"); const VkError = base.VkError; -const Device = base.Device; const F32x4 = zm.F32x4; const U32x4 = blitter.U32x4; diff --git a/src/software/SoftShaderModule.zig b/src/software/SoftShaderModule.zig index 3df942d..bb17187 100644 --- a/src/software/SoftShaderModule.zig +++ b/src/software/SoftShaderModule.zig @@ -2,12 +2,9 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); const spv = @import("spv"); -const lib = @import("lib.zig"); const VkError = base.VkError; -const Device = base.Device; -const SoftDevice = @import("SoftDevice.zig"); const Self = @This(); pub const Interface = base.ShaderModule; diff --git a/src/software/device/BoundedAllocator.zig b/src/software/device/BoundedAllocator.zig index 09fdac6..8c0b71b 100644 --- a/src/software/device/BoundedAllocator.zig +++ b/src/software/device/BoundedAllocator.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const base = @import("base"); const Self = @This(); diff --git a/src/software/device/ComputeDispatcher.zig b/src/software/device/ComputeDispatcher.zig index dd4139d..8acdad6 100644 --- a/src/software/device/ComputeDispatcher.zig +++ b/src/software/device/ComputeDispatcher.zig @@ -1,8 +1,6 @@ const std = @import("std"); -const vk = @import("vulkan"); const base = @import("base"); const spv = @import("spv"); -const lib = @import("../lib.zig"); const ExecutionDevice = @import("Device.zig"); const PipelineState = ExecutionDevice.PipelineState; diff --git a/src/software/device/Device.zig b/src/software/device/Device.zig index cb9a3f5..c807ad2 100644 --- a/src/software/device/Device.zig +++ b/src/software/device/Device.zig @@ -6,15 +6,11 @@ const spv = @import("spv"); const SoftDescriptorSet = @import("../SoftDescriptorSet.zig"); const SoftDevice = @import("../SoftDevice.zig"); -const SoftFramebuffer = @import("../SoftFramebuffer.zig"); const SoftPipeline = @import("../SoftPipeline.zig"); -const SoftRenderPass = @import("../SoftRenderPass.zig"); const ComputeDispatcher = @import("ComputeDispatcher.zig"); const Renderer = @import("Renderer.zig"); -const VkError = base.VkError; - const Self = @This(); pub const GRAPHICS_PIPELINE_STATE = 0; @@ -58,7 +54,9 @@ pub fn setup(self: *Self, device: *SoftDevice) void { .data = switch (i) { GRAPHICS_PIPELINE_STATE => .{ .graphics = .{ + // SAFETY: indexed draws bind the index buffer before the renderer reads it. .index_buffer = undefined, + // SAFETY: each vertex binding is populated before an attribute reads it. .vertex_buffers = undefined, }, }, diff --git a/src/software/device/Renderer.zig b/src/software/device/Renderer.zig index 953f838..e2ecd5f 100644 --- a/src/software/device/Renderer.zig +++ b/src/software/device/Renderer.zig @@ -9,16 +9,13 @@ const PipelineState = ExecutionDevice.PipelineState; const BoundedAllocator = @import("BoundedAllocator.zig"); const SoftBuffer = @import("../SoftBuffer.zig"); -const SoftDescriptorSet = @import("../SoftDescriptorSet.zig"); const SoftDevice = @import("../SoftDevice.zig"); const SoftFramebuffer = @import("../SoftFramebuffer.zig"); const SoftPipeline = @import("../SoftPipeline.zig"); const SoftRenderPass = @import("../SoftRenderPass.zig"); -const blitter = @import("blitter.zig"); const rasterizer = @import("rasterizer.zig"); const vertex_dispatcher = @import("vertex_dispatcher.zig"); -const clip = @import("clip.zig"); const VkError = base.VkError; const F32x4 = zm.F32x4; @@ -110,7 +107,9 @@ pub const DrawCall = struct { .vertex_count = vertex_count, .instance_count = instance_count, .renderer = renderer, + // SAFETY: draw assigns the viewport before the rasterizer receives this value. .viewport = undefined, + // SAFETY: draw assigns the scissor before the rasterizer receives this value. .scissor = undefined, .color_attachments = framebuffer.interface.attachments[0..], .depth_attachment = if (render_pass.interface.subpasses[renderer.subpass_index].depth_stencil_attachments) |desc| framebuffer.interface.attachments[desc.attachment] else null, diff --git a/src/software/device/blitter.zig b/src/software/device/blitter.zig index 1523e6a..33b6362 100644 --- a/src/software/device/blitter.zig +++ b/src/software/device/blitter.zig @@ -1640,7 +1640,7 @@ fn encodeUFloat(value: f32, mantissa_bits: comptime_int) u32 { return max_exponent << mantissa_bits; if (adjusted_exponent <= 0) { - const mantissa = @as(u32, @intFromFloat(@round(value * @as(f32, @floatFromInt(1 << (mantissa_bits + exponent_bias - 1)))))); + const mantissa: u32 = @intFromFloat(@round(value * @as(f32, @floatFromInt(1 << (mantissa_bits + exponent_bias - 1))))); return mantissa; } diff --git a/src/software/device/clip.zig b/src/software/device/clip.zig index a55312c..c3341ac 100644 --- a/src/software/device/clip.zig +++ b/src/software/device/clip.zig @@ -13,12 +13,12 @@ const VkError = base.VkError; const INTERFACE_BLOB_PADDING = @sizeOf(F32x4); const ClipPlane = enum { - Left, - Right, - Bottom, - Top, - Near, - Far, + left, + right, + bottom, + top, + near, + far, }; const MAX_CLIPPED_POLYGON_VERTICES = 16; @@ -29,7 +29,7 @@ pub const ClippedLine = struct { }; const ClippedPolygon = struct { - vertices: [MAX_CLIPPED_POLYGON_VERTICES]Vertex = undefined, + vertices: [MAX_CLIPPED_POLYGON_VERTICES]Vertex = std.mem.zeroes([MAX_CLIPPED_POLYGON_VERTICES]Vertex), len: usize = 0, fn append(self: *@This(), vertex: Vertex) VkError!void { @@ -48,12 +48,12 @@ pub fn clipTriangle(allocator: std.mem.Allocator, v0: *const Vertex, v1: *const try polygon.append(v2.*); const planes = [_]ClipPlane{ - .Left, - .Right, - .Bottom, - .Top, - .Near, - .Far, + .left, + .right, + .bottom, + .top, + .near, + .far, }; for (planes) |plane| { @@ -72,12 +72,12 @@ pub fn clipLine(allocator: std.mem.Allocator, v0: *const Vertex, v1: *const Vert }; const planes = [_]ClipPlane{ - .Left, - .Right, - .Bottom, - .Top, - .Near, - .Far, + .left, + .right, + .bottom, + .top, + .near, + .far, }; for (planes) |plane| { @@ -131,12 +131,12 @@ pub fn viewportTransformVertex(viewport: vk.Viewport, vertex: *Vertex) void { fn clipDistance(position: F32x4, plane: ClipPlane) f32 { const x, const y, const z, const w = position; return switch (plane) { - .Left => x + w, - .Right => w - x, - .Bottom => y + w, - .Top => w - y, - .Near => z, - .Far => w - z, + .left => x + w, + .right => w - x, + .bottom => y + w, + .top => w - y, + .near => z, + .far => w - z, }; } @@ -173,7 +173,7 @@ fn interpolateVertexForClipping(allocator: std.mem.Allocator, a: *const Vertex, .primitive_restart = false, .position = a.position + ((b.position - a.position) * zm.f32x4s(t)), .point_size = a.point_size + ((b.point_size - a.point_size) * t), - .outputs = undefined, + .outputs = @splat(@splat(null)), }; for (&result.outputs) |*location| { diff --git a/src/software/device/fragment.zig b/src/software/device/fragment.zig index a02a3a3..ab77904 100644 --- a/src/software/device/fragment.zig +++ b/src/software/device/fragment.zig @@ -8,10 +8,8 @@ const VertexInterpolationLocation = @import("rasterizer/common.zig").VertexInter const ExecutionDevice = @import("Device.zig"); const Renderer = @import("Renderer.zig"); -const SoftImage = @import("../SoftImage.zig"); const SoftPipeline = @import("../SoftPipeline.zig"); -const VkError = base.VkError; const SpvRuntimeError = spv.Runtime.RuntimeError; const INTERFACE_BLOB_PADDING = @sizeOf(zm.F32x4); const PROCESSED_INPUTS_STACK_CAPACITY = 4096; @@ -49,8 +47,10 @@ pub fn shaderInvocation( const io = draw_call.renderer.device.interface.io(); + // SAFETY: fragment dispatch only occurs after a graphics pipeline has been bound. const pipeline = draw_call.renderer.state.pipeline orelse return undefined; + // SAFETY: fragment dispatch only occurs when the bound pipeline has a fragment stage. const shader = pipeline.stages.getPtr(.fragment) orelse return undefined; const runtime = &shader.runtimes[batch_id]; const mutex = &runtime.mutex; @@ -245,7 +245,7 @@ pub fn shaderInvocation( } var depth: ?f32 = null; - var frag_depth: f32 = undefined; + var frag_depth: f32 = 0; if (rt.readBuiltIn(std.mem.asBytes(&frag_depth), .FragDepth)) { depth = frag_depth; } else |err| switch (err) { @@ -254,7 +254,7 @@ pub fn shaderInvocation( } var sample_mask: ?vk.SampleMask = null; - var frag_sample_mask: [1]vk.SampleMask = undefined; + var frag_sample_mask: [1]vk.SampleMask = .{0}; if (rt.readBuiltIn(std.mem.asBytes(&frag_sample_mask), .SampleMask)) { sample_mask = frag_sample_mask[0]; } else |err| switch (err) { diff --git a/src/software/device/rasterizer.zig b/src/software/device/rasterizer.zig index 03da27e..4509812 100644 --- a/src/software/device/rasterizer.zig +++ b/src/software/device/rasterizer.zig @@ -133,7 +133,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato ); const color_attachment_subresource_size = renderTargetSubresourceSize(render_target, render_target_view, color_range.aspect_mask, color_range.base_mip_level); access.* = .{ - .mutex = undefined, + .mutex = .init, .base = try render_target.mapAsSliceWithAddedOffset(u8, color_attachment_subresource_offset, color_attachment_subresource_size), .row_pitch = render_target.getRowPitchMemSizeForMipLevelWithFormat(color_range.aspect_mask, color_range.base_mip_level, color_format), .texel_size = base.format.texelSize(color_format), diff --git a/src/software/device/rasterizer/bresenham.zig b/src/software/device/rasterizer/bresenham.zig index 2f2d207..939f68d 100644 --- a/src/software/device/rasterizer/bresenham.zig +++ b/src/software/device/rasterizer/bresenham.zig @@ -8,7 +8,6 @@ const common = @import("common.zig"); const fragment = @import("../fragment.zig"); const Renderer = @import("../Renderer.zig"); -const SoftImage = @import("../../SoftImage.zig"); const VkError = base.VkError; const SpvRuntimeError = spv.Runtime.RuntimeError; diff --git a/src/software/device/rasterizer/common.zig b/src/software/device/rasterizer/common.zig index 505c120..fdaaae6 100644 --- a/src/software/device/rasterizer/common.zig +++ b/src/software/device/rasterizer/common.zig @@ -53,14 +53,14 @@ pub fn clampDepthBias(bias: f32, clamp: f32) f32 { } pub fn scissorContainsPixel(scissor: vk.Rect2D, x: i32, y: i32) bool { - const min_x: i64 = @as(i64, scissor.offset.x); - const min_y: i64 = @as(i64, scissor.offset.y); + const min_x: i64 = scissor.offset.x; + const min_y: i64 = scissor.offset.y; const max_x: i64 = min_x + @as(i64, @intCast(scissor.extent.width)); const max_y: i64 = min_y + @as(i64, @intCast(scissor.extent.height)); - const pixel_x: i64 = @as(i64, x); - const pixel_y: i64 = @as(i64, y); + const pixel_x: i64 = x; + const pixel_y: i64 = y; return pixel_x >= min_x and pixel_x < max_x and @@ -69,8 +69,8 @@ pub fn scissorContainsPixel(scissor: vk.Rect2D, x: i32, y: i32) bool { } pub fn rectContainsPixel(rect: vk.Rect2D, x: usize, y: usize) bool { - const min_x: i64 = @as(i64, rect.offset.x); - const min_y: i64 = @as(i64, rect.offset.y); + const min_x: i64 = rect.offset.x; + const min_y: i64 = rect.offset.y; const max_x: i64 = min_x + @as(i64, @intCast(rect.extent.width)); const max_y: i64 = min_y + @as(i64, @intCast(rect.extent.height)); diff --git a/src/software/device/rasterizer/edge_function.zig b/src/software/device/rasterizer/edge_function.zig index e2ddb46..c8c8f46 100644 --- a/src/software/device/rasterizer/edge_function.zig +++ b/src/software/device/rasterizer/edge_function.zig @@ -485,6 +485,7 @@ inline fn run(data: RunData) !void { centroid_b2, ); const derivative_inputs: ?fragment.DerivativeInputs = if (data.fragment_uses_derivatives) blk: { + // SAFETY: both dx and dy are assigned below before derivatives is returned. var derivatives: fragment.DerivativeInputs = undefined; const p_dx = zm.f32x4(@as(f32, @floatFromInt(x)) + 1.5, @as(f32, @floatFromInt(y)) + 0.5, 0.0, 1.0); diff --git a/src/software/device/vertex_dispatcher.zig b/src/software/device/vertex_dispatcher.zig index ec63c47..3957f8b 100644 --- a/src/software/device/vertex_dispatcher.zig +++ b/src/software/device/vertex_dispatcher.zig @@ -526,7 +526,7 @@ fn isConstantZero(rt: *spv.Runtime, result_word: spv.SpvWord) bool { const variant = rt.results[result_word].variant orelse return false; switch (variant) { .Constant => |constant| { - var value: u32 = undefined; + var value: u32 = 0; _ = constant.value.read(std.mem.asBytes(&value)) catch return false; return value == 0; }, diff --git a/src/vulkan/BinarySemaphore.zig b/src/vulkan/BinarySemaphore.zig index 173f813..8686622 100644 --- a/src/vulkan/BinarySemaphore.zig +++ b/src/vulkan/BinarySemaphore.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); @@ -25,6 +23,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Semap _ = info; return .{ .owner = device, + // SAFETY: the backend assigns the vtable before returning the semaphore. .vtable = undefined, }; } diff --git a/src/vulkan/Buffer.zig b/src/vulkan/Buffer.zig index 70acd4a..5d76d01 100644 --- a/src/vulkan/Buffer.zig +++ b/src/vulkan/Buffer.zig @@ -31,6 +31,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Buffe .usage = info.usage, .memory = null, .allowed_memory_types = std.bit_set.IntegerBitSet(32).initFull(), + // SAFETY: the backend assigns the vtable before returning the buffer. .vtable = undefined, }; } diff --git a/src/vulkan/BufferView.zig b/src/vulkan/BufferView.zig index fd8b0d6..e1836ed 100644 --- a/src/vulkan/BufferView.zig +++ b/src/vulkan/BufferView.zig @@ -27,6 +27,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Buffe return .{ .owner = device, .buffer = try NonDispatchable(Buffer).fromHandleObject(info.buffer), + // SAFETY: the backend assigns the vtable before returning the buffer view. .vtable = undefined, .format = info.format, .offset = info.offset, diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 29aab4c..3e4800a 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -18,11 +18,11 @@ const QueryPool = @import("QueryPool.zig"); const RenderPass = @import("RenderPass.zig"); const State = enum { - Initial, - Recording, - Executable, - Pending, - Invalid, + initial, + recording, + executable, + pending, + invalid, }; const Self = @This(); @@ -100,13 +100,15 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma return .{ .owner = device, .pool = try NonDispatchable(CommandPool).fromHandleObject(info.command_pool), - .state = .Initial, + .state = .initial, .begin_info = null, .usage_flags = .{}, .device_mask = 1, .host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object), .state_mutex = .init, + // SAFETY: the backend assigns both tables before returning the command buffer. .vtable = undefined, + // SAFETY: the backend assigns both tables before returning the command buffer. .dispatch_table = undefined, }; } @@ -128,9 +130,9 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { } pub fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError!void { - const implicitly_reset = self.state == .Executable or self.state == .Invalid; + const implicitly_reset = self.state == .executable or self.state == .invalid; - self.transitionState(.Recording, &.{ .Initial, .Executable, .Invalid }) catch return VkError.ValidationFailed; + self.transitionState(.recording, &.{ .initial, .executable, .invalid }) catch return VkError.ValidationFailed; if (implicitly_reset) { try self.dispatch_table.reset(self, .{}); self.begin_info = null; @@ -143,7 +145,7 @@ pub fn begin(self: *Self, info: *const vk.CommandBufferBeginInfo) VkError!void { } pub fn end(self: *Self) VkError!void { - self.transitionState(.Executable, &.{.Recording}) catch return VkError.ValidationFailed; + self.transitionState(.executable, &.{.recording}) catch return VkError.ValidationFailed; try self.dispatch_table.end(self); } @@ -156,7 +158,7 @@ pub fn reset(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void { } pub fn resetFromPool(self: *Self, flags: vk.CommandBufferResetFlags) VkError!void { - self.transitionState(.Initial, &.{ .Initial, .Recording, .Executable, .Invalid }) catch return VkError.ValidationFailed; + self.transitionState(.initial, &.{ .initial, .recording, .executable, .invalid }) catch return VkError.ValidationFailed; try self.dispatch_table.reset(self, flags); self.begin_info = null; self.usage_flags = .{}; @@ -165,18 +167,18 @@ pub fn resetFromPool(self: *Self, flags: vk.CommandBufferResetFlags) VkError!voi pub fn submit(self: *Self) VkError!void { if (!self.usage_flags.simultaneous_use_bit) { - self.transitionState(.Pending, &.{.Executable}) catch return VkError.ValidationFailed; + self.transitionState(.pending, &.{.executable}) catch return VkError.ValidationFailed; return; } - self.transitionState(.Pending, &.{ .Pending, .Executable }) catch return VkError.ValidationFailed; + self.transitionState(.pending, &.{ .pending, .executable }) catch return VkError.ValidationFailed; } pub fn finish(self: *Self) VkError!void { if (self.usage_flags.one_time_submit_bit) { - self.transitionState(.Invalid, &.{.Pending}) catch return VkError.ValidationFailed; + self.transitionState(.invalid, &.{.pending}) catch return VkError.ValidationFailed; return; } - self.transitionState(.Executable, &.{.Pending}) catch return VkError.ValidationFailed; + self.transitionState(.executable, &.{.pending}) catch return VkError.ValidationFailed; } // Commands ==================================================================================================== diff --git a/src/vulkan/CommandPool.zig b/src/vulkan/CommandPool.zig index 240e274..7720f7d 100644 --- a/src/vulkan/CommandPool.zig +++ b/src/vulkan/CommandPool.zig @@ -44,6 +44,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma .host_allocator = VulkanAllocator.from(allocator).clone(), .buffers = std.ArrayList(*Dispatchable(CommandBuffer)).initCapacity(allocator, BUFFER_POOL_BASE_CAPACITY) catch return VkError.OutOfHostMemory, .first_free_buffer_index = 0, + // SAFETY: the backend assigns the vtable before returning the command pool. .vtable = undefined, }; } @@ -112,6 +113,6 @@ pub fn reset(self: *Self, flags: vk.CommandPoolResetFlags) VkError!void { self.first_free_buffer_index = 0; for (self.buffers.items) |dis_cmd| { - _ = dis_cmd.object.resetFromPool(.{ .release_resources_bit = flags.release_resources_bit }) catch {}; + _ = dis_cmd.object.resetFromPool(.{ .release_resources_bit = flags.release_resources_bit }) catch @panic("Caught an error while handling an error"); } } diff --git a/src/vulkan/DescriptorPool.zig b/src/vulkan/DescriptorPool.zig index 423534f..6efbd4b 100644 --- a/src/vulkan/DescriptorPool.zig +++ b/src/vulkan/DescriptorPool.zig @@ -2,7 +2,6 @@ const std = @import("std"); const vk = @import("vulkan"); const VkError = @import("error_set.zig").VkError; -const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const Device = @import("Device.zig"); @@ -29,6 +28,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Descr return .{ .owner = device, .flags = info.flags, + // SAFETY: the backend assigns the vtable before returning the descriptor pool. .vtable = undefined, }; } diff --git a/src/vulkan/DescriptorSet.zig b/src/vulkan/DescriptorSet.zig index 1728c51..cbf4708 100644 --- a/src/vulkan/DescriptorSet.zig +++ b/src/vulkan/DescriptorSet.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); @@ -29,6 +27,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, layout: *DescriptorSe return .{ .owner = device, .layout = layout, + // SAFETY: the backend assigns the vtable before returning the descriptor set. .vtable = undefined, }; } diff --git a/src/vulkan/DescriptorSetLayout.zig b/src/vulkan/DescriptorSetLayout.zig index a70ecbd..ce16355 100644 --- a/src/vulkan/DescriptorSetLayout.zig +++ b/src/vulkan/DescriptorSetLayout.zig @@ -19,7 +19,7 @@ const BindingLayout = struct { /// This slice points to an array located after the binding layouts array immutable_samplers: []const *const Sampler, - driver_data: *anyopaque, + driver_data: ?*anyopaque, }; owner: *Device, @@ -77,7 +77,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Descr .array_size = 0, .dynamic_index = 0, .immutable_samplers = &.{}, - .driver_data = undefined, + .driver_data = null, }; } @@ -119,7 +119,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Descr .array_size = descriptor_count, .dynamic_index = dynamic_index, .immutable_samplers = binding_immutable_samplers, - .driver_data = undefined, + .driver_data = null, }; stages = stages.merge(binding_info.stage_flags); @@ -134,6 +134,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Descr .dynamic_descriptor_count = dynamic_descriptor_count, .stages = stages, .ref_count = std.atomic.Value(usize).init(1), + // SAFETY: the backend assigns the vtable before returning the descriptor set layout. .vtable = undefined, }; } diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index 288a312..1852c3d 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -4,7 +4,6 @@ const lib = @import("lib.zig"); const config = lib.config; const Dispatchable = @import("Dispatchable.zig").Dispatchable; -const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; @@ -16,7 +15,6 @@ const Buffer = @import("Buffer.zig"); const BufferView = @import("BufferView.zig"); const CommandPool = @import("CommandPool.zig"); const DescriptorPool = @import("DescriptorPool.zig"); -const DescriptorSet = @import("DescriptorSet.zig"); const DescriptorSetLayout = @import("DescriptorSetLayout.zig"); const DeviceMemory = @import("DeviceMemory.zig"); const Event = @import("Event.zig"); @@ -34,7 +32,6 @@ const Sampler = @import("Sampler.zig"); const ShaderModule = @import("ShaderModule.zig"); const SurfaceKHR = @import("wsi/SurfaceKHR.zig"); -const SwapchainKHR = @import("wsi/SwapchainKHR.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .device; @@ -120,7 +117,9 @@ pub fn init(allocator: std.mem.Allocator, instance: *Instance, physical_device: .enabled_khr_swapchain = enabled_khr_swapchain, .enabled_khr_device_group = enabled_khr_device_group, .device_allocator = if (config.device_debug_allocator) .init else .{}, + // SAFETY: the backend assigns both tables before returning the device. .dispatch_table = undefined, + // SAFETY: the backend assigns both tables before returning the device. .vtable = undefined, }; } @@ -141,7 +140,7 @@ pub fn createQueues(self: *Self, allocator: std.mem.Allocator, info: *const vk.D } const queue = try self.vtable.createQueue(allocator, self, queue_info.queue_family_index, @intCast(family_ptr.items.len), queue_info.flags); - errdefer self.vtable.destroyQueue(queue, allocator) catch {}; + errdefer self.vtable.destroyQueue(queue, allocator) catch @panic("Caught an error while handling an error"); const dispatchable_queue = try Dispatchable(Queue).wrap(allocator, queue); errdefer dispatchable_queue.destroy(allocator); diff --git a/src/vulkan/DeviceMemory.zig b/src/vulkan/DeviceMemory.zig index 2a7d359..aa27408 100644 --- a/src/vulkan/DeviceMemory.zig +++ b/src/vulkan/DeviceMemory.zig @@ -28,6 +28,7 @@ pub fn init(device: *Device, size: vk.DeviceSize, memory_type_index: u32) VkErro .size = size, .memory_type_index = memory_type_index, .is_mapped = false, + // SAFETY: the backend assigns the vtable before returning device memory. .vtable = undefined, }; } diff --git a/src/vulkan/Event.zig b/src/vulkan/Event.zig index 8c2006b..1e8f7c7 100644 --- a/src/vulkan/Event.zig +++ b/src/vulkan/Event.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); @@ -27,6 +25,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Event _ = info; return .{ .owner = device, + // SAFETY: the backend assigns the vtable before returning the event. .vtable = undefined, }; } diff --git a/src/vulkan/Fence.zig b/src/vulkan/Fence.zig index 55c5f58..b957de9 100644 --- a/src/vulkan/Fence.zig +++ b/src/vulkan/Fence.zig @@ -25,6 +25,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Fence return .{ .owner = device, .flags = info.flags, + // SAFETY: the backend assigns the vtable before returning the fence. .vtable = undefined, }; } diff --git a/src/vulkan/Framebuffer.zig b/src/vulkan/Framebuffer.zig index 005b3e0..4960063 100644 --- a/src/vulkan/Framebuffer.zig +++ b/src/vulkan/Framebuffer.zig @@ -44,6 +44,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Frame .height = @intCast(info.height), .layers = @intCast(info.layers), .attachments = attachments, + // SAFETY: the backend assigns the vtable before returning the framebuffer. .vtable = undefined, }; } diff --git a/src/vulkan/Image.zig b/src/vulkan/Image.zig index 7ee68fb..77b85d8 100644 --- a/src/vulkan/Image.zig +++ b/src/vulkan/Image.zig @@ -53,6 +53,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image .memory = null, .memory_offset = 0, .allowed_memory_types = std.bit_set.IntegerBitSet(32).initFull(), + // SAFETY: the backend assigns the vtable before returning the image. .vtable = undefined, }; } diff --git a/src/vulkan/ImageView.zig b/src/vulkan/ImageView.zig index 7fb28aa..c58f548 100644 --- a/src/vulkan/ImageView.zig +++ b/src/vulkan/ImageView.zig @@ -1,6 +1,5 @@ const std = @import("std"); const vk = @import("vulkan"); -const lib = @import("lib.zig"); const VkError = @import("error_set.zig").VkError; const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; @@ -33,6 +32,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image .format = info.format, .components = info.components, .subresource_range = info.subresource_range, + // SAFETY: the backend assigns the vtable before returning the image view. .vtable = undefined, }; } diff --git a/src/vulkan/Instance.zig b/src/vulkan/Instance.zig index fa5d083..b18e68d 100644 --- a/src/vulkan/Instance.zig +++ b/src/vulkan/Instance.zig @@ -1,7 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); const vk = @import("vulkan"); -const config = @import("lib.zig").config; const utils = @import("utils.zig"); const drm = @import("drm.zig"); const lib = @import("lib.zig"); @@ -23,12 +22,6 @@ comptime { const Self = @This(); pub const ObjectType: vk.ObjectType = .instance; -const DeviceAllocator = struct { - pub inline fn allocator(_: @This()) std.mem.Allocator { - return std.heap.smp_allocator; - } -}; - /// Dummy pub const EXTENSIONS = [_]vk.ExtensionProperties{}; @@ -52,7 +45,9 @@ pub fn init(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) V _ = infos; return .{ .physical_devices = .empty, + // SAFETY: the backend assigns both tables before returning the instance. .dispatch_table = undefined, + // SAFETY: the backend assigns both tables before returning the instance. .vtable = undefined, }; } diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index 0700974..ac8446b 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -38,25 +38,26 @@ pub fn init(allocator: std.mem.Allocator, instance: *Instance) VkError!Self { _ = allocator; return .{ .props = .{ - .api_version = undefined, - .driver_version = undefined, + .api_version = 0, + .driver_version = 0, .vendor_id = root.VULKAN_VENDOR_ID, - .device_id = undefined, - .device_type = undefined, + .device_id = 0, + .device_type = .other, .device_name = @as([vk.MAX_PHYSICAL_DEVICE_NAME_SIZE]u8, @splat(0)), - .pipeline_cache_uuid = undefined, + .pipeline_cache_uuid = @splat(0), .limits = std.mem.zeroInit(vk.PhysicalDeviceLimits, .{}), - .sparse_properties = undefined, + .sparse_properties = std.mem.zeroes(vk.PhysicalDeviceSparseProperties), }, .mem_props = .{ .memory_type_count = 0, - .memory_types = undefined, + .memory_types = @splat(.{ .heap_index = 0 }), .memory_heap_count = 0, - .memory_heaps = undefined, + .memory_heaps = @splat(.{ .size = 0 }), }, .queue_family_props = .empty, .features = .{}, .instance = instance, + // SAFETY: the backend assigns the dispatch table before returning the physical device. .dispatch_table = undefined, }; } diff --git a/src/vulkan/Pipeline.zig b/src/vulkan/Pipeline.zig index d8c84cb..54b8000 100644 --- a/src/vulkan/Pipeline.zig +++ b/src/vulkan/Pipeline.zig @@ -83,6 +83,7 @@ pub fn initCompute(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipel return .{ .owner = device, + // SAFETY: the backend assigns the vtable before returning the compute pipeline. .vtable = undefined, .bind_point = .compute, .stages = info.stage.stage, @@ -132,6 +133,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe return .{ .owner = device, + // SAFETY: the backend assigns the vtable before returning the graphics pipeline. .vtable = undefined, .bind_point = .graphics, .stages = stages, diff --git a/src/vulkan/PipelineCache.zig b/src/vulkan/PipelineCache.zig index ba1911f..366c76a 100644 --- a/src/vulkan/PipelineCache.zig +++ b/src/vulkan/PipelineCache.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const root = @import("lib.zig"); @@ -42,6 +40,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Pipel return .{ .owner = device, .data = data, + // SAFETY: the backend assigns the vtable before returning the pipeline cache. .vtable = undefined, }; } diff --git a/src/vulkan/PipelineLayout.zig b/src/vulkan/PipelineLayout.zig index 34095aa..4063fec 100644 --- a/src/vulkan/PipelineLayout.zig +++ b/src/vulkan/PipelineLayout.zig @@ -39,8 +39,9 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Pipel .set_layouts = [_]?*DescriptorSetLayout{null} ** lib.VULKAN_MAX_DESCRIPTOR_SETS, .dynamic_descriptor_offsets = [_]usize{0} ** lib.VULKAN_MAX_DESCRIPTOR_SETS, .push_ranges_count = info.push_constant_range_count, - .push_ranges = undefined, + .push_ranges = @splat(std.mem.zeroes(vk.PushConstantRange)), .ref_count = std.atomic.Value(usize).init(1), + // SAFETY: the backend assigns the vtable before returning the pipeline layout. .vtable = undefined, }; diff --git a/src/vulkan/QueryPool.zig b/src/vulkan/QueryPool.zig index 952b04a..189384c 100644 --- a/src/vulkan/QueryPool.zig +++ b/src/vulkan/QueryPool.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); @@ -37,6 +35,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Query .owner = device, .query_type = info.query_type, .queries = queries, + // SAFETY: the backend assigns the vtable before returning the query pool. .vtable = undefined, }; } diff --git a/src/vulkan/Queue.zig b/src/vulkan/Queue.zig index 45b40c8..44eb478 100644 --- a/src/vulkan/Queue.zig +++ b/src/vulkan/Queue.zig @@ -96,6 +96,7 @@ pub fn init(allocator: std.mem.Allocator, device: *Device, index: u32, family_in .index = index, .flags = flags, .host_allocator = VulkanAllocator.from(allocator).clone(), + // SAFETY: the backend assigns the dispatch table before returning the queue. .dispatch_table = undefined, }; } diff --git a/src/vulkan/RenderPass.zig b/src/vulkan/RenderPass.zig index f1cf1b2..c6193b3 100644 --- a/src/vulkan/RenderPass.zig +++ b/src/vulkan/RenderPass.zig @@ -79,6 +79,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Rende .owner = device, .attachments = attachments, .subpasses = subpasses, + // SAFETY: the backend assigns the vtable before returning the render pass. .vtable = undefined, }; } diff --git a/src/vulkan/Sampler.zig b/src/vulkan/Sampler.zig index b57ab68..e7ae47c 100644 --- a/src/vulkan/Sampler.zig +++ b/src/vulkan/Sampler.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const NonDispatchable = @import("NonDispatchable.zig"); - const VkError = @import("error_set.zig").VkError; const Device = @import("Device.zig"); @@ -48,6 +46,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Sampl .max_lod = info.max_lod, .border_color = info.border_color, .unnormalized_coordinates = info.unnormalized_coordinates, + // SAFETY: the backend assigns the vtable before returning the sampler. .vtable = undefined, }; } diff --git a/src/vulkan/ShaderModule.zig b/src/vulkan/ShaderModule.zig index c13dd00..0f71c63 100644 --- a/src/vulkan/ShaderModule.zig +++ b/src/vulkan/ShaderModule.zig @@ -1,8 +1,5 @@ const std = @import("std"); const vk = @import("vulkan"); -const lib = @import("lib.zig"); - -const NonDispatchable = @import("NonDispatchable.zig"); const VkError = @import("error_set.zig").VkError; @@ -24,6 +21,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Shade _ = info; return .{ .owner = device, + // SAFETY: the backend assigns the vtable before returning the shader module. .vtable = undefined, }; } diff --git a/src/vulkan/fallback_host_allocator.zig b/src/vulkan/fallback_host_allocator.zig index 9e0f488..6c1642e 100644 --- a/src/vulkan/fallback_host_allocator.zig +++ b/src/vulkan/fallback_host_allocator.zig @@ -8,9 +8,10 @@ const SpinMutex = @import("SpinMutex.zig"); var mutex: SpinMutex = .{}; var child_allocator: std.mem.Allocator = if (builtin.link_libc) std.heap.c_allocator else std.heap.smp_allocator; +var fallback_host_allocator_context: u8 = 0; pub const fallback_host_allocator: Allocator = .{ - .ptr = undefined, + .ptr = &fallback_host_allocator_context, .vtable = &vtable, }; diff --git a/src/vulkan/format.zig b/src/vulkan/format.zig index c202a9b..0cfb448 100644 --- a/src/vulkan/format.zig +++ b/src/vulkan/format.zig @@ -177,11 +177,11 @@ pub inline fn blockHeight(format: vk.Format) usize { } pub inline fn blockCountX(format: vk.Format, width: usize) usize { - return std.math.divCeil(usize, width, blockWidth(format)) catch unreachable; + return std.math.divCeil(usize, width, blockWidth(format)) catch @panic("Division failed"); } pub inline fn blockCountY(format: vk.Format, height: usize) usize { - return std.math.divCeil(usize, height, blockHeight(format)) catch unreachable; + return std.math.divCeil(usize, height, blockHeight(format)) catch @panic("Division failed"); } pub inline fn componentCount(format: vk.Format) usize { diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 36a8ebf..390157f 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -1,7 +1,6 @@ //! Here lies the documentation of the common internal API that Ape backends need to implement const std = @import("std"); -const builtin = @import("builtin"); const vk = @import("vulkan"); pub const c = @import("base_c"); diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index ccc9802..be96754 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -52,7 +52,7 @@ const has_wayland = switch (builtin.os.tag) { else => false, }; -pub const WaylandSurfaceKHR = if (has_wayland) @import("wsi/WaylandSurfaceKHR.zig") else undefined; +pub const WaylandSurfaceKHR = if (has_wayland) @import("wsi/WaylandSurfaceKHR.zig") else null; inline fn entryPointBeginLogTrace(comptime scope: @EnumLiteral()) void { std.log.scoped(scope).debug("Calling {s}...", .{@tagName(scope)}); @@ -358,6 +358,7 @@ pub export fn apeCreateInstance(info: *const vk.InstanceCreateInfo, callbacks: ? const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); Instance.validateCreateInfo(info) catch |err| return toVkResult(err); + // SAFETY: will be proprely initiated when not in test var instance: *lib.Instance = undefined; if (!builtin.is_test) { // Will call impl instead of interface as `root` refs the impl module @@ -365,12 +366,12 @@ pub export fn apeCreateInstance(info: *const vk.InstanceCreateInfo, callbacks: ? } instance.requestPhysicalDevices(allocator) catch |err| { - if (!builtin.is_test) instance.deinit(allocator) catch {}; + if (!builtin.is_test) instance.deinit(allocator) catch @panic("Caught an error while handling an error"); return toVkResult(err); }; const dispatchable = Dispatchable(Instance).wrap(allocator, instance) catch |err| { - if (!builtin.is_test) instance.deinit(allocator) catch {}; + if (!builtin.is_test) instance.deinit(allocator) catch @panic("Caught an error while handling an error"); return toVkResult(err); }; p_instance.* = dispatchable.toVkHandle(vk.Instance); @@ -489,7 +490,7 @@ pub export fn apeCreateDevice(p_physical_device: vk.PhysicalDevice, info: *const const device = physical_device.createDevice(allocator, info) catch |err| return toVkResult(err); const dispatchable = Dispatchable(Device).wrap(allocator, device) catch |err| { - device.destroy(allocator) catch {}; + device.destroy(allocator) catch @panic("Caught an error while handling an error"); return toVkResult(err); }; p_device.* = dispatchable.toVkHandle(vk.Device); diff --git a/src/vulkan/logger.zig b/src/vulkan/logger.zig index d804f25..6defb19 100644 --- a/src/vulkan/logger.zig +++ b/src/vulkan/logger.zig @@ -56,7 +56,7 @@ pub fn log(comptime level: std.log.Level, comptime scope: @EnumLiteral(), compti .warn, .err => stderr_file, }; - file.lock(io, .exclusive) catch {}; + file.lock(io, .exclusive) catch @panic("Caught an error while handling an error"); defer file.unlock(io); const now = std.Io.Timestamp.now(io, .real).toMicroseconds(); @@ -69,7 +69,7 @@ pub fn log(comptime level: std.log.Level, comptime scope: @EnumLiteral(), compti var fmt_buffer = std.mem.zeroes([4096]u8); var fmt_writer = std.Io.Writer.fixed(&fmt_buffer); - fmt_writer.print(format ++ "\n", args) catch {}; + fmt_writer.print(format ++ "\n", args) catch @panic("Caught an error while handling an error"); fmt_writer.flush() catch return; mutex.lock(io) catch return; @@ -86,31 +86,31 @@ pub fn log(comptime level: std.log.Level, comptime scope: @EnumLiteral(), compti .mode = std.Io.Terminal.Mode.detect(io, file, false, false) catch return, }; - term.setColor(.magenta) catch {}; + term.setColor(.magenta) catch @panic("Caught an error while handling an error"); writer.writeAll("[ApeDriver") catch continue; if (!builtin.is_test) { - term.setColor(.cyan) catch {}; + term.setColor(.cyan) catch @panic("Caught an error while handling an error"); writer.print(" {s} ", .{root.DRIVER_NAME}) catch continue; } - term.setColor(.yellow) catch {}; + term.setColor(.yellow) catch @panic("Caught an error while handling an error"); writer.print("{d}:{d}:{d}.{d:0>3}.{d:0>3}", .{ now_hour, now_min, now_sec, now_ms, now_us }) catch continue; - term.setColor(.magenta) catch {}; + term.setColor(.magenta) catch @panic("Caught an error while handling an error"); writer.writeAll("]") catch continue; - term.setColor(.cyan) catch {}; + term.setColor(.cyan) catch @panic("Caught an error while handling an error"); writer.print("[Thread {d: >8}]", .{std.Thread.getCurrentId()}) catch continue; - term.setColor(level_color) catch {}; + term.setColor(level_color) catch @panic("Caught an error while handling an error"); writer.print(prefix, .{}) catch continue; term.setColor(switch (level) { .err => .red, .warn => .magenta, else => .green, - }) catch {}; + }) catch @panic("Caught an error while handling an error"); writer.print("{s: >30}", .{scope_prefix}) catch continue; - term.setColor(.reset) catch {}; + term.setColor(.reset) catch @panic("Caught an error while handling an error"); writer.print("{s}\n", .{fmt_buffer[last_pos..pos]}) catch continue; writer.flush() catch continue; diff --git a/src/vulkan/wsi/PresentImage.zig b/src/vulkan/wsi/PresentImage.zig index f304e25..35a8699 100644 --- a/src/vulkan/wsi/PresentImage.zig +++ b/src/vulkan/wsi/PresentImage.zig @@ -9,9 +9,9 @@ const Image = @import("../Image.zig"); const NonDispatchable = @import("../NonDispatchable.zig").NonDispatchable; pub const State = enum { - Available, - Drawing, - Presenting, + available, + drawing, + presenting, }; const Self = @This(); @@ -25,7 +25,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image const image = try device.createImage(allocator, info); errdefer image.destroy(allocator); - var requirements: vk.MemoryRequirements = undefined; + var requirements = std.mem.zeroes(vk.MemoryRequirements); try image.getMemoryRequirements(&requirements); const memory = try device.allocateMemory(allocator, &.{ @@ -40,7 +40,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image .image = image, .non_dispatchable_image = try NonDispatchable(Image).wrap(allocator, image), .memory = memory, - .state = .Available, + .state = .available, }; } diff --git a/src/vulkan/wsi/SurfaceKHR.zig b/src/vulkan/wsi/SurfaceKHR.zig index 4b83cc2..1c86218 100644 --- a/src/vulkan/wsi/SurfaceKHR.zig +++ b/src/vulkan/wsi/SurfaceKHR.zig @@ -39,6 +39,7 @@ pub fn init(instance: *Instance, allocator: std.mem.Allocator) VkError!Self { return .{ .owner = instance, .swapchain = null, + // SAFETY: the backend assigns the vtable before returning the surface. .vtable = undefined, }; } diff --git a/src/vulkan/wsi/SwapchainKHR.zig b/src/vulkan/wsi/SwapchainKHR.zig index b66919e..0de5271 100644 --- a/src/vulkan/wsi/SwapchainKHR.zig +++ b/src/vulkan/wsi/SwapchainKHR.zig @@ -7,7 +7,6 @@ const VkError = @import("../error_set.zig").VkError; const BinarySemaphore = lib.BinarySemaphore; const Device = @import("../Device.zig"); const Fence = lib.Fence; -const Image = lib.Image; const PresentImage = @import("PresentImage.zig"); const SurfaceKHR = lib.SurfaceKHR; @@ -42,7 +41,7 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, surface: *SurfaceKH var initialized_image_count: usize = 0; errdefer { for (images[0..initialized_image_count]) |*image| { - surface.detachImage(allocator, image) catch {}; + surface.detachImage(allocator, image) catch @panic("Caught an error while handling an error"); image.deinit(allocator); } } @@ -86,8 +85,8 @@ pub fn getNextImage(self: *const Self, timeout: u64, semaphore: ?*BinarySemaphor // TODO: handle timeout correctly for (self.images, 0..) |*image, i| { - if (image.state == .Available) { - image.state = .Drawing; + if (image.state == .available) { + image.state = .drawing; index.* = @intCast(i); if (semaphore) |s| try s.signal(); @@ -105,7 +104,7 @@ pub fn present(self: *Self, index: usize) VkError!void { const image = &self.images[index]; if (self.surface) |surface| { - image.state = .Presenting; + image.state = .presenting; try surface.presentImage(allocator, image); } } @@ -116,7 +115,7 @@ pub fn detachSurface(self: *Self) VkError!void { if (self.surface) |surface| { surface.swapchain = null; for (self.images) |*image| { - if (image.state == .Available) + if (image.state == .available) try surface.detachImage(allocator, image); } } @@ -126,7 +125,7 @@ pub fn detachSurface(self: *Self) VkError!void { pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { for (self.images) |*image| { if (self.surface) |surface| { - surface.detachImage(allocator, image) catch {}; + surface.detachImage(allocator, image) catch @panic("Caught an error while handling an error"); } image.deinit(allocator); } diff --git a/src/vulkan/wsi/WaylandSurfaceKHR.zig b/src/vulkan/wsi/WaylandSurfaceKHR.zig index 9b7193b..e5627d1 100644 --- a/src/vulkan/wsi/WaylandSurfaceKHR.zig +++ b/src/vulkan/wsi/WaylandSurfaceKHR.zig @@ -20,7 +20,7 @@ const WaylandImage = struct { }; fn wlRegistryHandleGlobal(data: ?*anyopaque, registry: ?*wayland.wl_registry, name: u32, interface: [*c]const u8, _: u32) callconv(.c) void { - const pshm: **wayland.wl_shm = @ptrCast(@alignCast(data orelse return)); + const pshm: *?*wayland.wl_shm = @ptrCast(@alignCast(data orelse return)); if (std.mem.eql(u8, std.mem.span(interface), "wl_shm")) { if (wayland.wl_registry_bind(registry orelse return, name, wayland.wl_shm_interface, 1)) |shm| { pshm.* = @ptrCast(@alignCast(shm)); @@ -38,7 +38,7 @@ const wl_registry_listener: wayland.wl_registry_listener = .{ interface: Interface, display: *wayland.wl_display, surface: *wayland.wl_surface, -shm: *wayland.wl_shm, +shm: ?*wayland.wl_shm, image_map: std.AutoHashMapUnmanaged(*PresentImage, *WaylandImage), pub fn create(instance: *Instance, allocator: std.mem.Allocator, info: *const vk.WaylandSurfaceCreateInfoKHR) VkError!*Interface { @@ -61,13 +61,14 @@ pub fn create(instance: *Instance, allocator: std.mem.Allocator, info: *const vk .interface = interface, .display = info.display, .surface = info.surface, - .shm = undefined, + .shm = null, .image_map = .empty, }; const registry = wayland.wl_display_get_registry(@ptrCast(self.display)) orelse return VkError.Unknown; _ = wayland.wl_registry_add_listener(registry, &wl_registry_listener, @ptrCast(&self.shm)); _ = wayland.wl_display_dispatch(@ptrCast(self.display)); + if (self.shm == null) return VkError.Unknown; return &self.interface; } @@ -106,7 +107,8 @@ pub fn attachImage(interface: *Interface, allocator: std.mem.Allocator, image: * const data = std.posix.mmap(null, size, .{ .READ = true, .WRITE = true }, .{ .TYPE = .SHARED }, fd, 0) catch return VkError.OutOfHostMemory; errdefer std.posix.munmap(data); - const pool = wayland.wl_shm_create_pool(self.shm, fd, @intCast(size)) orelse return VkError.Unknown; + const shm = self.shm orelse return VkError.Unknown; + const pool = wayland.wl_shm_create_pool(shm, fd, @intCast(size)) orelse return VkError.Unknown; defer wayland.wl_shm_pool_destroy(pool); const buffer = wayland.wl_shm_pool_create_buffer(pool, 0, @intCast(width), @intCast(height), @intCast(stride), wayland.WL_SHM_FORMAT_ARGB8888) orelse return VkError.Unknown; @@ -152,7 +154,7 @@ pub fn presentImage(interface: *Interface, allocator: std.mem.Allocator, image: _ = wayland.wl_display_flush(@ptrCast(self.display)); - image.state = .Available; + image.state = .available; } fn createShmFile(size: usize) VkError!std.posix.fd_t { diff --git a/src/vulkan/wsi/clients/wayland.zig b/src/vulkan/wsi/clients/wayland.zig index a3f056e..ae78351 100644 --- a/src/vulkan/wsi/clients/wayland.zig +++ b/src/vulkan/wsi/clients/wayland.zig @@ -11,16 +11,16 @@ pub const wl_registry_listener = extern struct { global_remove: ?*const fn (data: ?*anyopaque, wl_registry: ?*wl_registry, name: u32) callconv(.c) void = null, }; -pub const WL_BUFFER_DESTROY = @as(c_int, 0); -pub const WL_DISPLAY_GET_REGISTRY = @as(c_int, 1); -pub const WL_REGISTRY_BIND = @as(c_int, 0); -pub const WL_SHM_CREATE_POOL = @as(c_int, 0); -pub const WL_SHM_FORMAT_ARGB8888 = @as(c_int, 0); -pub const WL_SHM_POOL_CREATE_BUFFER = @as(c_int, 0); -pub const WL_SHM_POOL_DESTROY = @as(c_int, 1); -pub const WL_SURFACE_ATTACH = @as(c_int, 1); -pub const WL_SURFACE_COMMIT = @as(c_int, 6); -pub const WL_SURFACE_DAMAGE = @as(c_int, 2); +pub const WL_BUFFER_DESTROY: c_int = 0; +pub const WL_DISPLAY_GET_REGISTRY: c_int = 1; +pub const WL_REGISTRY_BIND: c_int = 0; +pub const WL_SHM_CREATE_POOL: c_int = 0; +pub const WL_SHM_FORMAT_ARGB8888: c_int = 0; +pub const WL_SHM_POOL_CREATE_BUFFER: c_int = 0; +pub const WL_SHM_POOL_DESTROY: c_int = 1; +pub const WL_SURFACE_ATTACH: c_int = 1; +pub const WL_SURFACE_COMMIT: c_int = 6; +pub const WL_SURFACE_DAMAGE: c_int = 2; pub const wl_buffer = opaque {}; pub const wl_callback = opaque {}; @@ -46,17 +46,27 @@ pub const wl_interface = extern struct { events: ?[*]const wl_message = null, }; +// SAFETY: load assigns every function pointer before any protocol wrapper is used. pub var wl_display_dispatch: *const fn (*wl_display) callconv(.c) c_int = undefined; +// SAFETY: load assigns every function pointer before any protocol wrapper is used. pub var wl_proxy_marshal_flags: *const fn (*wl_proxy, u32, ?*const wl_interface, u32, u32, ...) callconv(.c) ?*wl_proxy = undefined; +// SAFETY: load assigns every function pointer before any protocol wrapper is used. pub var wl_proxy_get_version: *const fn (*wl_proxy) callconv(.c) u32 = undefined; +// SAFETY: load assigns every function pointer before any protocol wrapper is used. pub var wl_proxy_add_listener: *const fn (*wl_proxy, **const fn (void) void, ?*anyopaque) callconv(.c) c_int = undefined; +// SAFETY: load assigns every function pointer before any protocol wrapper is used. pub var wl_display_flush: *const fn (*wl_display) callconv(.c) c_int = undefined; +// SAFETY: load resolves every interface pointer before a surface can be created. pub var wl_buffer_interface: *wl_interface = undefined; +// SAFETY: load resolves every interface pointer before a surface can be created. pub var wl_registry_interface: *wl_interface = undefined; +// SAFETY: load resolves every interface pointer before a surface can be created. pub var wl_shm_interface: *wl_interface = undefined; +// SAFETY: load resolves every interface pointer before a surface can be created. pub var wl_shm_pool_interface: *wl_interface = undefined; +// SAFETY: load initializes the module before it can be closed or queried. pub var module: std.DynLib = undefined; pub var ref_count = std.atomic.Value(usize).init(0); diff --git a/test/test_runner.zig b/test/test_runner.zig new file mode 100644 index 0000000..3925e34 --- /dev/null +++ b/test/test_runner.zig @@ -0,0 +1,237 @@ +// See https://gist.github.com/karlseguin/c6bea5b35e4e8d26af6f81c22cb5d76b/1f317ebc9cd09bc50fd5591d09c34255e15d1d85 + +const std = @import("std"); +const builtin = @import("builtin"); + +const Allocator = std.mem.Allocator; + +const BORDER = "=" ** 80; + +// use in custom panic handler +var current_test: ?[]const u8 = null; + +pub fn main() !void { + var mem: [8192]u8 = undefined; + var fba = std.heap.FixedBufferAllocator.init(&mem); + + const allocator = fba.allocator(); + + var slowest = SlowTracker.init(allocator, 5); + defer slowest.deinit(allocator); + + var pass: usize = 0; + var fail: usize = 0; + var skip: usize = 0; + var leak: usize = 0; + + Printer.fmt("\r\x1b[0K", .{}); // beginning of line and clear to end of line + + for (builtin.test_functions) |t| { + if (isSetup(t)) { + t.func() catch |err| { + Printer.status(.fail, "\nsetup \"{s}\" failed: {}\n", .{ t.name, err }); + return err; + }; + } + } + + for (builtin.test_functions) |t| { + if (isSetup(t) or isTeardown(t)) { + continue; + } + + var status = Status.pass; + slowest.startTiming(); + + const friendly_name = blk: { + const name = t.name; + var it = std.mem.splitScalar(u8, name, '.'); + while (it.next()) |value| { + if (std.mem.eql(u8, value, "test")) { + const rest = it.rest(); + break :blk if (rest.len > 0) rest else name; + } + } + break :blk name; + }; + + current_test = friendly_name; + std.testing.allocator_instance = .{}; + const result = t.func(); + current_test = null; + + const ns_taken = slowest.endTiming(allocator, friendly_name); + + if (std.testing.allocator_instance.deinit() == .leak) { + leak += 1; + Printer.status(.fail, "\n{s}\n\"{s}\" - Memory Leak\n{s}\n", .{ BORDER, friendly_name, BORDER }); + } + + if (result) |_| { + pass += 1; + } else |err| switch (err) { + error.SkipZigTest => { + skip += 1; + status = .skip; + }, + else => { + status = .fail; + fail += 1; + Printer.status(.fail, "\n{s}\n\"{s}\" - {s}\n{s}\n", .{ BORDER, friendly_name, @errorName(err), BORDER }); + if (@errorReturnTrace()) |trace| { + std.debug.dumpErrorReturnTrace(trace); + } + }, + } + + const ms = @as(f64, @floatFromInt(ns_taken)) / 1_000_000.0; + Printer.status(status, "\x1b[35m[{d: >10.2} ms]\x1b[0m {s: <120}", .{ ms, friendly_name }); + } + + for (builtin.test_functions) |t| { + if (isTeardown(t)) { + t.func() catch |err| { + Printer.status(.fail, "\nteardown \"{s}\" failed: {}\n", .{ t.name, err }); + return err; + }; + } + } + + const total_tests = pass + fail; + const status = if (fail == 0) Status.pass else Status.fail; + Printer.status(status, "\n{d} of {d} test{s} passed\n", .{ pass, total_tests, if (total_tests != 1) "s" else "" }); + if (skip > 0) { + Printer.status(.skip, "{d} test{s} skipped\n", .{ skip, if (skip != 1) "s" else "" }); + } + if (leak > 0) { + Printer.status(.fail, "{d} test{s} leaked\n", .{ leak, if (leak != 1) "s" else "" }); + } + Printer.fmt("\n", .{}); + try slowest.display(); + Printer.fmt("\n", .{}); + std.process.exit(if (fail == 0) 0 else 1); +} + +const Printer = struct { + fn fmt(comptime format: []const u8, args: anytype) void { + var buffer: [256]u8 = undefined; + const stderr = std.Options.debug_io.lockStderr(&buffer, .escape_codes) catch return; + defer std.Options.debug_io.unlockStderr(); + stderr.file_writer.interface.print(format, args) catch @panic("Caught an error while handling an error"); + } + + fn status(s: Status, comptime format: []const u8, args: anytype) void { + switch (s) { + .pass => fmt(format ++ "\x1b[32m✓\x1b[0m\n", args), + .fail => fmt(format ++ "\x1b[31m✗\x1b[0m\n", args), + .skip => fmt(format ++ "\x1b[33m \x1b[0m\n", args), + else => unreachable, + } + } +}; + +const Status = enum { + pass, + fail, + skip, + text, +}; + +const SlowTracker = struct { + const SlowestQueue = std.PriorityDequeue(TestInfo, void, compareTiming); + max: usize, + slowest: SlowestQueue, + timer: std.Io.Timestamp, + + fn init(allocator: Allocator, count: u32) SlowTracker { + var slowest = SlowestQueue.empty; + slowest.ensureTotalCapacity(allocator, count) catch @panic("OOM"); + return .{ + .max = count, + .timer = std.Io.Timestamp.now(std.testing.io, .real), + .slowest = slowest, + }; + } + + const TestInfo = struct { + ns: i96, + name: []const u8, + }; + + fn deinit(self: *SlowTracker, allocator: std.mem.Allocator) void { + self.slowest.deinit(allocator); + } + + fn startTiming(self: *SlowTracker) void { + self.timer = std.Io.Timestamp.now(std.testing.io, .real); + } + + fn endTiming(self: *SlowTracker, allocator: std.mem.Allocator, test_name: []const u8) i96 { + const duration = self.timer.untilNow(std.testing.io, .real); + const ns = duration.toNanoseconds(); + + var slowest = &self.slowest; + + if (slowest.count() < self.max) { + // Capacity is fixed to the # of slow tests we want to track + // If we've tracked fewer tests than this capacity, than always add + slowest.push(allocator, TestInfo{ .ns = ns, .name = test_name }) catch @panic("failed to track test timing"); + return ns; + } + + { + // Optimization to avoid shifting the dequeue for the common case + // where the test isn't one of our slowest. + const fastest_of_the_slow = slowest.peekMin() orelse unreachable; + if (fastest_of_the_slow.ns > ns) { + // the test was faster than our fastest slow test, don't add + return ns; + } + } + + // the previous fastest of our slow tests, has been pushed off. + _ = slowest.popMin(); + slowest.push(allocator, TestInfo{ .ns = ns, .name = test_name }) catch @panic("failed to track test timing"); + return ns; + } + + fn display(self: *SlowTracker) !void { + var slowest = self.slowest; + const count = slowest.count(); + Printer.fmt("Slowest {d} test{s}: \n", .{ count, if (count != 1) "s" else "" }); + while (slowest.popMin()) |info| { + const ms = @as(f64, @floatFromInt(info.ns)) / 1_000_000.0; + Printer.fmt(" {d:.2}ms\t{s}\n", .{ ms, info.name }); + } + } + + fn compareTiming(context: void, a: TestInfo, b: TestInfo) std.math.Order { + _ = context; + return std.math.order(a.ns, b.ns); + } +}; + +pub const panic = std.debug.FullPanic(struct { + pub fn panicFn(msg: []const u8, first_trace_addr: ?usize) noreturn { + if (current_test) |ct| { + Printer.fmt("\x1b[31m{s}\npanic running \"{s}\"\n{s}\x1b[0m\n", .{ BORDER, ct, BORDER }); + } + std.debug.defaultPanic(msg, first_trace_addr); + } +}.panicFn); + +fn isUnnamed(t: std.builtin.TestFn) bool { + const marker = ".test_"; + const test_name = t.name; + const index = std.mem.indexOf(u8, test_name, marker) orelse return false; + _ = std.fmt.parseInt(u32, test_name[index + marker.len ..], 10) catch return false; + return true; +} + +fn isSetup(t: std.builtin.TestFn) bool { + return std.mem.endsWith(u8, t.name, "tests:beforeAll"); +} + +fn isTeardown(t: std.builtin.TestFn) bool { + return std.mem.endsWith(u8, t.name, "tests:afterAll"); +}