From 4efc0842c4b07c911f90f1b8c5c95b2bc3a40e62 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Mon, 9 Mar 2026 18:20:39 +0100 Subject: [PATCH] working on copy operations; ci skip --- src/soft/SoftCommandBuffer.zig | 67 +++++++++++++++++++++-- src/soft/SoftImage.zig | 83 +++++++++++++++++------------ src/soft/device/ComputeRoutines.zig | 12 ----- src/vulkan/CommandBuffer.zig | 21 +++++++- src/vulkan/lib_vulkan.zig | 30 ++++------- 5 files changed, 140 insertions(+), 73 deletions(-) diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index 1b677cd..595d95e 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -43,12 +43,14 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .bindPipeline = bindPipeline, .clearColorImage = clearColorImage, .copyBuffer = copyBuffer, + .copyBufferToImage = copyBufferToImage, .copyImage = copyImage, .copyImageToBuffer = copyImageToBuffer, .dispatch = dispatch, .dispatchIndirect = dispatchIndirect, .end = end, .fillBuffer = fillBuffer, + .pipelineBarrier = pipelineBarrier, .reset = reset, .resetEvent = resetEvent, .setEvent = setEvent, @@ -74,11 +76,12 @@ pub fn execute(self: *Self, device: *ExecutionDevice) VkError!void { for (self.commands.items) |command| { try command.vtable.execute(command.ptr, device); } + try self.interface.finish(); } pub fn begin(interface: *Interface, _: *const vk.CommandBufferBeginInfo) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - self.command_allocator.deinit(); + _ = self.command_allocator.reset(.free_all); } pub fn end(interface: *Interface) VkError!void { @@ -90,8 +93,7 @@ pub fn reset(interface: *Interface, _: vk.CommandBufferResetFlags) VkError!void const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); self.commands.clearAndFree(allocator); - if (!self.command_allocator.reset(.{ .retain_with_limit = 16_384 })) - return VkError.OutOfHostMemory; + _ = self.command_allocator.reset(.free_all); } // Commands ==================================================================================================== @@ -206,6 +208,36 @@ pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, r self.commands.append(allocator, Command.from(cmd)) catch return VkError.OutOfHostMemory; } +pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + src: *const SoftBuffer, + dst: *SoftImage, + dst_layout: vk.ImageLayout, + regions: []const vk.BufferImageCopy, + + pub fn execute(impl: *const Impl, _: *ExecutionDevice) VkError!void { + for (impl.regions[0..]) |region| { + try impl.dst.copyFromBuffer(impl.src, region); + } + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{ + .src = @alignCast(@fieldParentPtr("interface", src)), + .dst_layout = dst_layout, + .dst = @alignCast(@fieldParentPtr("interface", dst)), + .regions = allocator.dupe(vk.BufferImageCopy, regions) catch return VkError.OutOfHostMemory, // Will be freed on cmdbuf reset or destroy + }; + self.commands.append(allocator, Command.from(cmd)) catch return VkError.OutOfHostMemory; +} + 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 { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const allocator = self.command_allocator.allocator(); @@ -249,7 +281,9 @@ pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk regions: []const vk.BufferImageCopy, pub fn execute(impl: *const Impl, _: *ExecutionDevice) VkError!void { - try impl.src.copyImageToBuffer(impl.src_layout, impl.dst, impl.regions); + for (impl.regions[0..]) |region| { + try impl.dst.copyToBuffer(impl.dst, region); + } } }; @@ -348,6 +382,31 @@ pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.Device self.commands.append(allocator, Command.from(cmd)) catch return VkError.OutOfHostMemory; } +pub fn pipelineBarrier(interface: *Interface, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, dependency: vk.DependencyFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const allocator = self.command_allocator.allocator(); + + const CommandImpl = struct { + const Impl = @This(); + + pub fn execute(_: *const Impl, _: *ExecutionDevice) VkError!void { + // TODO: implement synchronization for rasterizations stages + } + }; + + const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(cmd); + cmd.* = .{}; + self.commands.append(allocator, Command.from(cmd)) catch return VkError.OutOfHostMemory; + + _ = src_stage; + _ = dst_stage; + _ = dependency; + _ = memory_barriers; + _ = buffer_barriers; + _ = image_barriers; +} + pub fn resetEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void { // No-op _ = interface; diff --git a/src/soft/SoftImage.zig b/src/soft/SoftImage.zig index a2fdf26..c11929a 100644 --- a/src/soft/SoftImage.zig +++ b/src/soft/SoftImage.zig @@ -68,39 +68,52 @@ pub fn copyImage(self: *const Self, self_layout: vk.ImageLayout, dst: *Self, dst std.log.scoped(.commandExecutor).warn("FIXME: implement image to image copy", .{}); } -pub fn copyImageToBuffer(self: *const Self, self_layout: vk.ImageLayout, dst: *SoftBuffer, regions: []const vk.BufferImageCopy) VkError!void { - _ = self_layout; - for (regions) |region| { - const src_memory = if (self.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - const dst_memory = if (dst.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; - - const pixel_size: u32 = @intCast(self.interface.getPixelSize()); - const image_row_pitch: u32 = self.interface.extent.width * pixel_size; - const image_size: u32 = @intCast(self.interface.getTotalSize()); - - const buffer_row_length: u32 = if (region.buffer_row_length != 0) region.buffer_row_length else region.image_extent.width; - const buffer_row_pitch: u32 = buffer_row_length * pixel_size; - const buffer_size: u32 = buffer_row_pitch * region.image_extent.height * region.image_extent.depth; - - const src_map: []u8 = @as([*]u8, @ptrCast(try src_memory.map(0, image_size)))[0..image_size]; - const dst_map: []u8 = @as([*]u8, @ptrCast(try dst_memory.map(region.buffer_offset, buffer_size)))[0..buffer_size]; - - const row_size = region.image_extent.width * pixel_size; - for (0..self.interface.extent.depth) |z| { - for (0..self.interface.extent.height) |y| { - const z_as_u32: u32 = @intCast(z); - const y_as_u32: u32 = @intCast(y); - - const src_offset = ((@as(u32, @intCast(region.image_offset.z)) + z_as_u32) * self.interface.extent.height + @as(u32, @intCast(region.image_offset.y)) + y_as_u32) * image_row_pitch + @as(u32, @intCast(region.image_offset.x)) * pixel_size; - const dst_offset = (z_as_u32 * buffer_row_length * region.image_extent.height + y_as_u32 * buffer_row_length) * pixel_size; - - const src_slice = src_map[src_offset..(src_offset + row_size)]; - const dst_slice = dst_map[dst_offset..(dst_offset + row_size)]; - @memcpy(dst_slice, src_slice); - } - } - - src_memory.unmap(); - dst_memory.unmap(); - } +pub fn copyToBuffer(self: *const Self, dst: *SoftBuffer, region: vk.BufferImageCopy) VkError!void { + const dst_size = dst.interface.size - region.buffer_offset; + const dst_memory = if (dst.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; + const dst_map: []u8 = @as([*]u8, @ptrCast(try dst_memory.map(region.buffer_offset, dst_size)))[0..dst_size]; + try self.copy( + null, + dst_map, + @intCast(region.buffer_row_length), + @intCast(region.buffer_image_height), + region.image_subresource, + region.image_offset, + region.image_extent, + ); +} + +pub fn copyFromBuffer(self: *const Self, src: *SoftBuffer, region: vk.BufferImageCopy) VkError!void { + const src_size = src.interface.size - region.buffer_offset; + const src_memory = if (src.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; + const src_map: []u8 = @as([*]u8, @ptrCast(try src_memory.map(region.buffer_offset, src_size)))[0..src_size]; + try self.copy( + src_map, + null, + @intCast(region.buffer_row_length), + @intCast(region.buffer_image_height), + region.image_subresource, + region.image_offset, + region.image_extent, + ); +} + +pub fn copy( + self: *Self, + src_memory: ?[]const u8, + dst_memory: ?[]u8, + row_len: usize, + image_height: usize, + image_subresource: vk.ImageSubresourceLayers, + image_copy_offset: vk.Offset3D, + image_copy_extent: vk.Extent3D, +) VkError!void { + _ = self; + _ = src_memory; + _ = dst_memory; + _ = row_len; + _ = image_height; + _ = image_subresource; + _ = image_copy_offset; + _ = image_copy_extent; } diff --git a/src/soft/device/ComputeRoutines.zig b/src/soft/device/ComputeRoutines.zig index fb502a4..93c2812 100644 --- a/src/soft/device/ComputeRoutines.zig +++ b/src/soft/device/ComputeRoutines.zig @@ -64,18 +64,6 @@ pub fn dispatch(self: *Self, group_count_x: u32, group_count_y: u32, group_count .pipeline = pipeline, }, }); - //runWrapper( - // RunData{ - // .self = self, - // .batch_id = batch_id, - // .group_count = group_count, - // .group_count_x = @as(usize, @intCast(group_count_x)), - // .group_count_y = @as(usize, @intCast(group_count_y)), - // .group_count_z = @as(usize, @intCast(group_count_z)), - // .invocations_per_workgroup = invocations_per_workgroup, - // .pipeline = pipeline, - // }, - //); } self.device.workers.waitAndWork(&wg); } diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index fc7764f..e4926fb 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -37,17 +37,19 @@ vtable: *const VTable, dispatch_table: *const DispatchTable, pub const DispatchTable = struct { + begin: *const fn (*Self, *const vk.CommandBufferBeginInfo) VkError!void, bindDescriptorSets: *const fn (*Self, vk.PipelineBindPoint, u32, [lib.VULKAN_MAX_DESCRIPTOR_SETS]?*DescriptorSet, []const u32) VkError!void, bindPipeline: *const fn (*Self, vk.PipelineBindPoint, *Pipeline) VkError!void, - begin: *const fn (*Self, *const vk.CommandBufferBeginInfo) VkError!void, clearColorImage: *const fn (*Self, *Image, vk.ImageLayout, *const vk.ClearColorValue, vk.ImageSubresourceRange) VkError!void, copyBuffer: *const fn (*Self, *Buffer, *Buffer, []const vk.BufferCopy) VkError!void, + copyBufferToImage: *const fn (*Self, *Buffer, *Image, vk.ImageLayout, []const vk.BufferImageCopy) VkError!void, copyImage: *const fn (*Self, *Image, vk.ImageLayout, *Image, vk.ImageLayout, []const vk.ImageCopy) VkError!void, copyImageToBuffer: *const fn (*Self, *Image, vk.ImageLayout, *Buffer, []const vk.BufferImageCopy) VkError!void, dispatch: *const fn (*Self, u32, u32, u32) VkError!void, dispatchIndirect: *const fn (*Self, *Buffer, vk.DeviceSize) VkError!void, end: *const fn (*Self) VkError!void, fillBuffer: *const fn (*Self, *Buffer, vk.DeviceSize, vk.DeviceSize, u32) VkError!void, + pipelineBarrier: *const fn (*Self, vk.PipelineStageFlags, vk.PipelineStageFlags, vk.DependencyFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void, reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void, resetEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void, setEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void, @@ -117,6 +119,15 @@ pub inline fn submit(self: *Self) VkError!void { self.transitionState(.Pending, &.{ .Pending, .Executable }) catch return VkError.ValidationFailed; } +pub inline fn finish(self: *Self) VkError!void { + if (self.begin_info) |begin_info| { + if (!begin_info.flags.one_time_submit_bit) { + self.transitionState(.Invalid, &.{.Pending}) catch return VkError.ValidationFailed; + } + } + self.transitionState(.Executable, &.{.Pending}) catch return VkError.ValidationFailed; +} + // Commands ==================================================================================================== pub inline fn bindDescriptorSets(self: *Self, bind_point: vk.PipelineBindPoint, first_set: u32, sets: []const vk.DescriptorSet, dynamic_offsets: []const u32) VkError!void { @@ -141,6 +152,10 @@ pub inline fn copyBuffer(self: *Self, src: *Buffer, dst: *Buffer, regions: []con try self.dispatch_table.copyBuffer(self, src, dst, regions); } +pub inline fn copyBufferToImage(self: *Self, src: *Buffer, dst: *Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void { + try self.dispatch_table.copyBufferToImage(self, src, dst, dst_layout, regions); +} + pub inline fn copyImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void { try self.dispatch_table.copyImage(self, src, src_layout, dst, dst_layout, regions); } @@ -161,6 +176,10 @@ pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, si try self.dispatch_table.fillBuffer(self, buffer, offset, size, data); } +pub inline fn pipelineBarrier(self: *Self, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, dependency: vk.DependencyFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void { + try self.dispatch_table.pipelineBarrier(self, src_stage, dst_stage, dependency, memory_barriers, buffer_barriers, image_barriers); +} + pub inline fn resetEvent(self: *Self, event: *Event, stage: vk.PipelineStageFlags) VkError!void { try self.dispatch_table.resetEvent(self, event, stage); } diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 84eef16..f741199 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -1806,14 +1806,7 @@ pub export fn strollCmdCopyBufferToImage(p_cmd: vk.CommandBuffer, p_src: vk.Buff const src = NonDispatchable(Buffer).fromHandleObject(p_src) catch |err| return errorLogger(err); const dst = NonDispatchable(Image).fromHandleObject(p_dst) catch |err| return errorLogger(err); - notImplementedWarning(); - - _ = cmd; - _ = src; - _ = dst; - _ = layout; - _ = count; - _ = regions; + cmd.copyBufferToImage(src, dst, layout, regions[0..count]) catch |err| return errorLogger(err); } pub export fn strollCmdCopyImage(p_cmd: vk.CommandBuffer, p_src: vk.Image, src_layout: vk.ImageLayout, p_dst: vk.Image, dst_layout: vk.ImageLayout, count: u32, regions: [*]const vk.ImageCopy) callconv(vk.vulkan_call_conv) void { @@ -2009,19 +2002,14 @@ pub export fn strollCmdPipelineBarrier( defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = src_stage_mask; - _ = dst_stage_mask; - _ = dependency_flags; - _ = memory_barrier_count; - _ = memory_barriers; - _ = buffer_memory_barrier_count; - _ = buffer_memory_barriers; - _ = image_memory_barrier_count; - _ = image_memory_barriers; + cmd.pipelineBarrier( + src_stage_mask, + dst_stage_mask, + dependency_flags, + memory_barriers[0..memory_barrier_count], + buffer_memory_barriers[0..buffer_memory_barrier_count], + image_memory_barriers[0..image_memory_barrier_count], + ) catch |err| return errorLogger(err); } pub export fn strollCmdPushConstants(p_cmd: vk.CommandBuffer, layout: vk.PipelineLayout, flags: vk.ShaderStageFlags, offset: u32, size: u32, values: *const anyopaque) callconv(vk.vulkan_call_conv) void {