diff --git a/build.zig.zon b/build.zig.zon index 392db74..2025558 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -31,8 +31,8 @@ .lazy = true, }, .SPIRV_Interpreter = .{ - .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#45453c1b9e93dc9ca096855d6219533f31e89f0f", - .hash = "SPIRV_Interpreter-0.0.1-ajmpnydRBQBjwqmtraJk0vDJt-5npiV3atf423vS0D14", + .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#bc84a9f5530c5d9c7a981126b0c1ee6405b90bf7", + .hash = "SPIRV_Interpreter-0.0.1-ajmpnyNmBQDv76iN4hKcjzO-2vT0JLCwkKhfWLjaYmDL", .lazy = true, }, //.SPIRV_Interpreter = .{ diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index b07e239..2d7e75f 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -829,14 +829,15 @@ pub fn pushConstants(interface: *Interface, stages: vk.ShaderStageFlags, offset: pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void { const impl: *Impl = @ptrCast(@alignCast(context)); + const state = &device.pipeline_states[ + if (impl.stages.vertex_bit or impl.stages.fragment_bit) + ExecutionDevice.GRAPHICS_PIPELINE_STATE + else + ExecutionDevice.COMPUTE_PIPELINE_STATE + ]; + const size = @min(lib.PUSH_CONSTANT_SIZE - impl.offset, impl.blob.len); - // TODO: pipeline layout offset - if (impl.stages.vertex_bit or impl.stages.fragment_bit) { - @memcpy(device.pipeline_states[ExecutionDevice.GRAPHICS_PIPELINE_STATE].push_constant_blob[impl.offset..size], impl.blob[0..size]); - } - if (impl.stages.compute_bit) { - @memcpy(device.pipeline_states[ExecutionDevice.COMPUTE_PIPELINE_STATE].push_constant_blob[impl.offset..size], impl.blob[0..size]); - } + @memcpy(state.push_constant_blob[impl.offset .. impl.offset + size], impl.blob[0..size]); } }; diff --git a/src/soft/SoftDescriptorSet.zig b/src/soft/SoftDescriptorSet.zig index 0dd8462..beb7a39 100644 --- a/src/soft/SoftDescriptorSet.zig +++ b/src/soft/SoftDescriptorSet.zig @@ -7,6 +7,7 @@ const Device = base.Device; const Buffer = base.Buffer; const BufferView = base.BufferView; const ImageView = base.ImageView; +const Sampler = base.Sampler; const SoftBuffer = @import("SoftBuffer.zig"); const SoftBufferView = @import("SoftBufferView.zig"); @@ -72,12 +73,18 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base. .storage_buffer, .storage_buffer_dynamic, => @sizeOf(DescriptorBuffer), + .storage_image, .input_attachment, => @sizeOf(DescriptorImage), + .storage_texel_buffer, .uniform_texel_buffer, => @sizeOf(DescriptorTexel), + + .combined_image_sampler, + => @sizeOf(DescriptorTexture), + else => 0, }; @@ -135,7 +142,22 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, layout: *base. } break :blk desc; }, - else => {}, + + .combined_image_sampler, + => descriptor.* = blk: { + const desc: Descriptor = .{ + .texture = local_allocator.alloc(DescriptorTexture, binding.array_size) catch return VkError.OutOfHostMemory, + }; + for (desc.texture[0..]) |*d| { + d.* = .{ + .sampler = null, + .view = null, + }; + } + break :blk desc; + }, + + else => descriptor.* = .{ .unsupported = .{} }, } } @@ -153,33 +175,124 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { allocator.destroy(self); } +fn descriptorLen(descriptor: Descriptor) usize { + return switch (descriptor) { + .buffer => |buffer| buffer.len, + .image => |image| image.len, + .texel_buffer => |texel_buffer| texel_buffer.len, + .texture => |texture| texture.len, + .unsupported => 0, + }; +} + +fn advanceToAvailableDescriptor(descriptors: []const Descriptor, binding: *usize, array_element: *usize) bool { + while (binding.* < descriptors.len) { + switch (descriptors[binding.*]) { + .unsupported => return true, + else => {}, + } + + const len = descriptorLen(descriptors[binding.*]); + if (array_element.* < len) return true; + if (array_element.* > len) return false; + + binding.* += 1; + array_element.* = 0; + } + + return false; +} + +fn copyDescriptorRange(dst_desc: *Descriptor, dst_array_element: usize, src_desc: Descriptor, src_array_element: usize, descriptor_count: usize) bool { + switch (dst_desc.*) { + .buffer => |dst_buffer| { + const src_buffer = switch (src_desc) { + .buffer => |buffer| buffer, + else => return false, + }; + @memcpy( + dst_buffer[dst_array_element .. dst_array_element + descriptor_count], + src_buffer[src_array_element .. src_array_element + descriptor_count], + ); + }, + + .image => |dst_image| { + const src_image = switch (src_desc) { + .image => |image| image, + else => return false, + }; + @memcpy( + dst_image[dst_array_element .. dst_array_element + descriptor_count], + src_image[src_array_element .. src_array_element + descriptor_count], + ); + }, + + .texel_buffer => |dst_texel_buffer| { + const src_texel_buffer = switch (src_desc) { + .texel_buffer => |texel_buffer| texel_buffer, + else => return false, + }; + @memcpy( + dst_texel_buffer[dst_array_element .. dst_array_element + descriptor_count], + src_texel_buffer[src_array_element .. src_array_element + descriptor_count], + ); + }, + + .texture => |dst_texture| { + const src_texture = switch (src_desc) { + .texture => |texture| texture, + else => return false, + }; + @memcpy( + dst_texture[dst_array_element .. dst_array_element + descriptor_count], + src_texture[src_array_element .. src_array_element + descriptor_count], + ); + }, + + .unsupported => return false, + } + + return true; +} + pub fn copy(interface: *Interface, src_interface: *const Interface, data: vk.CopyDescriptorSet) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const src: *const Self = @alignCast(@fieldParentPtr("interface", src_interface)); - const dst_start = @min(@as(usize, @intCast(data.dst_binding)), self.descriptors.len); - const src_start = @min(@as(usize, @intCast(data.src_binding)), src.descriptors.len); + var dst_binding: usize = @intCast(data.dst_binding); + var src_binding: usize = @intCast(data.src_binding); + var dst_array_element: usize = @intCast(data.dst_array_element); + var src_array_element: usize = @intCast(data.src_array_element); + var descriptor_count: usize = @intCast(data.descriptor_count); - const descriptor_count: usize = @intCast(data.descriptor_count); - - const dst_remaining = self.descriptors.len - dst_start; - const src_remaining = src.descriptors.len - src_start; - - const copy_count = @min(descriptor_count, dst_remaining, src_remaining); - - const dst_slice = self.descriptors[dst_start .. dst_start + copy_count]; - const src_slice = src.descriptors[src_start .. src_start + copy_count]; - - for (dst_slice, src_slice) |*dst_desc, src_desc| { - switch (dst_desc.*) { - .buffer => |dst_buffer| @memcpy(dst_buffer[0..], src_desc.buffer[0..]), - .image => |dst_image| @memcpy(dst_image[0..], src_desc.image[0..]), - .texel_buffer => |dst_texel| @memcpy(dst_texel[0..], src_desc.texel_buffer[0..]), - else => { - dst_desc.* = .{ .unsupported = .{} }; - base.unsupported("descriptor type for copy", .{}); - }, + while (descriptor_count > 0) { + if (!advanceToAvailableDescriptor(self.descriptors, &dst_binding, &dst_array_element) or + !advanceToAvailableDescriptor(src.descriptors, &src_binding, &src_array_element)) + { + return; } + + const dst_desc = &self.descriptors[dst_binding]; + const src_desc = src.descriptors[src_binding]; + const dst_len = descriptorLen(dst_desc.*); + const src_len = descriptorLen(src_desc); + if (dst_len == 0 or src_len == 0) { + base.unsupported("descriptor type for copy", .{}); + return; + } + + const dst_remaining = dst_len - dst_array_element; + const src_remaining = src_len - src_array_element; + const copy_count = @min(descriptor_count, dst_remaining, src_remaining); + + if (!copyDescriptorRange(dst_desc, dst_array_element, src_desc, src_array_element, copy_count)) { + base.unsupported("descriptor type for copy", .{}); + return; + } + + descriptor_count -= copy_count; + dst_array_element += copy_count; + src_array_element += copy_count; } } @@ -207,6 +320,7 @@ pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!v } } }, + .storage_image, .input_attachment, => { @@ -219,6 +333,7 @@ pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!v } } }, + .storage_texel_buffer, .uniform_texel_buffer, => { @@ -231,6 +346,26 @@ pub fn write(interface: *Interface, write_data: vk.WriteDescriptorSet) VkError!v } } }, + + .combined_image_sampler, + => { + for (write_data.p_image_info, 0..write_data.descriptor_count) |image_info, i| { + const desc = &self.descriptors[write_data.dst_binding].texture[i]; + desc.* = .{ + .sampler = null, + .view = null, + }; + if (image_info.image_view != .null_handle) { + const image_view = try NonDispatchable(ImageView).fromHandleObject(image_info.image_view); + desc.view = @as(*SoftImageView, @alignCast(@fieldParentPtr("interface", image_view))); + } + if (image_info.sampler != .null_handle) { + const sampler = try NonDispatchable(Sampler).fromHandleObject(image_info.sampler); + desc.sampler = @as(*SoftSampler, @alignCast(@fieldParentPtr("interface", sampler))); + } + } + }, + else => { self.descriptors[write_data.dst_binding] = .{ .unsupported = .{} }; base.unsupported("descriptor type {s} for writting", .{@tagName(write_data.descriptor_type)}); diff --git a/src/soft/SoftPipeline.zig b/src/soft/SoftPipeline.zig index 1778e45..53df4a4 100644 --- a/src/soft/SoftPipeline.zig +++ b/src/soft/SoftPipeline.zig @@ -20,6 +20,7 @@ const SoftBufferView = @import("SoftBufferView.zig"); const SoftImage = @import("SoftImage.zig"); const SoftImageView = @import("SoftImageView.zig"); const SoftInstance = @import("SoftInstance.zig"); +const SoftSampler = @import("SoftSampler.zig"); const SoftShaderModule = @import("SoftShaderModule.zig"); const Self = @This(); @@ -100,6 +101,7 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache: .readImageInt4 = readImageInt4, .writeImageFloat4 = writeImageFloat4, .writeImageInt4 = writeImageInt4, + .sampleImageFloat4 = sampleImageFloat4, }, ) catch |err| { std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)}); @@ -184,6 +186,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache: .readImageInt4 = readImageInt4, .writeImageFloat4 = writeImageFloat4, .writeImageInt4 = writeImageInt4, + .sampleImageFloat4 = sampleImageFloat4, }, ) catch |err| { std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)}); @@ -368,3 +371,41 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, ) catch return SpvRuntimeError.Unknown; } } + +fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32) SpvRuntimeError!spv.Runtime.Vec4(f32) { + var pixel = zm.f32x4s(0.0); + + if (dim == .Buffer) { + const buffer_view: *SoftBufferView = @ptrCast(@alignCast(context)); + const buffer: *SoftBuffer = @alignCast(@fieldParentPtr("interface", buffer_view.interface.buffer)); + const map = buffer.mapAsSliceWithOffset(u8, buffer_view.interface.offset, buffer_view.interface.range) catch return SpvRuntimeError.Unknown; + _ = map; + } else { + const image_view: *SoftImageView = @ptrCast(@alignCast(context)); + const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); + + const sampler: *SoftSampler = @ptrCast(@alignCast(context2)); + _ = sampler; + + pixel = image.readFloat4( + .{ + .x = std.math.clamp(@as(i32, @intFromFloat(x * @as(f32, @floatFromInt(image.interface.extent.width)))), 0, image.interface.extent.width - 1), + .y = std.math.clamp(@as(i32, @intFromFloat(y * @as(f32, @floatFromInt(image.interface.extent.height)))), 0, image.interface.extent.height - 1), + .z = std.math.clamp(@as(i32, @intFromFloat(z * @as(f32, @floatFromInt(image.interface.extent.depth)))), 0, image.interface.extent.depth - 1), + }, + .{ + .aspect_mask = image_view.interface.subresource_range.aspect_mask, + .mip_level = image_view.interface.subresource_range.base_mip_level, + .array_layer = image_view.interface.subresource_range.base_array_layer, + }, + image_view.interface.format, + ) catch return SpvRuntimeError.Unknown; + } + + return .{ + .x = pixel[0], + .y = pixel[1], + .z = pixel[2], + .w = pixel[3], + }; +} diff --git a/src/soft/device/Device.zig b/src/soft/device/Device.zig index 06c47e1..97f6583 100644 --- a/src/soft/device/Device.zig +++ b/src/soft/device/Device.zig @@ -80,6 +80,7 @@ pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void { ); } }, + .image => |image_data_array| for (image_data_array, 0..) |image_data, descriptor_index| { if (image_data.object) |image_view| { const addr: usize = @intFromPtr(image_view); @@ -91,6 +92,7 @@ pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void { ); } }, + .texel_buffer => |texel_data_array| for (texel_data_array, 0..) |texel_data, descriptor_index| { if (texel_data.object) |buffer_view| { const addr: usize = @intFromPtr(buffer_view); @@ -102,6 +104,32 @@ pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void { ); } }, + + .texture => |texture_data_array| for (texture_data_array, 0..) |texture_data, descriptor_index| { + const SampledImage = packed struct { + image: usize, + sampler: usize, + }; + + var data: SampledImage = undefined; + + if (texture_data.view) |image_view| { + const addr: usize = @intFromPtr(image_view); + data.image = addr; + } + if (texture_data.sampler) |sampler| { + const addr: usize = @intFromPtr(sampler); + data.sampler = addr; + } + + try rt.writeDescriptorSet( + std.mem.asBytes(&data), + @as(u32, @intCast(set_index)), + @as(u32, @intCast(binding_index)), + @as(u32, @intCast(descriptor_index)), + ); + }, + else => {}, } }