diff --git a/build.zig.zon b/build.zig.zon index 22e411b..69ac181 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,8 +6,8 @@ .dependencies = .{ .vulkan_headers = .{ - .url = "git+https://github.com/KhronosGroup/Vulkan-Headers?ref=v1.4.330#ee3b5caaa7e372715873c7b9c390ee1c3ca5db25", - .hash = "N-V-__8AAFXYAQKsK51AAGXB9HziPDFjS_DVUq6_QHVxHrBM", + .url = "git+https://github.com/KhronosGroup/Vulkan-Headers/#01393c3df0e5285b54ee6527466513f9e614be94", + .hash = "N-V-__8AAEu6eQLGuoPmVY5dM6IQxznJGorQMHhLn5xFnn_8", }, .vulkan_zig = .{ .url = "git+https://github.com/Snektron/vulkan-zig#be16fc99f7f794cba90334978c6c5aadeda8094f", @@ -26,8 +26,8 @@ .hash = "N-V-__8AAF9uOh0I4P_99za7N822J3JwsDaqONrFVrcEQo59", }, .SPIRV_Interpreter = .{ - .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#089a33981c449220fd74287560347e72e5ce53fa", - .hash = "SPIRV_Interpreter-0.0.1-ajmpn8hBBwCp53qmU9TiIKGybBRsx-edOSeE44gnNgQR", + .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#c7320325fdf6b1e5e6371ff620ed08b926587eed", + .hash = "SPIRV_Interpreter-0.0.1-ajmpn5F_BwBQHPDX6S9rSgLls4FYjpdxGD30B17paW7L", .lazy = true, }, //.SPIRV_Interpreter = .{ diff --git a/src/soft/SoftPipeline.zig b/src/soft/SoftPipeline.zig index c362e79..86e38c9 100644 --- a/src/soft/SoftPipeline.zig +++ b/src/soft/SoftPipeline.zig @@ -104,6 +104,7 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache: .writeImageInt4 = writeImageInt4, .sampleImageFloat4 = sampleImageFloat4, .sampleImageInt4 = sampleImageInt4, + .sampleImageDref = sampleImageDref, .queryImageSize = queryImageSize, }, ) catch |err| { @@ -192,6 +193,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache: .writeImageInt4 = writeImageInt4, .sampleImageFloat4 = sampleImageFloat4, .sampleImageInt4 = sampleImageInt4, + .sampleImageDref = sampleImageDref, .queryImageSize = queryImageSize, }, ) catch |err| { @@ -382,7 +384,7 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, } } -fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) SpvRuntimeError!spv.Runtime.Vec4(f32) { +fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: spv.Runtime.ImageOffset) SpvRuntimeError!spv.Runtime.Vec4(f32) { var pixel = zm.f32x4s(0.0); if (dim == .Buffer) { @@ -395,7 +397,7 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const sampler: *SoftSampler = @ptrCast(@alignCast(context2)); - pixel = SoftSampler.sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod) catch return SpvRuntimeError.Unknown; + pixel = SoftSampler.sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod, offset) catch return SpvRuntimeError.Unknown; } return .{ @@ -406,7 +408,7 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, }; } -fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) SpvRuntimeError!spv.Runtime.Vec4(u32) { +fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: spv.Runtime.ImageOffset) SpvRuntimeError!spv.Runtime.Vec4(u32) { var pixel = @Vector(4, u32){ 0, 0, 0, 0 }; if (dim == .Buffer) { @@ -419,7 +421,7 @@ fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const sampler: *SoftSampler = @ptrCast(@alignCast(context2)); - pixel = SoftSampler.sampleImageInt4(image, image_view, sampler, dim, x, y, z, lod) catch return SpvRuntimeError.Unknown; + pixel = SoftSampler.sampleImageInt4(image, image_view, sampler, dim, x, y, z, lod, offset) catch return SpvRuntimeError.Unknown; } return .{ @@ -430,6 +432,16 @@ fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x }; } +fn sampleImageDref(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: spv.Runtime.ImageOffset) SpvRuntimeError!f32 { + if (dim == .Buffer) + return SpvRuntimeError.UnsupportedSpirV; + + const image_view: *SoftImageView = @ptrCast(@alignCast(context)); + const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); + const sampler: *SoftSampler = @ptrCast(@alignCast(context2)); + return SoftSampler.sampleImageDref(image, image_view, sampler, dim, x, y, z, dref, lod, offset) catch return SpvRuntimeError.Unknown; +} + fn queryImageSize(context: *anyopaque, dim: spv.SpvDim, arrayed: bool) SpvRuntimeError!spv.Runtime.Vec4(u32) { if (dim == .Buffer) { const buffer_view: *SoftBufferView = @ptrCast(@alignCast(context)); diff --git a/src/soft/SoftSampler.zig b/src/soft/SoftSampler.zig index d3d4a89..8aabc5f 100644 --- a/src/soft/SoftSampler.zig +++ b/src/soft/SoftSampler.zig @@ -15,6 +15,7 @@ const SoftImageView = @import("SoftImageView.zig"); const Self = @This(); pub const Interface = base.Sampler; +pub const ImageOffset = spv.Runtime.ImageOffset; const CubeCoordinate = struct { face: u32, @@ -276,6 +277,20 @@ fn swizzleInt4(color: U32x4, components: vk.ComponentMapping) U32x4 { }; } +fn compareDepth(op: vk.CompareOp, reference: f32, value: f32) bool { + return switch (op) { + .never => false, + .less => reference < value, + .equal => reference == value, + .less_or_equal => reference <= value, + .greater => reference > value, + .not_equal => reference != value, + .greater_or_equal => reference >= value, + .always => true, + else => false, + }; +} + fn readSampledFloat4( image: *SoftImage, image_view: *SoftImageView, @@ -410,7 +425,7 @@ fn readSampledInt4( ); } -pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) VkError!F32x4 { +pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) VkError!F32x4 { const mip_level = sampleMipLevel(image, image_view, sampler, lod); const extent = image.getMipLevelExtent(mip_level); const coord: CubeCoordinate = switch (image_view.interface.view_type) { @@ -454,9 +469,9 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: *const ImageSamplingContext, &context, zm.f32x4( - coord.u * scale_u, - coord.v * scale_v, - coord.w * scale_w, + coord.u * scale_u + @as(f32, @floatFromInt(offset.x)), + coord.v * scale_v + @as(f32, @floatFromInt(offset.y)), + coord.w * scale_w + @as(f32, @floatFromInt(offset.z)), 0.0, ), switch (sampler.interface.mag_filter) { @@ -468,7 +483,7 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: ); } -pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) VkError!U32x4 { +pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) VkError!U32x4 { const mip_level = sampleMipLevel(image, image_view, sampler, lod); const extent = image.getMipLevelExtent(mip_level); const coord: CubeCoordinate = switch (image_view.interface.view_type) { @@ -507,13 +522,20 @@ pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: * dim, coord, mip_level, - @intFromFloat(@floor(coord.u * scale_u)), - @intFromFloat(@floor(coord.v * scale_v)), - @intFromFloat(@floor(coord.w * scale_w)), + @as(i32, @intFromFloat(@floor(coord.u * scale_u))) + offset.x, + @as(i32, @intFromFloat(@floor(coord.v * scale_v))) + offset.y, + @as(i32, @intFromFloat(@floor(coord.w * scale_w))) + offset.z, ); return swizzleInt4(color, image_view.interface.components); } +pub fn sampleImageDref(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: ImageOffset) VkError!f32 { + const color = try sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod, offset); + if (sampler.interface.compare_enable == .false) + return color[0]; + return if (compareDepth(sampler.interface.compare_op, dref, color[0])) 1.0 else 0.0; +} + pub fn sampleFloat4( comptime Context: type, context: Context, diff --git a/src/soft/device/fragment.zig b/src/soft/device/fragment.zig index 303b7c4..91388b2 100644 --- a/src/soft/device/fragment.zig +++ b/src/soft/device/fragment.zig @@ -99,8 +99,7 @@ pub fn shaderInvocation( SpvRuntimeError.OutOfBounds => {}, SpvRuntimeError.Killed => { try rt.flushDescriptorSets(allocator); - freeOwnedInputs(allocator, fragment_inputs); - return undefined; // FIXME + return SpvRuntimeError.Killed; }, else => return err, }; @@ -154,13 +153,32 @@ fn readFragmentOutput( component: usize, result_word: spv.SpvWord, ) SpvRuntimeError!void { - const memory_size = try rt.getResultMemorySize(result_word); - const offset = component * @sizeOf(f32); - const location_size = @sizeOf(zm.F32x4); - const direct_capacity = location_size - offset; + const value = try rt.results[result_word].getConstValue(); + switch (value.*) { + .Array => |array| { + for (array.values, 0..) |element, element_index| { + const target_location = location + element_index; + if (target_location >= outputs.len) + return SpvRuntimeError.OutOfBounds; - if (memory_size <= direct_capacity) { - try rt.readOutput(outputs[location][offset .. offset + memory_size], result_word); + const memory_size = try element.getPlainMemorySize(); + const output = allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return SpvRuntimeError.OutOfMemory; + defer allocator.free(output); + @memset(output, 0); + + _ = try element.read(output); + try copyFragmentOutputBytes(outputs, output[0..memory_size], target_location, component); + } + return; + }, + else => {}, + } + + const memory_size = try rt.getResultMemorySize(result_word); + if (memory_size <= INTERFACE_BLOB_PADDING) { + var output = std.mem.zeroes([INTERFACE_BLOB_PADDING]u8); + try rt.readOutput(output[0..memory_size], result_word); + try copyFragmentOutputBytes(outputs, output[0..memory_size], location, component); return; } @@ -168,7 +186,25 @@ fn readFragmentOutput( defer allocator.free(output); @memset(output, 0); - try rt.readOutput(output, result_word); + try rt.readOutput(output[0..memory_size], result_word); + try copyFragmentOutputBytes(outputs, output[0..memory_size], location, component); +} + +fn copyFragmentOutputBytes( + outputs: *[spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(zm.F32x4)]u8, + output: []const u8, + location: usize, + component: usize, +) SpvRuntimeError!void { + const memory_size = output.len; + const offset = component * @sizeOf(f32); + const location_size = @sizeOf(zm.F32x4); + const direct_capacity = location_size - offset; + + if (memory_size <= direct_capacity) { + @memcpy(outputs[location][offset .. offset + memory_size], output); + return; + } var source_offset: usize = 0; var target_location = location; diff --git a/src/soft/device/rasterizer.zig b/src/soft/device/rasterizer.zig index b3b6679..ba96295 100644 --- a/src/soft/device/rasterizer.zig +++ b/src/soft/device/rasterizer.zig @@ -17,6 +17,7 @@ const DrawCall = Renderer.DrawCall; const SoftImage = @import("../SoftImage.zig"); const VkError = base.VkError; +const SpvRuntimeError = spv.Runtime.RuntimeError; pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocator, draw_call: *DrawCall) VkError!void { const io = draw_call.renderer.device.interface.io(); @@ -315,6 +316,9 @@ fn clipTransformAndRasterizePoint( try common.interpolateVertexOutputs(allocator, &transformed, &transformed, &transformed, 1.0, 0.0, 0.0), null, ) catch |err| { + if (err == SpvRuntimeError.Killed) + continue; + std.log.scoped(.@"Fragment stage").err("catched a '{s}'", .{@errorName(err)}); if (comptime base.config.logs == .verbose) { if (@errorReturnTrace()) |trace| { diff --git a/src/soft/device/rasterizer/bresenham.zig b/src/soft/device/rasterizer/bresenham.zig index 9e5be77..c46df15 100644 --- a/src/soft/device/rasterizer/bresenham.zig +++ b/src/soft/device/rasterizer/bresenham.zig @@ -163,6 +163,9 @@ inline fn run(data: RunData) !void { try common.interpolateLineOutputs(data.allocator, data.start_vertex, data.end_vertex, t), null, ) catch |err| { + if (err == SpvRuntimeError.Killed) + continue; + std.log.scoped(.@"Fragment stage").err("catched a '{s}'", .{@errorName(err)}); if (comptime base.config.logs == .verbose) { if (@errorReturnTrace()) |trace| { diff --git a/src/soft/device/rasterizer/edge_function.zig b/src/soft/device/rasterizer/edge_function.zig index b7f2d10..0c8f3c0 100644 --- a/src/soft/device/rasterizer/edge_function.zig +++ b/src/soft/device/rasterizer/edge_function.zig @@ -223,6 +223,9 @@ inline fn run(data: RunData) !void { inputs, derivative_inputs, ) catch |err| { + if (err == SpvRuntimeError.Killed) + continue; + std.log.scoped(.@"Fragment stage").err("catched a '{s}'", .{@errorName(err)}); if (comptime base.config.logs == .verbose) { if (@errorReturnTrace()) |trace| { diff --git a/src/soft/device/vertex_dispatcher.zig b/src/soft/device/vertex_dispatcher.zig index 76ed575..fa5b6e2 100644 --- a/src/soft/device/vertex_dispatcher.zig +++ b/src/soft/device/vertex_dispatcher.zig @@ -107,9 +107,16 @@ inline fn run(data: RunData) !void { SpvRuntimeError.NotFound => continue, else => return err, }; + const memory_size = try rt.getResultMemorySize(result_word); + + const result_is_integer = blk: { + const result_type = rt.getResultPrimitiveType(result_word) catch break :blk false; + break :blk result_type == .SInt or result_type == .UInt; + }; + output.outputs[location][component] = .{ - .interpolation_type = if (rt.hasResultDecoration(result_word, .Flat) or rt.resultIsInteger(result_word)) .flat else .smooth, // TODO : handle noperspective + .interpolation_type = if (rt.hasResultDecoration(result_word, .Flat) or result_is_integer) .flat else .smooth, // TODO : handle noperspective .blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory, .size = memory_size, }; @@ -181,7 +188,10 @@ fn writeVertexInput(rt: *spv.Runtime, allocator: std.mem.Allocator, raw_input: [ return; } - const input_memory_size = try rt.getInputLocationMemorySize(location); + const input_memory_size = rt.getInputLocationMemorySize(location) catch |err| switch (err) { + SpvRuntimeError.NotFound => return, + else => return err, + }; if (expanded_slice.len >= input_memory_size) { try rt.writeInputLocation(expanded_slice[0..input_memory_size], location); diff --git a/src/vulkan/Sampler.zig b/src/vulkan/Sampler.zig index a83e633..b57ab68 100644 --- a/src/vulkan/Sampler.zig +++ b/src/vulkan/Sampler.zig @@ -18,6 +18,8 @@ address_mode_u: vk.SamplerAddressMode, address_mode_v: vk.SamplerAddressMode, address_mode_w: vk.SamplerAddressMode, mip_lod_bias: f32, +compare_enable: vk.Bool32, +compare_op: vk.CompareOp, min_lod: f32, max_lod: f32, border_color: vk.BorderColor, @@ -40,6 +42,8 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Sampl .address_mode_v = info.address_mode_v, .address_mode_w = info.address_mode_w, .mip_lod_bias = info.mip_lod_bias, + .compare_enable = info.compare_enable, + .compare_op = info.compare_op, .min_lod = info.min_lod, .max_lod = info.max_lod, .border_color = info.border_color, diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index bd6e510..f7ce269 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -52,9 +52,7 @@ pub const ShaderModule = @import("ShaderModule.zig"); pub const SurfaceKHR = @import("wsi/SurfaceKHR.zig"); pub const SwapchainKHR = @import("wsi/SwapchainKHR.zig"); -// To be commented out when spec 1.4.354 is released -// pub const VULKAN_VENDOR_ID: i32 = @intFromEnum(vk.VendorId.ape); -pub const VULKAN_VENDOR_ID: i32 = 0x10008; +pub const VULKAN_VENDOR_ID: i32 = @intFromEnum(vk.VendorId.ape); /// Default driver name pub const DRIVER_NAME = "Unnamed Ape Driver";