added per-output centroid flag to vertex outputs
Test / build_and_test (push) Successful in 1m32s
Build / build (push) Successful in 3m16s

This commit is contained in:
2026-07-03 00:52:48 +02:00
parent 63a39f1e72
commit 912b510c67
6 changed files with 52 additions and 14 deletions
+1
View File
@@ -73,6 +73,7 @@ pub const Vertex = struct {
point_size: f32, point_size: f32,
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct { outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct {
interpolation_type: InterpolationType, interpolation_type: InterpolationType,
centroid: bool,
blob: []u8, blob: []u8,
size: usize, size: usize,
}, },
+1
View File
@@ -187,6 +187,7 @@ fn interpolateVertexForClipping(allocator: std.mem.Allocator, a: *const Vertex,
result.outputs[location][component] = .{ result.outputs[location][component] = .{
.interpolation_type = out_a.interpolation_type, .interpolation_type = out_a.interpolation_type,
.centroid = out_a.centroid,
.blob = if (out_a.interpolation_type == .flat) .blob = if (out_a.interpolation_type == .flat)
allocator.dupe(u8, out_a.blob) catch return VkError.OutOfDeviceMemory allocator.dupe(u8, out_a.blob) catch return VkError.OutOfDeviceMemory
else else
+1 -1
View File
@@ -477,7 +477,7 @@ fn rasterizeTransformedPoint(
point_coord, point_coord,
null, null,
true, true,
try common.interpolateVertexOutputs(allocator, vertex, vertex, vertex, vertex, 1.0, 0.0, 0.0), try common.interpolateVertexOutputs(allocator, vertex, vertex, vertex, vertex, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0),
null, null,
) catch |err| { ) catch |err| {
if (err == SpvRuntimeError.Killed) if (err == SpvRuntimeError.Killed)
+10 -3
View File
@@ -262,6 +262,9 @@ pub fn interpolateVertexOutputs(
b0: f32, b0: f32,
b1: f32, b1: f32,
b2: f32, b2: f32,
centroid_b0: f32,
centroid_b1: f32,
centroid_b2: f32,
) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation { ) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation {
var inputs = [_]VertexInterpolationLocation{[_]VertexInterpolation{.{ var inputs = [_]VertexInterpolationLocation{[_]VertexInterpolation{.{
.blob = &.{}, .blob = &.{},
@@ -290,19 +293,23 @@ pub fn interpolateVertexOutputs(
const input = allocator.alloc(u8, len + @sizeOf(F32x4)) catch return VkError.OutOfDeviceMemory; const input = allocator.alloc(u8, len + @sizeOf(F32x4)) catch return VkError.OutOfDeviceMemory;
@memset(input, 0); @memset(input, 0);
const input_b0 = if (out0.centroid) centroid_b0 else b0;
const input_b1 = if (out0.centroid) centroid_b1 else b1;
const input_b2 = if (out0.centroid) centroid_b2 else b2;
var byte_index: usize = 0; var byte_index: usize = 0;
while (byte_index + @sizeOf(F32x4) <= len) : (byte_index += @sizeOf(F32x4)) { while (byte_index + @sizeOf(F32x4) <= len) : (byte_index += @sizeOf(F32x4)) {
const value0 = std.mem.bytesToValue(F32x4, out0.blob[byte_index..]); const value0 = std.mem.bytesToValue(F32x4, out0.blob[byte_index..]);
const value1 = std.mem.bytesToValue(F32x4, out1.blob[byte_index..]); const value1 = std.mem.bytesToValue(F32x4, out1.blob[byte_index..]);
const value2 = std.mem.bytesToValue(F32x4, out2.blob[byte_index..]); const value2 = std.mem.bytesToValue(F32x4, out2.blob[byte_index..]);
base.utils.writePacked(F32x4, input[byte_index..], interpolateF32x4(out0.interpolation_type, value0, value1, value2, v0, v1, v2, b0, b1, b2)); base.utils.writePacked(F32x4, input[byte_index..], interpolateF32x4(out0.interpolation_type, value0, value1, value2, v0, v1, v2, input_b0, input_b1, input_b2));
} }
while (byte_index + @sizeOf(f32) <= len) : (byte_index += @sizeOf(f32)) { while (byte_index + @sizeOf(f32) <= len) : (byte_index += @sizeOf(f32)) {
const value0 = std.mem.bytesToValue(f32, out0.blob[byte_index..]); const value0 = std.mem.bytesToValue(f32, out0.blob[byte_index..]);
const value1 = std.mem.bytesToValue(f32, out1.blob[byte_index..]); const value1 = std.mem.bytesToValue(f32, out1.blob[byte_index..]);
const value2 = std.mem.bytesToValue(f32, out2.blob[byte_index..]); const value2 = std.mem.bytesToValue(f32, out2.blob[byte_index..]);
base.utils.writePacked(f32, input[byte_index..], interpolateF32(out0.interpolation_type, value0, value1, value2, v0, v1, v2, b0, b1, b2)); base.utils.writePacked(f32, input[byte_index..], interpolateF32(out0.interpolation_type, value0, value1, value2, v0, v1, v2, input_b0, input_b1, input_b2));
} }
if (byte_index < len) if (byte_index < len)
@@ -322,7 +329,7 @@ pub fn interpolateLineOutputs(
provoking_vertex: *const Renderer.Vertex, provoking_vertex: *const Renderer.Vertex,
t: f32, t: f32,
) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation { ) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation {
return interpolateVertexOutputs(allocator, v0, v1, v0, provoking_vertex, 1.0 - t, t, 0.0); return interpolateVertexOutputs(allocator, v0, v1, v0, provoking_vertex, 1.0 - t, t, 0.0, 1.0 - t, t, 0.0);
} }
pub fn interpolateVertexOutputDerivatives( pub fn interpolateVertexOutputDerivatives(
@@ -381,7 +381,7 @@ inline fn run(data: RunData) !void {
if (early_depth.mask == 0) if (early_depth.mask == 0)
continue; continue;
const interpolation_barycentrics = if (data.sample_count > 1 and data.fragment_uses_centroid) blk: { const centroid_barycentrics = if (data.sample_count > 1 and data.fragment_uses_centroid) blk: {
const sample_pos = firstCoveredSamplePosition(data.sample_count, early_depth.mask); const sample_pos = firstCoveredSamplePosition(data.sample_count, early_depth.mask);
const centroid_p = zm.f32x4( const centroid_p = zm.f32x4(
@as(f32, @floatFromInt(x)) + sample_pos.x, @as(f32, @floatFromInt(x)) + sample_pos.x,
@@ -398,9 +398,9 @@ inline fn run(data: RunData) !void {
centroid_w2 / data.area, centroid_w2 / data.area,
}; };
} else .{ b0, b1, b2 }; } else .{ b0, b1, b2 };
const input_b0 = interpolation_barycentrics[0]; const centroid_b0 = centroid_barycentrics[0];
const input_b1 = interpolation_barycentrics[1]; const centroid_b1 = centroid_barycentrics[1];
const input_b2 = interpolation_barycentrics[2]; const centroid_b2 = centroid_barycentrics[2];
var fragment_result: fragment.InvocationResult = .{ var fragment_result: fragment.InvocationResult = .{
.outputs = std.mem.zeroes([spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(F32x4)]u8), .outputs = std.mem.zeroes([spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(F32x4)]u8),
@@ -417,7 +417,19 @@ inline fn run(data: RunData) !void {
if ((early_depth.mask & sample_coverage_mask) == 0) if ((early_depth.mask & sample_coverage_mask) == 0)
continue; continue;
const inputs = try common.interpolateVertexOutputs(data.allocator, &data.v0, &data.v1, &data.v2, &data.provoking_vertex, input_b0, input_b1, input_b2); const inputs = try common.interpolateVertexOutputs(
data.allocator,
&data.v0,
&data.v1,
&data.v2,
&data.provoking_vertex,
b0,
b1,
b2,
centroid_b0,
centroid_b1,
centroid_b2,
);
const sample_result = fragment.shaderInvocation( const sample_result = fragment.shaderInvocation(
data.allocator, data.allocator,
data.draw_call, data.draw_call,
@@ -459,7 +471,19 @@ inline fn run(data: RunData) !void {
continue; continue;
} }
if (data.has_fragment_shader) { if (data.has_fragment_shader) {
const inputs = try common.interpolateVertexOutputs(data.allocator, &data.v0, &data.v1, &data.v2, &data.provoking_vertex, input_b0, input_b1, input_b2); const inputs = try common.interpolateVertexOutputs(
data.allocator,
&data.v0,
&data.v1,
&data.v2,
&data.provoking_vertex,
b0,
b1,
b2,
centroid_b0,
centroid_b1,
centroid_b2,
);
const derivative_inputs: ?fragment.DerivativeInputs = if (data.fragment_uses_derivatives) blk: { const derivative_inputs: ?fragment.DerivativeInputs = if (data.fragment_uses_derivatives) blk: {
var derivatives: fragment.DerivativeInputs = undefined; var derivatives: fragment.DerivativeInputs = undefined;
+9 -4
View File
@@ -202,9 +202,10 @@ fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, l
const value = try rt.results[result_word].getConstValue(); const value = try rt.results[result_word].getConstValue();
const memory_size = try rt.getResultMemorySize(result_word); const memory_size = try rt.getResultMemorySize(result_word);
const interpolation_type = vertexOutputInterpolationType(data, rt, location, component, result_word); const interpolation_type = vertexOutputInterpolationType(data, rt, location, component, result_word);
const centroid = fragmentInputHasDecoration(data, location, component, .Centroid);
switch (value.*) { switch (value.*) {
.Array, .Matrix => { .Array, .Matrix => {
try readVertexOutputAggregate(data, output, value, location, component, interpolation_type); try readVertexOutputAggregate(data, output, value, location, component, interpolation_type, centroid);
return; return;
}, },
else => {}, else => {},
@@ -212,6 +213,7 @@ fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, l
output.outputs[location][component] = .{ output.outputs[location][component] = .{
.interpolation_type = interpolation_type, .interpolation_type = interpolation_type,
.centroid = centroid,
.blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory, .blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory,
.size = memory_size, .size = memory_size,
}; };
@@ -226,22 +228,23 @@ fn readVertexOutputAggregate(
location: usize, location: usize,
component: usize, component: usize,
interpolation_type: Renderer.InterpolationType, interpolation_type: Renderer.InterpolationType,
centroid: bool,
) !void { ) !void {
var target_location = location; var target_location = location;
switch (value.*) { switch (value.*) {
.Array => |array| { .Array => |array| {
for (array.values) |*element| { for (array.values) |*element| {
try readVertexOutputAggregate(data, output, element, target_location, component, interpolation_type); try readVertexOutputAggregate(data, output, element, target_location, component, interpolation_type, centroid);
target_location += vertexOutputValueLocationCount(element); target_location += vertexOutputValueLocationCount(element);
} }
}, },
.Matrix => |columns| { .Matrix => |columns| {
for (columns) |*column| { for (columns) |*column| {
try writeVertexOutputValue(data, output, column, target_location, component, interpolation_type); try writeVertexOutputValue(data, output, column, target_location, component, interpolation_type, centroid);
target_location += 1; target_location += 1;
} }
}, },
else => try writeVertexOutputValue(data, output, value, location, component, interpolation_type), else => try writeVertexOutputValue(data, output, value, location, component, interpolation_type, centroid),
} }
} }
@@ -252,6 +255,7 @@ fn writeVertexOutputValue(
location: usize, location: usize,
component: usize, component: usize,
interpolation_type: Renderer.InterpolationType, interpolation_type: Renderer.InterpolationType,
centroid: bool,
) !void { ) !void {
if (location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4) if (location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4)
return VkError.ValidationFailed; return VkError.ValidationFailed;
@@ -259,6 +263,7 @@ fn writeVertexOutputValue(
const memory_size = try value.getPlainMemorySize(); const memory_size = try value.getPlainMemorySize();
output.outputs[location][component] = .{ output.outputs[location][component] = .{
.interpolation_type = interpolation_type, .interpolation_type = interpolation_type,
.centroid = centroid,
.blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory, .blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory,
.size = memory_size, .size = memory_size,
}; };