From 23f6d70e6c500f531680f6787bc1c181b0649c68 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Wed, 8 Jul 2026 00:58:30 +0200 Subject: [PATCH] adding base command buffer submit and some buffer commands in phi --- build.zig | 2 + src/phi/PhiCommandBuffer.zig | 216 +++++++++++++++++++++++++---------- src/phi/PhiDevice.zig | 7 +- src/phi/PhiDeviceMemory.zig | 4 +- src/phi/PhiQueue.zig | 30 ++++- src/phi/PhiTransport.zig | 5 +- src/phi/mic/Buffer.c | 66 +++++++++++ src/phi/mic/Buffer.h | 9 ++ src/phi/mic/CommandBuffer.c | 96 ++++++++++++++++ src/phi/mic/CommandBuffer.h | 16 +++ src/phi/mic/Daemon.c | 18 ++- src/phi/shared/Commands.h | 39 +++++++ src/phi/shared/Protocol.h | 33 ++++-- 13 files changed, 456 insertions(+), 85 deletions(-) create mode 100644 src/phi/mic/Buffer.c create mode 100644 src/phi/mic/Buffer.h create mode 100644 src/phi/mic/CommandBuffer.c create mode 100644 src/phi/mic/CommandBuffer.h create mode 100644 src/phi/shared/Commands.h diff --git a/build.zig b/build.zig index 4c796f0..97ea782 100644 --- a/build.zig +++ b/build.zig @@ -607,6 +607,8 @@ fn addPhiCardDaemon( const sources = [_][]const u8{ "src/phi/mic/main.c", + "src/phi/mic/Buffer.c", + "src/phi/mic/CommandBuffer.c", "src/phi/mic/Daemon.c", "src/phi/mic/Logger.c", "src/phi/mic/Memory.c", diff --git a/src/phi/PhiCommandBuffer.zig b/src/phi/PhiCommandBuffer.zig index 91c5b4f..081da6c 100644 --- a/src/phi/PhiCommandBuffer.zig +++ b/src/phi/PhiCommandBuffer.zig @@ -1,13 +1,19 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const lib = @import("lib.zig"); +const proto = lib.proto; const VkError = base.VkError; +const PhiDeviceMemory = @import("PhiDeviceMemory.zig"); const Self = @This(); pub const Interface = base.CommandBuffer; interface: Interface, +cmd_count: usize, +serialized_cmd_count: usize, +commands: std.ArrayList(u8), pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.CommandBufferAllocateInfo) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; @@ -67,20 +73,21 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .writeTimestamp = writeTimestamp, }; - self.* = .{ .interface = interface }; + self.* = .{ + .interface = interface, + .cmd_count = 0, + .serialized_cmd_count = 0, + .commands = .empty, + }; return self; } pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.commands.deinit(allocator); allocator.destroy(self); } -pub fn execute(self: *Self) VkError!void { - try self.interface.submit(); - self.interface.finish() catch {}; -} - pub fn begin(interface: *Interface, info: *const vk.CommandBufferBeginInfo) VkError!void { _ = interface; _ = info; @@ -91,28 +98,56 @@ pub fn end(interface: *Interface) VkError!void { } pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count = 0; + self.serialized_cmd_count = 0; + self.commands.clearRetainingCapacity(); _ = flags; } +fn appendCommand(self: *Self, comptime T: type, command_type: c_int, payload: T) VkError!void { + const allocator = self.interface.host_allocator.allocator(); + const header: proto.PhiCmdHeader = .{ + .magic = proto.PHI_COMMAND_MAGIC, + .type = @intCast(command_type), + }; + self.commands.appendSlice(allocator, std.mem.asBytes(&header)) catch return VkError.OutOfHostMemory; + self.commands.appendSlice(allocator, std.mem.asBytes(&payload)) catch return VkError.OutOfHostMemory; + self.cmd_count += 1; + self.serialized_cmd_count += 1; +} + +fn remoteMemory(buffer: *base.Buffer) VkError!*PhiDeviceMemory { + const memory = buffer.memory orelse return VkError.ValidationFailed; + const phi_memory: *PhiDeviceMemory = @alignCast(@fieldParentPtr("interface", memory)); + if (phi_memory.remote_handle == 0) { + return VkError.ValidationFailed; + } + return phi_memory; +} + pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, flags: vk.QueryControlFlags) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = flags; try pool.begin(query); } pub fn endQuery(interface: *Interface, pool: *base.QueryPool, query: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; try pool.end(query); } pub fn resetQueryPool(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; try pool.reset(first, count); } pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, framebuffer: *base.Framebuffer, render_area: vk.Rect2D, clear_values: ?[]const vk.ClearValue) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = render_pass; _ = framebuffer; _ = render_area; @@ -120,7 +155,8 @@ pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, fra } pub fn bindDescriptorSets(interface: *Interface, bind_point: vk.PipelineBindPoint, first_set: u32, sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*base.DescriptorSet, dynamic_offsets: []const u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = bind_point; _ = first_set; _ = sets; @@ -128,27 +164,31 @@ pub fn bindDescriptorSets(interface: *Interface, bind_point: vk.PipelineBindPoin } pub fn bindPipeline(interface: *Interface, bind_point: vk.PipelineBindPoint, pipeline: *base.Pipeline) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = bind_point; _ = pipeline; } pub fn bindIndexBuffer(interface: *Interface, buffer: *base.Buffer, offset: usize, index_type: vk.IndexType) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = buffer; _ = offset; _ = index_type; } pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffer, offset: usize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = index; _ = buffer; _ = offset; } pub fn blitImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src; _ = src_layout; _ = dst; @@ -158,13 +198,15 @@ pub fn blitImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLa } pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = attachment; _ = rect; } pub fn clearColorImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, range: vk.ImageSubresourceRange) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = image; _ = layout; _ = color; @@ -172,7 +214,8 @@ pub fn clearColorImage(interface: *Interface, image: *base.Image, layout: vk.Ima } pub fn clearDepthStencilImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, value: *const vk.ClearDepthStencilValue, range: vk.ImageSubresourceRange) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = image; _ = layout; _ = value; @@ -180,14 +223,30 @@ pub fn clearDepthStencilImage(interface: *Interface, image: *base.Image, layout: } pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, regions: []const vk.BufferCopy) VkError!void { - _ = interface; - _ = src; - _ = dst; - _ = regions; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const src_memory = try remoteMemory(src); + const dst_memory = try remoteMemory(dst); + + for (regions) |region| { + const src_offset, const src_overflow = @addWithOverflow(src.offset, region.src_offset); + const dst_offset, const dst_overflow = @addWithOverflow(dst.offset, region.dst_offset); + if (src_overflow != 0 or dst_overflow != 0) { + return VkError.ValidationFailed; + } + + try self.appendCommand(proto.PhiCmdCopyBuffer, proto.PHI_CMD_COPY_BUFFER, .{ + .size = region.size, + .src_memory = @intCast(src_memory.remote_handle), + .dst_memory = @intCast(dst_memory.remote_handle), + .src_offset = src_offset, + .dst_offset = dst_offset, + }); + } } pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src; _ = dst; _ = dst_layout; @@ -195,7 +254,8 @@ pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Im } pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src; _ = src_layout; _ = dst; @@ -204,7 +264,8 @@ pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLa } pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src; _ = src_layout; _ = dst; @@ -212,7 +273,8 @@ pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk } pub fn copyQueryPoolResults(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32, dst: *base.Buffer, offset: vk.DeviceSize, stride: vk.DeviceSize, flags: vk.QueryResultFlags) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = pool; _ = first; _ = count; @@ -223,14 +285,16 @@ pub fn copyQueryPoolResults(interface: *Interface, pool: *base.QueryPool, first: } pub fn dispatch(interface: *Interface, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = group_count_x; _ = group_count_y; _ = group_count_z; } pub fn dispatchBase(interface: *Interface, base_group_x: u32, base_group_y: u32, base_group_z: u32, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = base_group_x; _ = base_group_y; _ = base_group_z; @@ -240,18 +304,21 @@ pub fn dispatchBase(interface: *Interface, base_group_x: u32, base_group_y: u32, } pub fn setDeviceMask(interface: *Interface, device_mask: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = device_mask; } pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = buffer; _ = offset; } pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = vertex_count; _ = instance_count; _ = first_vertex; @@ -259,7 +326,8 @@ pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, f } pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: i32, first_instance: usize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = index_count; _ = instance_count; _ = first_index; @@ -268,7 +336,8 @@ pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: us } pub fn drawIndexedIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = buffer; _ = offset; _ = count; @@ -276,7 +345,8 @@ pub fn drawIndexedIndirect(interface: *Interface, buffer: *base.Buffer, offset: } pub fn drawIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = buffer; _ = offset; _ = count; @@ -284,36 +354,47 @@ pub fn drawIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, } pub fn endRenderPass(interface: *Interface) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; } pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = commands; } pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { - _ = interface; - _ = buffer; - _ = offset; - _ = size; - _ = data; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; + + const memory = try remoteMemory(buffer); + + try self.appendCommand(proto.PhiCmdFillBuffer, proto.PHI_CMD_FILL_BUFFER, .{ + .size = if (size == vk.WHOLE_SIZE) buffer.interface.size - offset else size, + .memory = @intCast(memory.remote_handle), + .offset = offset, + .data = data, + }); } pub fn updateBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, data: []const u8) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = buffer; _ = offset; _ = data; } pub fn nextSubpass(interface: *Interface, contents: vk.SubpassContents) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = contents; } pub fn pipelineBarrier(interface: *Interface, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, dependency: vk.DependencyFlags, memory: []const vk.MemoryBarrier, buffers: []const vk.BufferMemoryBarrier, images: []const vk.ImageMemoryBarrier) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src_stage; _ = dst_stage; _ = dependency; @@ -323,20 +404,23 @@ pub fn pipelineBarrier(interface: *Interface, src_stage: vk.PipelineStageFlags, } pub fn pushConstants(interface: *Interface, stages: vk.ShaderStageFlags, offset: u32, blob: []const u8) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = stages; _ = offset; _ = blob; } pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = stage; try event.reset(); } pub fn resolveImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, region: vk.ImageResolve) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = src; _ = src_layout; _ = dst; @@ -345,66 +429,77 @@ pub fn resolveImage(interface: *Interface, src: *base.Image, src_layout: vk.Imag } pub fn setEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = stage; try event.signal(); } pub fn setScissor(interface: *Interface, first: u32, scissor: []const vk.Rect2D) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = first; _ = scissor; } pub fn setViewport(interface: *Interface, first: u32, viewports: []const vk.Viewport) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = first; _ = viewports; } pub fn setBlendConstants(interface: *Interface, constants: [4]f32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = constants; } pub fn setDepthBias(interface: *Interface, constant_factor: f32, clamp: f32, slope_factor: f32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = constant_factor; _ = clamp; _ = slope_factor; } pub fn setDepthBounds(interface: *Interface, min: f32, max: f32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = min; _ = max; } pub fn setLineWidth(interface: *Interface, width: f32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = width; } pub fn setStencilCompareMask(interface: *Interface, face_mask: vk.StencilFaceFlags, compare_mask: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = face_mask; _ = compare_mask; } pub fn setStencilReference(interface: *Interface, face_mask: vk.StencilFaceFlags, reference: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = face_mask; _ = reference; } pub fn setStencilWriteMask(interface: *Interface, face_mask: vk.StencilFaceFlags, write_mask: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = face_mask; _ = write_mask; } pub fn waitEvent(interface: *Interface, event: *base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = event; _ = src_stage; _ = dst_stage; @@ -414,7 +509,8 @@ pub fn waitEvent(interface: *Interface, event: *base.Event, src_stage: vk.Pipeli } pub fn writeTimestamp(interface: *Interface, stage: vk.PipelineStageFlags, pool: *base.QueryPool, query: u32) VkError!void { - _ = interface; + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.cmd_count += 1; _ = stage; try pool.writeTimestamp(query, 0); } diff --git a/src/phi/PhiDevice.zig b/src/phi/PhiDevice.zig index 0b4c160..279c250 100644 --- a/src/phi/PhiDevice.zig +++ b/src/phi/PhiDevice.zig @@ -79,9 +79,12 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a }; const phi_physical_device: *PhiPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device)); - try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num); - const transport = try PhiTransport.init(instance, phi_physical_device.scif_node_id); + const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: { + // If first connect failed try to upload the daemon to the card + try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num); + break :blk try PhiTransport.init(instance, phi_physical_device.scif_node_id); + }; self.* = .{ .interface = interface, diff --git a/src/phi/PhiDeviceMemory.zig b/src/phi/PhiDeviceMemory.zig index e40a36c..de54f96 100644 --- a/src/phi/PhiDeviceMemory.zig +++ b/src/phi/PhiDeviceMemory.zig @@ -47,7 +47,7 @@ pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceS }; var reply: proto.PhiAllocMemoryReply = undefined; - try device.transport.request(proto.PHI_COMMAND_ALLOC_MEMORY, std.mem.asBytes(&alloc_request), std.mem.asBytes(&reply)); + 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) { return PhiTransport.statusToErr(reply.result.status); @@ -84,7 +84,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { .remote_handle = self.remote_handle, }; var reply: proto.PhiFreeMemoryReply = undefined; - device.transport.request(proto.PHI_COMMAND_FREE_MEMORY, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)) catch |err| { + device.transport.request(proto.PHI_PACKET_FREE_MEMORY, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)) catch |err| { std.log.scoped(.PhiTransport).err("Remote free failed: {s}", .{@errorName(err)}); return; }; diff --git a/src/phi/PhiQueue.zig b/src/phi/PhiQueue.zig index 163cd53..01b504d 100644 --- a/src/phi/PhiQueue.zig +++ b/src/phi/PhiQueue.zig @@ -1,8 +1,12 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const lib = @import("lib.zig"); +const proto = lib.proto; const PhiCommandBuffer = @import("PhiCommandBuffer.zig"); +const PhiDevice = @import("PhiDevice.zig"); +const PhiTransport = @import("PhiTransport.zig"); const VkError = base.VkError; @@ -39,15 +43,35 @@ pub fn bindSparse(interface: *Interface, info: []const vk.BindSparseInfo, fence: } pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, fence: ?*base.Fence) VkError!void { - _ = interface; + const device: *PhiDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); + for (infos) |info| { for (info.wait_semaphores.items) |semaphore| { try semaphore.wait(); } for (info.command_buffers.items) |command_buffer| { - const intel_command_buffer: *PhiCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); - _ = intel_command_buffer; + const phi_command_buffer: *PhiCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); + + const work_execution_request: proto.PhiWorkExecutionRequest = .{ + .cmd_count = phi_command_buffer.serialized_cmd_count, + .command_buffer_size = phi_command_buffer.commands.items.len, + }; + const payload_size = @sizeOf(proto.PhiWorkExecutionRequest) + phi_command_buffer.commands.items.len; + const allocator = interface.host_allocator.allocator(); + const payload = allocator.alloc(u8, payload_size) catch return VkError.OutOfHostMemory; + defer allocator.free(payload); + + @memcpy(payload[0..@sizeOf(proto.PhiWorkExecutionRequest)], std.mem.asBytes(&work_execution_request)); + @memcpy(payload[@sizeOf(proto.PhiWorkExecutionRequest)..], phi_command_buffer.commands.items); + + // Synchronous queues for now + var reply: proto.PhiWorkExecutionReply = undefined; + try device.transport.request(proto.PHI_PACKET_WORK_EXECUTION, payload, std.mem.asBytes(&reply)); + + if (reply.result.status != proto.PHI_STATUS_OK) { + return PhiTransport.statusToErr(reply.result.status); + } } for (info.signal_semaphores.items) |semaphore| { diff --git a/src/phi/PhiTransport.zig b/src/phi/PhiTransport.zig index 57c825c..fdcdd27 100644 --- a/src/phi/PhiTransport.zig +++ b/src/phi/PhiTransport.zig @@ -39,12 +39,15 @@ pub fn init(instance: *base.Instance, node_id: u16) VkError!Self { .instance = instance, }; try self.handshake(); + + std.log.scoped(.PhiTransport).info("Successfully connected", .{}); return self; } pub fn deinit(self: *Self) void { _ = scif.close(self.epd); scif.unload(); + std.log.scoped(.PhiTransport).info("Closed connection", .{}); } pub fn request(self: *Self, command: c_uint, payload: []const u8, reply_payload: []u8) VkError!void { @@ -117,7 +120,7 @@ fn handshake(self: *Self) VkError!void { .reserved = 0, }; var reply: proto.PhiHelloReply = undefined; - try self.request(proto.PHI_COMMAND_HELLO, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)); + try self.request(proto.PHI_PACKET_HELLO, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)); if (reply.result.status != proto.PHI_STATUS_OK) { return statusToErr(reply.result.status); } diff --git a/src/phi/mic/Buffer.c b/src/phi/mic/Buffer.c new file mode 100644 index 0000000..439c71e --- /dev/null +++ b/src/phi/mic/Buffer.c @@ -0,0 +1,66 @@ +#include + +#include + +int PhiIsBufferCommand(const PhiCmdHeader* header) +{ + switch((PhiCmdType)header->type) + { + case PHI_CMD_COPY_BUFFER: + case PHI_CMD_FILL_BUFFER: + return 1; + + default: + return 0; + } +} + +static PhiStatus CopyBuffer(PhiCommandReader* reader) +{ + PhiCmdCopyBuffer command; + PhiStatus status = PhiReadCommandData(reader, &command, sizeof(command)); + if(status != PHI_STATUS_OK) + return status; + + if(command.src_memory == 0 || command.dst_memory == 0) + return PHI_STATUS_INVALID_HANDLE; + + void* dst = (void*)((uintptr_t)command.dst_memory + (uintptr_t)command.dst_offset); + const void* src = (const void*)((uintptr_t)command.src_memory + (uintptr_t)command.src_offset); + + memcpy(dst, src, (size_t)command.size); + + return PHI_STATUS_OK; +} + +static PhiStatus FillBuffer(PhiCommandReader* reader) +{ + PhiCmdFillBuffer command; + PhiStatus status = PhiReadCommandData(reader, &command, sizeof(command)); + if(status != PHI_STATUS_OK) + return status; + + if(command.memory == 0) + return PHI_STATUS_INVALID_HANDLE; + + uint32_t* dst = (uint32_t*)((uintptr_t)command.memory + (uintptr_t)command.offset); + + for(; command.size >= 4; command.size -= 4, dst++) + *dst = command.data; + + return PHI_STATUS_OK; +} + +PhiStatus PhiExecuteBufferCommand(PhiCommandReader* reader, const PhiCmdHeader* header) +{ + switch((PhiCmdType)header->type) + { + case PHI_CMD_COPY_BUFFER: + return CopyBuffer(reader); + case PHI_CMD_FILL_BUFFER: + return FillBuffer(reader); + + default: + return PHI_STATUS_BAD_MESSAGE; + } +} diff --git a/src/phi/mic/Buffer.h b/src/phi/mic/Buffer.h new file mode 100644 index 0000000..90a2a58 --- /dev/null +++ b/src/phi/mic/Buffer.h @@ -0,0 +1,9 @@ +#ifndef APE_PHI_BUFFER_H +#define APE_PHI_BUFFER_H + +#include + +int PhiIsBufferCommand(const PhiCmdHeader* header); +PhiStatus PhiExecuteBufferCommand(PhiCommandReader* reader, const PhiCmdHeader* header); + +#endif diff --git a/src/phi/mic/CommandBuffer.c b/src/phi/mic/CommandBuffer.c new file mode 100644 index 0000000..2e36332 --- /dev/null +++ b/src/phi/mic/CommandBuffer.c @@ -0,0 +1,96 @@ +#include + +#include + +PhiStatus PhiReadCommandData(PhiCommandReader* reader, void* data, uint64_t size) +{ + if(reader->remaining < size) + return PHI_STATUS_BAD_MESSAGE; + + if(ReadAll(reader->endpoint, data, (size_t)size) < 0) + return PHI_STATUS_BAD_MESSAGE; + + reader->remaining -= size; + return PHI_STATUS_OK; +} + +int PhiDrainCommandReader(PhiCommandReader* reader) +{ + if(reader->remaining == 0) + return 0; + + int result = DrainPayload(reader->endpoint, reader->remaining); + reader->remaining = 0; + return result; +} + +static PhiStatus ReadCommandHeader(PhiCommandReader* reader, PhiCmdHeader* command_header) +{ + PhiStatus status = PhiReadCommandData(reader, command_header, sizeof(*command_header)); + if(status != PHI_STATUS_OK) + return status; + + if(command_header->magic != PHI_COMMAND_MAGIC) + return PHI_STATUS_BAD_MESSAGE; + + return PHI_STATUS_OK; +} + +static PhiStatus ExecuteCommand(PhiCommandReader* reader, const PhiCmdHeader* command_header) +{ + if(PhiIsBufferCommand(command_header)) + return PhiExecuteBufferCommand(reader, command_header); + + return PHI_STATUS_BAD_MESSAGE; +} + +int HandleWorkExecution(scif_epd_t endpoint, const PhiMessageHeader* header) +{ + PhiWorkExecutionRequest request; + PhiWorkExecutionReply reply = { + .result = { + .status = PHI_STATUS_OK, + .reserved = 0, + }, + }; + + if(header->payload_size < sizeof(request)) + { + if(DrainPayload(endpoint, header->payload_size) < 0) + return -1; + reply.result.status = PHI_STATUS_BAD_MESSAGE; + return SendReply(endpoint, header, &reply, sizeof(reply)); + } + if(ReadAll(endpoint, &request, sizeof(request)) < 0) + return -1; + + PhiCommandReader reader = { + .endpoint = endpoint, + .remaining = header->payload_size - sizeof(request), + }; + + if(reader.remaining != request.command_buffer_size) + { + if(PhiDrainCommandReader(&reader) < 0) + return -1; + reply.result.status = PHI_STATUS_BAD_MESSAGE; + return SendReply(endpoint, header, &reply, sizeof(reply)); + } + + for(uint64_t cmd_index = 0; cmd_index < request.cmd_count; ++cmd_index) + { + PhiCmdHeader cmd_header; + reply.result.status = ReadCommandHeader(&reader, &cmd_header); + if(reply.result.status != PHI_STATUS_OK) + break; + + reply.result.status = ExecuteCommand(&reader, &cmd_header); + if(reply.result.status != PHI_STATUS_OK) + break; + } + + if(reader.remaining > 0 && PhiDrainCommandReader(&reader) < 0) + return -1; + + return SendReply(endpoint, header, &reply, sizeof(reply)); +} diff --git a/src/phi/mic/CommandBuffer.h b/src/phi/mic/CommandBuffer.h new file mode 100644 index 0000000..f5d1320 --- /dev/null +++ b/src/phi/mic/CommandBuffer.h @@ -0,0 +1,16 @@ +#ifndef APE_PHI_COMMAND_BUFFER_H +#define APE_PHI_COMMAND_BUFFER_H + +#include + +typedef struct PhiCommandReader +{ + scif_epd_t endpoint; + uint64_t remaining; +} PhiCommandReader; + +int HandleWorkExecution(scif_epd_t endpoint, const PhiMessageHeader* header); +int PhiDrainCommandReader(PhiCommandReader* reader); +PhiStatus PhiReadCommandData(PhiCommandReader* reader, void* data, uint64_t size); + +#endif diff --git a/src/phi/mic/Daemon.c b/src/phi/mic/Daemon.c index c8ca1eb..58c740c 100644 --- a/src/phi/mic/Daemon.c +++ b/src/phi/mic/Daemon.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -83,24 +84,29 @@ int HandlePacket(scif_epd_t endpoint) continue; } - switch((PhiCommandType)header.type) + switch((PhiPacketType)header.type) { - case PHI_COMMAND_HELLO: + case PHI_PACKET_HELLO: if(HandleHello(endpoint, &header) < 0) return -1; break; - case PHI_COMMAND_ALLOC_MEMORY: + case PHI_PACKET_ALLOC_MEMORY: if(HandleAllocMemory(endpoint, &header) < 0) return -1; break; - case PHI_COMMAND_FREE_MEMORY: + case PHI_PACKET_FREE_MEMORY: if(HandleFreeMemory(endpoint, &header) < 0) return -1; break; - case PHI_COMMAND_SHUTDOWN: + case PHI_PACKET_WORK_EXECUTION: + if(HandleWorkExecution(endpoint, &header) < 0) + return -1; + break; + + case PHI_PACKET_SHUTDOWN: if(DrainPayload(endpoint, header.payload_size) < 0) return -1; if(SendStatus(endpoint, &header, PHI_STATUS_OK) < 0) @@ -110,7 +116,7 @@ int HandlePacket(scif_epd_t endpoint) default: if(DrainPayload(endpoint, header.payload_size) < 0) return -1; - if(SendStatus(endpoint, &header, PHI_STATUS_UNSUPPORTED_COMMAND) < 0) + if(SendStatus(endpoint, &header, PHI_STATUS_UNSUPPORTED_PACKET) < 0) return -1; break; } diff --git a/src/phi/shared/Commands.h b/src/phi/shared/Commands.h new file mode 100644 index 0000000..8e12435 --- /dev/null +++ b/src/phi/shared/Commands.h @@ -0,0 +1,39 @@ +#ifndef APE_PHI_COMMANDS_H +#define APE_PHI_COMMANDS_H + +#include + +#define PHI_COMMAND_MAGIC 0x4253BF92u + +typedef enum PhiCmdType +{ + PHI_CMD_COPY_BUFFER = 0, + PHI_CMD_FILL_BUFFER = 1, +} PhiCmdType; + +typedef struct PhiCmdHeader +{ + uint32_t magic; + uint16_t type; +} PhiCmdHeader; + +typedef struct PhiCmdCopyBuffer +{ + uintptr_t src_memory; + uint64_t src_offset; + + uintptr_t dst_memory; + uint64_t dst_offset; + + uint64_t size; +} PhiCmdCopyBuffer; + +typedef struct PhiCmdFillBuffer +{ + uintptr_t memory; + uint64_t offset; + uint64_t size; + uint32_t data; +} PhiCmdFillBuffer; + +#endif diff --git a/src/phi/shared/Protocol.h b/src/phi/shared/Protocol.h index 70dfa7f..b3e0cbe 100644 --- a/src/phi/shared/Protocol.h +++ b/src/phi/shared/Protocol.h @@ -1,30 +1,30 @@ #ifndef APE_PHI_PROTOCOL_H #define APE_PHI_PROTOCOL_H +#include "Commands.h" #include #define PHI_PROTOCOL_MAGIC 0x50484941u #define PHI_PROTOCOL_VERSION 1u -#define PHI_RPOTOCOL_VERSION PHI_PROTOCOL_VERSION #define PHI_SCIF_PORT 43616u -typedef enum PhiCommandType +typedef enum PhiPacketType { - PHI_COMMAND_HELLO = 1, - PHI_COMMAND_ALLOC_MEMORY = 2, - PHI_COMMAND_FREE_MEMORY = 3, - PHI_COMMAND_UPLOAD = 4, - PHI_COMMAND_DOWNLOAD = 5, - PHI_COMMAND_SUBMIT = 6, - PHI_COMMAND_SHUTDOWN = 7, -} PhiCommandType; + PHI_PACKET_HELLO = 1, + PHI_PACKET_ALLOC_MEMORY = 2, + PHI_PACKET_FREE_MEMORY = 3, + PHI_PACKET_UPLOAD = 4, + PHI_PACKET_DOWNLOAD = 5, + PHI_PACKET_WORK_EXECUTION = 6, + PHI_PACKET_SHUTDOWN = 7, +} PhiPacketType; typedef enum PhiStatus { PHI_STATUS_OK = 0, PHI_STATUS_BAD_MESSAGE = 1, PHI_STATUS_UNSUPPORTED_VERSION = 2, - PHI_STATUS_UNSUPPORTED_COMMAND = 3, + PHI_STATUS_UNSUPPORTED_PACKET = 3, PHI_STATUS_OUT_OF_MEMORY = 4, PHI_STATUS_INVALID_HANDLE = 5, } PhiStatus; @@ -81,4 +81,15 @@ typedef struct PhiFreeMemoryReply PhiResult result; } PhiFreeMemoryReply; +typedef struct PhiWorkExecutionRequest +{ + uint64_t cmd_count; + uint64_t command_buffer_size; +} PhiWorkExecutionRequest; + +typedef struct PhiWorkExecutionReply +{ + PhiResult result; +} PhiWorkExecutionReply; + #endif