diff --git a/README.md b/README.md index d040c8e..a19999a 100644 --- a/README.md +++ b/README.md @@ -521,7 +521,7 @@ vkCreatePipelineLayout | ⚙️ WIP vkCreateQueryPool | ⚙️ WIP vkCreateRenderPass | ⚙️ WIP vkCreateSampler | ⚙️ WIP -vkCreateSemaphore | ⚙️ WIP +vkCreateSemaphore | ✅ Implemented vkCreateShaderModule | ⚙️ WIP vkCreateSwapchainKHR | ⚙️ WIP vkCreateWaylandSurfaceKHR | ⚙️ WIP @@ -546,7 +546,7 @@ vkDestroyPipelineLayout | ⚙️ WIP vkDestroyQueryPool | ⚙️ WIP vkDestroyRenderPass | ⚙️ WIP vkDestroySampler | ⚙️ WIP -vkDestroySemaphore | ⚙️ WIP +vkDestroySemaphore | ✅ Implemented vkDestroyShaderModule | ⚙️ WIP vkDestroySurfaceKHR | ⚙️ WIP vkDestroySwapchainKHR | ⚙️ WIP diff --git a/src/intel/FlintBinarySemaphore.zig b/src/intel/FlintBinarySemaphore.zig index 421d048..4e0dfc9 100644 --- a/src/intel/FlintBinarySemaphore.zig +++ b/src/intel/FlintBinarySemaphore.zig @@ -1,20 +1,71 @@ const std = @import("std"); const vk = @import("vulkan"); 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; +const drm_syncobj_destroy = 0xc0; +const drm_syncobj_wait = 0xc3; +const drm_syncobj_reset = 0xc4; +const drm_syncobj_signal = 0xc5; + +const syncobj_wait_all: u32 = 1 << 0; +const syncobj_wait_for_submit: u32 = 1 << 1; + +const SyncObjCreate = extern struct { + handle: u32, + flags: u32, +}; + +const SyncObjDestroy = extern struct { + handle: u32, + pad: u32, +}; + +const SyncObjWait = extern struct { + handles: u64, + timeout_nsec: i64, + count_handles: u32, + flags: u32, + first_signaled: u32, + pad: u32, + deadline_nsec: u64, +}; + +const SyncObjArray = extern struct { + handles: u64, + count_handles: u32, + pad: u32, +}; const Self = @This(); pub const Interface = base.BinarySemaphore; interface: Interface, +handle: u32, pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.SemaphoreCreateInfo) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; errdefer allocator.destroy(self); var interface = try Interface.init(device, allocator, info); + const flint_device: *FlintDevice = @alignCast(@fieldParentPtr("interface", device)); + var create_info = SyncObjCreate{ + .handle = 0, + .flags = 0, + }; + + base.utils.ioctl( + try flint_device.kmd.file(), + device.io(), + kmd.drmIoctlIowr(drm_syncobj_create, SyncObjCreate), + &create_info, + ) catch return VkError.DeviceLost; + errdefer destroyHandle(flint_device, device.io(), create_info.handle); interface.vtable = &.{ .destroy = destroy, @@ -24,21 +75,89 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v self.* = .{ .interface = interface, + .handle = create_info.handle, }; return self; } pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); + destroyHandle(device, interface.owner.io(), self.handle); allocator.destroy(self); } pub fn signal(interface: *Interface) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - _ = self; + const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); + var handles = [_]u32{self.handle}; + var signal_info = SyncObjArray{ + .handles = @intFromPtr(&handles), + .count_handles = handles.len, + .pad = 0, + }; + base.utils.ioctl( + try device.kmd.file(), + interface.owner.io(), + kmd.drmIoctlIowr(drm_syncobj_signal, SyncObjArray), + &signal_info, + ) catch return VkError.DeviceLost; } pub fn wait(interface: *Interface) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - _ = self; + const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); + var handles = [_]u32{self.handle}; + var wait_info = SyncObjWait{ + .handles = @intFromPtr(&handles), + .timeout_nsec = std.math.maxInt(i64), + .count_handles = handles.len, + .flags = syncobj_wait_all | syncobj_wait_for_submit, + .first_signaled = 0, + .pad = 0, + .deadline_nsec = 0, + }; + + const errno = base.utils.ioctlErrno( + try device.kmd.file(), + interface.owner.io(), + kmd.drmIoctlIowr(drm_syncobj_wait, SyncObjWait), + &wait_info, + ) catch return VkError.DeviceLost; + + switch (errno) { + .SUCCESS => {}, + else => return VkError.DeviceLost, + } + try reset(interface); +} + +pub fn reset(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); + var handles = [_]u32{self.handle}; + var reset_info = SyncObjArray{ + .handles = @intFromPtr(&handles), + .count_handles = handles.len, + .pad = 0, + }; + base.utils.ioctl( + try device.kmd.file(), + interface.owner.io(), + kmd.drmIoctlIowr(drm_syncobj_reset, SyncObjArray), + &reset_info, + ) catch return VkError.DeviceLost; +} + +fn destroyHandle(device: *FlintDevice, io: std.Io, handle: u32) void { + var destroy_info = SyncObjDestroy{ + .handle = handle, + .pad = 0, + }; + base.utils.ioctl( + device.kmd.file() catch return, + io, + kmd.drmIoctlIowr(drm_syncobj_destroy, SyncObjDestroy), + &destroy_info, + ) catch {}; } diff --git a/src/intel/FlintQueue.zig b/src/intel/FlintQueue.zig index 7e4d3da..2c2b786 100644 --- a/src/intel/FlintQueue.zig +++ b/src/intel/FlintQueue.zig @@ -2,6 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const FlintBinarySemaphore = @import("FlintBinarySemaphore.zig"); const FlintCommandBuffer = @import("FlintCommandBuffer.zig"); const FlintDevice = @import("FlintDevice.zig"); const FlintFence = @import("FlintFence.zig"); @@ -55,51 +56,67 @@ pub fn bindSparse(interface: *Interface, info: []const vk.BindSparseInfo, fence: pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*base.Fence) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const device: *FlintDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); - - var remaining_batches: usize = 0; - for (infos) |info| { - for (info.command_buffers.items) |command_buffer| { - const intel_command_buffer: *FlintCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); - if (intel_command_buffer.batch.items.len != 0) remaining_batches += 1; - } - } - const batch_count = remaining_batches; + const allocator = interface.host_allocator.allocator(); try self.completion.interface.reset(); - for (infos) |info| { - for (info.wait_semaphores.items) |semaphore| { - try semaphore.wait(); - } + for (infos, 0..) |info, info_index| { + const last_info = info_index + 1 == infos.len; + const request_count = @max(info.command_buffers.items.len, 1); - for (info.command_buffers.items) |command_buffer| { - const intel_command_buffer: *FlintCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); - if (intel_command_buffer.batch.items.len == 0) { - try intel_command_buffer.submitGpuBatch(&.{}); - continue; - } + for (0..request_count) |request_index| { + const first_request = request_index == 0; + const last_request = request_index + 1 == request_count; - remaining_batches -= 1; - var syncs: [2]kmd.SyncDependency = undefined; - var sync_count: usize = 0; - if (remaining_batches == 0) { - syncs[sync_count] = .{ .handle = self.completion.handle, .signal = true }; - sync_count += 1; - if (fence) |base_fence| { - const flint_fence: *FlintFence = @alignCast(@fieldParentPtr("interface", base_fence)); - syncs[sync_count] = .{ .handle = flint_fence.handle, .signal = true }; - sync_count += 1; + var syncs = std.ArrayList(kmd.SyncDependency).empty; + defer syncs.deinit(allocator); + + if (first_request) { + for (info.wait_semaphores.items) |base_semaphore| { + const semaphore: *FlintBinarySemaphore = @alignCast(@fieldParentPtr("interface", base_semaphore)); + syncs.append(allocator, .{ .handle = semaphore.handle, .wait = true }) catch return VkError.OutOfHostMemory; } } - try intel_command_buffer.submitGpuBatch(syncs[0..sync_count]); - } - for (info.signal_semaphores.items) |semaphore| { - try semaphore.signal(); + if (last_request) { + for (info.signal_semaphores.items) |base_semaphore| { + const semaphore: *FlintBinarySemaphore = @alignCast(@fieldParentPtr("interface", base_semaphore)); + syncs.append(allocator, .{ .handle = semaphore.handle, .signal = true }) catch return VkError.OutOfHostMemory; + } + + if (last_info) { + syncs.append(allocator, .{ .handle = self.completion.handle, .signal = true }) catch return VkError.OutOfHostMemory; + if (fence) |base_fence| { + const flint_fence: *FlintFence = @alignCast(@fieldParentPtr("interface", base_fence)); + syncs.append(allocator, .{ .handle = flint_fence.handle, .signal = true }) catch return VkError.OutOfHostMemory; + } + } + } + + if (info.command_buffers.items.len == 0) { + try device.kmd.submitBatch( + interface.owner.io(), + allocator, + &.{}, + &.{}, + syncs.items, + ); + } else { + const command_buffer = info.command_buffers.items[request_index]; + const intel_command_buffer: *FlintCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); + try intel_command_buffer.submitGpuBatch(syncs.items); + } + + if (first_request) { + for (info.wait_semaphores.items) |base_semaphore| { + const semaphore: *FlintBinarySemaphore = @alignCast(@fieldParentPtr("interface", base_semaphore)); + try FlintBinarySemaphore.reset(&semaphore.interface); + } + } } } - if (batch_count == 0) { + if (infos.len == 0) { var syncs: [2]kmd.SyncDependency = undefined; var sync_count: usize = 1; syncs[0] = .{ .handle = self.completion.handle, .signal = true }; @@ -109,11 +126,9 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*bas sync_count += 1; } - // A real no-op request preserves queue order: its output fence cannot - // signal ahead of an earlier request that is still running. try device.kmd.submitBatch( interface.owner.io(), - interface.host_allocator.allocator(), + allocator, &.{}, &.{}, syncs[0..sync_count],