From a95e57bd5e76900ac6b6bb908cca8ec4814eb6c3 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Wed, 18 Feb 2026 01:46:57 +0100 Subject: [PATCH] adding descriptor writes for storage buffers --- src/soft/SoftCommandBuffer.zig | 11 ++++++++ src/soft/SoftDescriptorSet.zig | 43 +++++++++++++++++++++++++++-- src/soft/SoftQueue.zig | 2 +- src/soft/device/ComputeRoutines.zig | 29 +++++++++++++++++++ src/soft/device/Device.zig | 22 ++++++++++++--- src/vulkan/CommandBuffer.zig | 21 ++++++++++---- src/vulkan/DescriptorSet.zig | 1 + src/vulkan/commands.zig | 2 ++ src/vulkan/lib_vulkan.zig | 8 ++---- 9 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 src/soft/device/ComputeRoutines.zig diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index ce2804a..3487a39 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -22,6 +22,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v interface.dispatch_table = &.{ .begin = begin, + .bindPipeline = bindPipeline, .clearColorImage = clearColorImage, .copyBuffer = copyBuffer, .copyImage = copyImage, @@ -64,6 +65,16 @@ pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!v // Commands ==================================================================================================== +pub fn bindPipeline(interface: *Interface, bind_point: vk.PipelineBindPoint, pipeline: *base.Pipeline) VkError!void { + _ = interface; + _ = pipeline; + + if (bind_point != .graphics and bind_point != .compute) { + std.log.warn("Software driver does not support bind point {s}", .{@tagName(bind_point)}); + return VkError.ValidationFailed; + } +} + pub fn clearColorImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, range: vk.ImageSubresourceRange) VkError!void { // No-op _ = interface; diff --git a/src/soft/SoftDescriptorSet.zig b/src/soft/SoftDescriptorSet.zig index 4fa2e8c..f82244d 100644 --- a/src/soft/SoftDescriptorSet.zig +++ b/src/soft/SoftDescriptorSet.zig @@ -4,12 +4,28 @@ const base = @import("base"); const VkError = base.VkError; const Device = base.Device; +const Buffer = base.Buffer; + +const SoftBuffer = @import("SoftBuffer.zig"); + +const NonDispatchable = base.NonDispatchable; const Self = @This(); pub const Interface = base.DescriptorSet; +const Descriptor = union(enum) { + buffer: struct { + object: ?*SoftBuffer, + offset: vk.DeviceSize, + size: vk.DeviceSize, + }, + image: struct {}, +}; + interface: Interface, +descriptors: []Descriptor, + pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base.DescriptorSetLayout) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; errdefer allocator.destroy(self); @@ -22,8 +38,12 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base. .write = write, }; + const descriptors = allocator.alloc(Descriptor, layout.bindings.len) catch return VkError.OutOfHostMemory; + errdefer allocator.free(descriptors); + self.* = .{ .interface = interface, + .descriptors = descriptors, }; return self; } @@ -36,11 +56,30 @@ pub fn copy(interface: *Interface, copy_data: vk.CopyDescriptorSet) VkError!void pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.free(self.descriptors); allocator.destroy(self); } pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - _ = self; - _ = write_data; + + switch (write_data.descriptor_type) { + .storage_buffer, .storage_buffer_dynamic => { + for (write_data.p_buffer_info, 0..write_data.descriptor_count) |buffer_info, i| { + const desc = &self.descriptors[write_data.dst_binding + i]; + desc.* = .{ + .buffer = .{ + .object = null, + .offset = buffer_info.offset, + .size = buffer_info.range, + }, + }; + if (buffer_info.buffer != .null_handle) { + const buffer = try NonDispatchable(Buffer).fromHandleObject(buffer_info.buffer); + desc.buffer.object = @as(*SoftBuffer, @alignCast(@fieldParentPtr("interface", buffer))); + } + } + }, + else => base.unsupported("descriptor type {s} for writting", .{@tagName(write_data.descriptor_type)}), + } } diff --git a/src/soft/SoftQueue.zig b/src/soft/SoftQueue.zig index 955fb96..a5f88c6 100644 --- a/src/soft/SoftQueue.zig +++ b/src/soft/SoftQueue.zig @@ -97,7 +97,7 @@ fn taskRunner(self: *Self, info: Interface.SubmitInfo, p_fence: ?*base.Fence, ru command_buffers.deinit(soft_device.device_allocator.allocator()); } - var device = Device.init(); + var device = Device.init(soft_device); defer device.deinit(); loop: for (info.command_buffers.items) |command_buffer| { diff --git a/src/soft/device/ComputeRoutines.zig b/src/soft/device/ComputeRoutines.zig new file mode 100644 index 0000000..c8e8c17 --- /dev/null +++ b/src/soft/device/ComputeRoutines.zig @@ -0,0 +1,29 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); +const spv = @import("spv"); + +const SoftDevice = @import("../SoftDevice.zig"); +const SoftPipeline = @import("../SoftPipeline.zig"); + +const VkError = base.VkError; + +const Self = @This(); + +device: *SoftDevice, +pipeline: ?*SoftPipeline, + +pub fn init(device: *SoftDevice) Self { + return .{ + .device = device, + .pipeline = null, + }; +} + +pub fn destroy(self: *Self) void { + _ = self; +} + +pub fn bindPipeline(self: *Self, pipeline: *SoftPipeline) void { + self.pipeline = pipeline; +} diff --git a/src/soft/device/Device.zig b/src/soft/device/Device.zig index 931d062..0ee2a55 100644 --- a/src/soft/device/Device.zig +++ b/src/soft/device/Device.zig @@ -2,24 +2,38 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); +const SoftDevice = @import("../SoftDevice.zig"); const SoftImage = @import("../SoftImage.zig"); +const SoftPipeline = @import("../SoftPipeline.zig"); + +const ComputeRoutines = @import("ComputeRoutines.zig"); const cmd = base.commands; const VkError = base.VkError; const Self = @This(); -pub fn init() Self { - return .{}; +compute_routine: ComputeRoutines, + +pub fn init(device: *SoftDevice) Self { + return .{ + .compute_routine = .init(device), + }; } pub fn deinit(self: *Self) void { - _ = self; + self.compute_routine.destroy(); } pub fn dispatch(self: *Self, command: *const cmd.Command) VkError!void { - _ = self; switch (command.*) { + .BindPipeline => |data| { + if (data.bind_point == .compute) { + self.compute_routine.bindPipeline(@alignCast(@fieldParentPtr("interface", data.pipeline))); + } else { + // TODO + } + }, .ClearColorImage => |data| try clearColorImage(&data), .CopyBuffer => |data| try copyBuffer(&data), .CopyImage => |data| try copyImage(&data), diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 7914a11..86cf19d 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -13,6 +13,7 @@ const Buffer = @import("Buffer.zig"); const CommandPool = @import("CommandPool.zig"); const Event = @import("Event.zig"); const Image = @import("Image.zig"); +const Pipeline = @import("Pipeline.zig"); const COMMAND_BUFFER_BASE_CAPACITY = 256; @@ -39,6 +40,7 @@ vtable: *const VTable, dispatch_table: *const DispatchTable, pub const DispatchTable = struct { + 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, @@ -133,31 +135,41 @@ fn cleanCommandList(self: *Self) void { // Commands ==================================================================================================== +pub inline fn bindPipeline(self: *Self, bind_point: vk.PipelineBindPoint, pipeline: *Pipeline) VkError!void { + const allocator = self.host_allocator.allocator(); + try self.dispatch_table.bindPipeline(self, bind_point, pipeline); + self.commands.append(allocator, .{ .BindPipeline = .{ + .bind_point = bind_point, + .pipeline = pipeline, + } }) catch return VkError.OutOfHostMemory; +} + pub inline fn clearColorImage(self: *Self, image: *Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void { const allocator = self.host_allocator.allocator(); for (ranges) |range| { + try self.dispatch_table.clearColorImage(self, image, layout, color, range); self.commands.append(allocator, .{ .ClearColorImage = .{ .image = image, .layout = layout, .clear_color = color.*, .range = range, } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.clearColorImage(self, image, layout, color, range); } } pub inline fn copyBuffer(self: *Self, src: *Buffer, dst: *Buffer, regions: []const vk.BufferCopy) VkError!void { const allocator = self.host_allocator.allocator(); + try self.dispatch_table.copyBuffer(self, src, dst, regions); self.commands.append(allocator, .{ .CopyBuffer = .{ .src = src, .dst = dst, .regions = allocator.dupe(vk.BufferCopy, regions) catch return VkError.OutOfHostMemory, } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.copyBuffer(self, src, dst, 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 { const allocator = self.host_allocator.allocator(); + try self.dispatch_table.copyImage(self, src, src_layout, dst, dst_layout, regions); self.commands.append(allocator, .{ .CopyImage = .{ .src = src, .src_layout = src_layout, @@ -165,29 +177,28 @@ pub inline fn copyImage(self: *Self, src: *Image, src_layout: vk.ImageLayout, ds .dst_layout = dst_layout, .regions = allocator.dupe(vk.ImageCopy, regions) catch return VkError.OutOfHostMemory, } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.copyImage(self, src, src_layout, dst, dst_layout, regions); } pub inline fn copyImageToBuffer(self: *Self, src: *Image, src_layout: vk.ImageLayout, dst: *Buffer, regions: []const vk.BufferImageCopy) VkError!void { const allocator = self.host_allocator.allocator(); + try self.dispatch_table.copyImageToBuffer(self, src, src_layout, dst, regions); self.commands.append(allocator, .{ .CopyImageToBuffer = .{ .src = src, .src_layout = src_layout, .dst = dst, .regions = allocator.dupe(vk.BufferImageCopy, regions) catch return VkError.OutOfHostMemory, } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.copyImageToBuffer(self, src, src_layout, dst, regions); } pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { const allocator = self.host_allocator.allocator(); + try self.dispatch_table.fillBuffer(self, buffer, offset, size, data); self.commands.append(allocator, .{ .FillBuffer = .{ .buffer = buffer, .offset = offset, .size = if (size == vk.WHOLE_SIZE) buffer.size else size, .data = data, } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.fillBuffer(self, buffer, offset, size, data); } pub inline fn resetEvent(self: *Self, event: *Event, stage: vk.PipelineStageFlags) VkError!void { diff --git a/src/vulkan/DescriptorSet.zig b/src/vulkan/DescriptorSet.zig index 4839fe2..a507d32 100644 --- a/src/vulkan/DescriptorSet.zig +++ b/src/vulkan/DescriptorSet.zig @@ -32,6 +32,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, layout: *DescriptorSe .vtable = undefined, }; } + pub inline fn copy(self: *Self, copy_data: vk.CopyDescriptorSet) VkError!void { try self.vtable.copy(self, copy_data); } diff --git a/src/vulkan/commands.zig b/src/vulkan/commands.zig index b172500..8e85f08 100644 --- a/src/vulkan/commands.zig +++ b/src/vulkan/commands.zig @@ -3,6 +3,7 @@ const vk = @import("vulkan"); const Buffer = @import("Buffer.zig"); const Image = @import("Image.zig"); +const Pipeline = @import("Pipeline.zig"); pub const CommandType = enum { BindPipeline, @@ -20,6 +21,7 @@ pub const CommandType = enum { pub const CommandBindPipeline = struct { bind_point: vk.PipelineBindPoint, + pipeline: *Pipeline, }; pub const CommandBindVertexBuffer = struct { buffers: []*const Buffer, diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 794a667..ef1644e 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -1707,12 +1707,8 @@ pub export fn strollCmdBindPipeline(p_cmd: vk.CommandBuffer, bind_point: vk.Pipe defer entryPointEndLogTrace(); const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); - - notImplementedWarning(); - - _ = cmd; - _ = bind_point; - _ = p_pipeline; + const pipeline = Dispatchable(Pipeline).fromHandleObject(p_pipeline) catch |err| return errorLogger(err); + cmd.bindPipeline(bind_point, pipeline) catch |err| return errorLogger(err); } pub export fn strollCmdBindVertexBuffers(p_cmd: vk.CommandBuffer, first: u32, count: u32, p_buffers: [*]const vk.Buffer, offsets: [*]const vk.DeviceSize) callconv(vk.vulkan_call_conv) void {