diff --git a/build.zig.zon b/build.zig.zon index aef768a..55c69a1 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -59,8 +59,9 @@ .lazy = true, }, .SPIRV_Interpreter = .{ - .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#ad013d23fcf287d7354a05251ad0140f5fb883f7", - .hash = "SPIRV_Interpreter-0.0.1-ajmpnwSPAwD5VW4PJc1fUX0Q7niFovZyIHfhM7jZ2kkB", + //.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#1a48af468d345d8786cbb9b7d9f308f8832cbcd0", + //.hash = "SPIRV_Interpreter-0.0.1-ajmpn8CQAwD6-6jsLx5nODWFc4lAUvVTuZVVHop1X3-m", + .path = "../SPIRV-Interpreter", }, }, diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index b62e006..7cc7f4e 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -71,18 +71,24 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { allocator.destroy(self); } -pub fn execute(self: *Self, device: *ExecutionDevice) VkError!void { +pub fn execute(self: *Self, device: *ExecutionDevice) void { self.interface.submit() catch return; defer self.interface.finish() catch {}; for (self.commands.items) |command| { - try command.vtable.execute(command.ptr, device); + command.vtable.execute(command.ptr, device) catch |err| { + base.errors.errorLoggerContext(err, "the software execution device"); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return; // Should we return or continue ? Maybe device lost ? + }; } } pub fn begin(interface: *Interface, _: *const vk.CommandBufferBeginInfo) VkError!void { - const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); - _ = self.command_allocator.reset(.free_all); + // No-op + _ = interface; } pub fn end(interface: *Interface) VkError!void { diff --git a/src/soft/SoftDescriptorSet.zig b/src/soft/SoftDescriptorSet.zig index c4f7069..4fb2106 100644 --- a/src/soft/SoftDescriptorSet.zig +++ b/src/soft/SoftDescriptorSet.zig @@ -13,17 +13,22 @@ const NonDispatchable = base.NonDispatchable; const Self = @This(); pub const Interface = base.DescriptorSet; +const DescriptorBuffer = struct { + object: ?*SoftBuffer, + offset: vk.DeviceSize, + size: vk.DeviceSize, +}; + const Descriptor = union(enum) { - buffer: struct { - object: ?*SoftBuffer, - offset: vk.DeviceSize, - size: vk.DeviceSize, - }, + buffer: []DescriptorBuffer, image: struct {}, }; interface: Interface, +/// Memory containing actual binding descriptors and their array +heap: []u8, + descriptors: []Descriptor, pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base.DescriptorSetLayout) VkError!*Self { @@ -38,11 +43,38 @@ 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); + const heap_size = blk: { + var size: usize = layout.bindings.len * @sizeOf(Descriptor); + for (layout.bindings) |binding| { + const struct_size: usize = switch (binding.descriptor_type) { + .storage_buffer, .storage_buffer_dynamic => @sizeOf(DescriptorBuffer), + else => 0, + }; + + size += binding.array_size * struct_size; + } + break :blk size; + }; + + const heap = allocator.alloc(u8, heap_size) catch return VkError.OutOfHostMemory; + errdefer allocator.free(heap); + + var local_heap = std.heap.FixedBufferAllocator.init(heap); + const local_allocator = local_heap.allocator(); + + const descriptors = local_allocator.alloc(Descriptor, layout.bindings.len) catch return VkError.OutOfHostMemory; + for (descriptors, layout.bindings) |*descriptor, binding| { + switch (binding.descriptor_type) { + .storage_buffer, .storage_buffer_dynamic => descriptor.* = .{ + .buffer = local_allocator.alloc(DescriptorBuffer, binding.array_size) catch return VkError.OutOfHostMemory, + }, + else => {}, + } + } self.* = .{ .interface = interface, + .heap = heap, .descriptors = descriptors, }; return self; @@ -56,7 +88,7 @@ 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.free(self.heap); allocator.destroy(self); } @@ -66,19 +98,17 @@ pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!v 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]; + const desc = &self.descriptors[write_data.dst_binding].buffer[i]; desc.* = .{ - .buffer = .{ - .object = null, - .offset = buffer_info.offset, - .size = buffer_info.range, - }, + .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))); - if (desc.buffer.size == vk.WHOLE_SIZE) { - desc.buffer.size = if (buffer.memory) |memory| memory.size - desc.buffer.offset else return VkError.InvalidDeviceMemoryDrv; + desc.object = @as(*SoftBuffer, @alignCast(@fieldParentPtr("interface", buffer))); + if (desc.size == vk.WHOLE_SIZE) { + desc.size = if (buffer.memory) |memory| memory.size - desc.offset else return VkError.InvalidDeviceMemoryDrv; } } } diff --git a/src/soft/SoftQueue.zig b/src/soft/SoftQueue.zig index 07910dd..fc35f92 100644 --- a/src/soft/SoftQueue.zig +++ b/src/soft/SoftQueue.zig @@ -104,12 +104,7 @@ fn taskRunner(self: *Self, info: Interface.SubmitInfo, p_fence: ?*base.Fence, ru for (info.command_buffers.items) |command_buffer| { const soft_command_buffer: *SoftCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); - soft_command_buffer.execute(&execution_device) catch |err| { - base.errors.errorLoggerContext(err, "the software execution device"); - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - }; + soft_command_buffer.execute(&execution_device); } if (p_fence) |fence| { diff --git a/src/soft/SoftShaderModule.zig b/src/soft/SoftShaderModule.zig index 93c146a..fe97b17 100644 --- a/src/soft/SoftShaderModule.zig +++ b/src/soft/SoftShaderModule.zig @@ -35,7 +35,13 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v .use_simd_vectors_specializations = !std.process.hasEnvVarConstant(lib.NO_SHADER_SIMD_ENV_NAME), }) catch |err| switch (err) { spv.Module.ModuleError.OutOfMemory => return VkError.OutOfHostMemory, - else => return VkError.ValidationFailed, + else => { + std.log.scoped(.@"SPIR-V module").err("module creation catched a '{s}'", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return VkError.ValidationFailed; + }, }, .ref_count = std.atomic.Value(usize).init(1), }; diff --git a/src/soft/device/ComputeRoutines.zig b/src/soft/device/ComputeRoutines.zig index 93c2812..710318e 100644 --- a/src/soft/device/ComputeRoutines.zig +++ b/src/soft/device/ComputeRoutines.zig @@ -2,6 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); const spv = @import("spv"); +const lib = @import("../lib.zig"); const PipelineState = @import("PipelineState.zig"); @@ -52,18 +53,35 @@ pub fn dispatch(self: *Self, group_count_x: u32, group_count_y: u32, group_count var wg: std.Thread.WaitGroup = .{}; for (0..@min(self.batch_size, group_count)) |batch_id| { - self.device.workers.spawnWg(&wg, 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, - }, - }); + if (std.process.hasEnvVarConstant(lib.SINGLE_THREAD_COMPUTE_EXECUTION_ENV_NAME)) { + @branchHint(.cold); // Should only be reached for debugging + + 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, + }, + ); + } else { + self.device.workers.spawnWg(&wg, 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); } @@ -135,14 +153,17 @@ fn writeDescriptorSets(self: *Self, rt: *spv.Runtime) !void { bindings: for (set.?.descriptors[0..], 0..) |binding, binding_index| { switch (binding) { - .buffer => |buffer_data| if (buffer_data.object) |buffer| { - const memory = if (buffer.interface.memory) |memory| memory else continue :bindings; - const map: []u8 = @as([*]u8, @ptrCast(try memory.map(buffer_data.offset, buffer_data.size)))[0..buffer_data.size]; - try rt.writeDescriptorSet( - map, - @as(u32, @intCast(set_index)), - @as(u32, @intCast(binding_index)), - ); + .buffer => |buffer_data_array| for (buffer_data_array, 0..) |buffer_data, descriptor_index| { + if (buffer_data.object) |buffer| { + const memory = if (buffer.interface.memory) |memory| memory else continue :bindings; + const map: []u8 = @as([*]u8, @ptrCast(try memory.map(buffer_data.offset, buffer_data.size)))[0..buffer_data.size]; + try rt.writeDescriptorSet( + map, + @as(u32, @intCast(set_index)), + @as(u32, @intCast(binding_index)), + @as(u32, @intCast(descriptor_index)), + ); + } }, else => {}, } diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 47eb56d..93fb7bb 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -41,6 +41,7 @@ pub const DRIVER_VERSION = vk.makeApiVersion(0, 0, 0, 1); pub const DEVICE_ID = 0x600DCAFE; pub const NO_SHADER_SIMD_ENV_NAME = "STROLL_SOFT_NO_SIMD"; +pub const SINGLE_THREAD_COMPUTE_EXECUTION_ENV_NAME = "STROLL_SINGLE_THREAD_COMPUTE_EXECUTION"; /// Generic system memory. pub const MEMORY_TYPE_GENERIC_BIT = 0;