improving spirv kill support
Build / build (push) Successful in 2m17s
Test / build_and_test (push) Successful in 1m58s

This commit is contained in:
2026-06-12 23:13:58 +02:00
parent ab0bca0d82
commit a8ba6fd14f
10 changed files with 122 additions and 30 deletions
+4 -4
View File
@@ -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 = .{
+16 -4
View File
@@ -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));
+30 -8
View File
@@ -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,
+45 -9
View File
@@ -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;
+4
View File
@@ -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| {
+3
View File
@@ -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| {
@@ -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| {
+12 -2
View File
@@ -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);
+4
View File
@@ -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,
+1 -3
View File
@@ -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";