fixing spirv interpreter image API functions
This commit is contained in:
+2
-2
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
// Soft dependencies
|
// Soft dependencies
|
||||||
.SPIRV_Interpreter = .{
|
.SPIRV_Interpreter = .{
|
||||||
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#25ef7751c6c0610179e65c7a0d1b8eff2165acbe",
|
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#ae0914647bbc48683dd10108b5cae9acc54fe759",
|
||||||
.hash = "SPIRV_Interpreter-0.0.1-ajmpn6HuBwDtrbf_UHTbmbSCTgPBuNimCMt-l5NlU6tR",
|
.hash = "SPIRV_Interpreter-0.0.1-ajmpn9_vBwCUxGCNVFXUgZXaDv0OyNz8sqhzuyFD7hTU",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
//.SPIRV_Interpreter = .{
|
//.SPIRV_Interpreter = .{
|
||||||
|
|||||||
@@ -251,12 +251,7 @@ fn createShader(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initRuntime(
|
fn initRuntime(allocator: std.mem.Allocator, module: *SoftShaderModule, stage: *const vk.PipelineShaderStageCreateInfo, image_api: spv.Runtime.ImageAPI) VkError!spv.Runtime {
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
module: *SoftShaderModule,
|
|
||||||
stage: *const vk.PipelineShaderStageCreateInfo,
|
|
||||||
image_api: spv.Runtime.ImageAPI,
|
|
||||||
) VkError!spv.Runtime {
|
|
||||||
var runtime = spv.Runtime.init(allocator, &module.module, image_api) catch |err| {
|
var runtime = spv.Runtime.init(allocator, &module.module, image_api) catch |err| {
|
||||||
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)});
|
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)});
|
||||||
return VkError.Unknown;
|
return VkError.Unknown;
|
||||||
@@ -311,6 +306,33 @@ fn imageReadAspect(image_view: *SoftImageView, comptime int_read: bool) vk.Image
|
|||||||
return aspect;
|
return aspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sampledTexelOffset(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, sample_index: u32) VkError!usize {
|
||||||
|
const sample_count = image.interface.samples.toInt();
|
||||||
|
if (sample_index >= sample_count)
|
||||||
|
return VkError.ValidationFailed;
|
||||||
|
|
||||||
|
return try image.getTexelMemoryOffset(offset, subresource) +
|
||||||
|
@as(usize, sample_index) * image.getMipLevelSize(subresource.aspect_mask, subresource.mip_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readImageFloat4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!zm.F32x4 {
|
||||||
|
if (image.interface.samples.toInt() == 1)
|
||||||
|
return image.readFloat4(offset, subresource, format);
|
||||||
|
|
||||||
|
const texel_size = base.format.texelSize(format);
|
||||||
|
const texel_offset = try sampledTexelOffset(image, offset, subresource, sample_index);
|
||||||
|
return blitter.readFloat4(try image.mapAsSliceWithAddedOffset(u8, texel_offset, texel_size), format);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readImageInt4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!@Vector(4, u32) {
|
||||||
|
if (image.interface.samples.toInt() == 1)
|
||||||
|
return image.readInt4(offset, subresource, format);
|
||||||
|
|
||||||
|
const texel_size = base.format.texelSize(format);
|
||||||
|
const texel_offset = try sampledTexelOffset(image, offset, subresource, sample_index);
|
||||||
|
return blitter.readInt4(try image.mapAsSliceWithAddedOffset(u8, texel_offset, texel_size), format);
|
||||||
|
}
|
||||||
|
|
||||||
fn subpassDataCoord(x: i32, y: i32, z: i32) SpvRuntimeError!vk.Offset3D {
|
fn subpassDataCoord(x: i32, y: i32, z: i32) SpvRuntimeError!vk.Offset3D {
|
||||||
const coord = current_fragment_coord orelse return SpvRuntimeError.Unknown;
|
const coord = current_fragment_coord orelse return SpvRuntimeError.Unknown;
|
||||||
return .{ .x = coord.x + x, .y = coord.y + y, .z = coord.z + z };
|
return .{ .x = coord.x + x, .y = coord.y + y, .z = coord.z + z };
|
||||||
@@ -340,14 +362,18 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
|
|||||||
else => 0,
|
else => 0,
|
||||||
};
|
};
|
||||||
const aspect_mask = imageReadAspect(image_view, false);
|
const aspect_mask = imageReadAspect(image_view, false);
|
||||||
pixel = SoftSampler.swizzleFloat4(image.readFloat4(
|
const subresource = vk.ImageSubresource{
|
||||||
|
.aspect_mask = aspect_mask,
|
||||||
|
.mip_level = mip_level,
|
||||||
|
.array_layer = array_layer,
|
||||||
|
};
|
||||||
|
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
||||||
|
pixel = SoftSampler.swizzleFloat4(readImageFloat4Sample(
|
||||||
|
image,
|
||||||
image_coord,
|
image_coord,
|
||||||
.{
|
subresource,
|
||||||
.aspect_mask = aspect_mask,
|
|
||||||
.mip_level = mip_level,
|
|
||||||
.array_layer = array_layer,
|
|
||||||
},
|
|
||||||
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
||||||
|
sample_index,
|
||||||
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
@@ -382,14 +408,18 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, l
|
|||||||
else => 0,
|
else => 0,
|
||||||
};
|
};
|
||||||
const aspect_mask = imageReadAspect(image_view, true);
|
const aspect_mask = imageReadAspect(image_view, true);
|
||||||
pixel = SoftSampler.swizzleInt4(image.readInt4(
|
const subresource = vk.ImageSubresource{
|
||||||
|
.aspect_mask = aspect_mask,
|
||||||
|
.mip_level = mip_level,
|
||||||
|
.array_layer = array_layer,
|
||||||
|
};
|
||||||
|
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
||||||
|
pixel = SoftSampler.swizzleInt4(readImageInt4Sample(
|
||||||
|
image,
|
||||||
image_coord,
|
image_coord,
|
||||||
.{
|
subresource,
|
||||||
.aspect_mask = aspect_mask,
|
|
||||||
.mip_level = mip_level,
|
|
||||||
.array_layer = array_layer,
|
|
||||||
},
|
|
||||||
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
||||||
|
sample_index,
|
||||||
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
|
|||||||
@@ -383,10 +383,13 @@ fn readSampledFloat4(
|
|||||||
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
|
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
|
||||||
else
|
else
|
||||||
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColor(sampler, format);
|
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColor(sampler, format);
|
||||||
const sy = if (dim == .Cube)
|
const sy = switch (image_view.interface.view_type) {
|
||||||
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
|
.@"1d", .@"1d_array" => 0,
|
||||||
else
|
else => if (dim == .Cube)
|
||||||
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColor(sampler, format);
|
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
|
||||||
|
else
|
||||||
|
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColor(sampler, format),
|
||||||
|
};
|
||||||
|
|
||||||
const color = try image.readFloat4(
|
const color = try image.readFloat4(
|
||||||
.{
|
.{
|
||||||
@@ -458,10 +461,13 @@ fn readSampledInt4(
|
|||||||
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
|
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
|
||||||
else
|
else
|
||||||
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColorInt(sampler, format);
|
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColorInt(sampler, format);
|
||||||
const sy = if (dim == .Cube)
|
const sy = switch (image_view.interface.view_type) {
|
||||||
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
|
.@"1d", .@"1d_array" => 0,
|
||||||
else
|
else => if (dim == .Cube)
|
||||||
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColorInt(sampler, format);
|
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
|
||||||
|
else
|
||||||
|
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColorInt(sampler, format),
|
||||||
|
};
|
||||||
|
|
||||||
return image.readInt4(
|
return image.readInt4(
|
||||||
.{
|
.{
|
||||||
|
|||||||
@@ -286,6 +286,9 @@ fn setupSubgroupBuiltins(self: *Self, rt: *spv.Runtime, group_id: @Vector(3, u32
|
|||||||
local_invocation[0] = idx;
|
local_invocation[0] = idx;
|
||||||
|
|
||||||
const global_invocation_index = local_base + local_invocation;
|
const global_invocation_index = local_base + local_invocation;
|
||||||
|
const local_invocation_index_u32: u32 = @intCast(local_invocation_index);
|
||||||
|
|
||||||
|
rt.writeBuiltIn(std.mem.asBytes(&local_invocation), .LocalInvocationId) catch {};
|
||||||
|
rt.writeBuiltIn(std.mem.asBytes(&local_invocation_index_u32), .LocalInvocationIndex) catch {};
|
||||||
rt.writeBuiltIn(std.mem.asBytes(&global_invocation_index), .GlobalInvocationId) catch {};
|
rt.writeBuiltIn(std.mem.asBytes(&global_invocation_index), .GlobalInvocationId) catch {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,19 @@ fn clipTransformAndRasterizePoint(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try common.writeToTargets(fragment_result.outputs, draw_call, color_attachment_access, depth_attachment_access, stencil_attachment_access, true, @intCast(px), @intCast(py), fragment_result.depth orelse transformed.position[2], fragment_result.sample_mask);
|
try common.writeToTargets(
|
||||||
|
fragment_result.outputs,
|
||||||
|
draw_call,
|
||||||
|
color_attachment_access,
|
||||||
|
depth_attachment_access,
|
||||||
|
stencil_attachment_access,
|
||||||
|
true,
|
||||||
|
@intCast(px),
|
||||||
|
@intCast(py),
|
||||||
|
fragment_result.depth orelse transformed.position[2],
|
||||||
|
null,
|
||||||
|
fragment_result.sample_mask,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ pub fn drawLine(
|
|||||||
if (runtimes_count == 0)
|
if (runtimes_count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const step_count: usize = if (d_x == 0) 1 else @intCast(d_x);
|
const step_count: usize = @intCast(@max(d_x, 0) + 1);
|
||||||
const runs_count = @min(runtimes_count, step_count);
|
const runs_count = @min(runtimes_count, step_count);
|
||||||
const steps_per_run = @divTrunc(step_count + runs_count - 1, runs_count);
|
const steps_per_run = @divTrunc(step_count + runs_count - 1, runs_count);
|
||||||
|
|
||||||
@@ -193,6 +193,7 @@ inline fn run(data: RunData) !void {
|
|||||||
@intCast(pixel_x),
|
@intCast(pixel_x),
|
||||||
@intCast(pixel_y),
|
@intCast(pixel_y),
|
||||||
fragment_result.depth orelse z,
|
fragment_result.depth orelse z,
|
||||||
|
null,
|
||||||
fragment_result.sample_mask,
|
fragment_result.sample_mask,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,11 @@ pub fn interpolateVertexOutputs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const len = @min(out0.size, out1.size, out2.size);
|
const len = @min(out0.size, out1.size, out2.size);
|
||||||
|
if (std.mem.eql(u8, out0.blob[0..len], out1.blob[0..len]) and std.mem.eql(u8, out0.blob[0..len], out2.blob[0..len])) {
|
||||||
|
inputs[location][component] = .{ .blob = out0.blob, .size = len, .free_responsability = false };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -407,13 +412,14 @@ pub fn writeToTargets(
|
|||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
z: f32,
|
z: f32,
|
||||||
|
coverage_sample_mask: ?vk.SampleMask,
|
||||||
fragment_sample_mask: ?vk.SampleMask,
|
fragment_sample_mask: ?vk.SampleMask,
|
||||||
) VkError!void {
|
) VkError!void {
|
||||||
const io = draw_call.renderer.device.interface.io();
|
const io = draw_call.renderer.device.interface.io();
|
||||||
const pipeline_data = draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
const pipeline_data = draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
||||||
const depth_stencil_state = pipeline_data.depth_stencil;
|
const depth_stencil_state = pipeline_data.depth_stencil;
|
||||||
|
|
||||||
if (!sampleMaskEnablesAnySample(pipeline_data.multisample, fragment_sample_mask))
|
if (!sampleMaskEnablesAnySample(pipeline_data.multisample, coverage_sample_mask, fragment_sample_mask))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (x >= draw_call.framebuffer.interface.width or y >= draw_call.framebuffer.interface.height)
|
if (x >= draw_call.framebuffer.interface.width or y >= draw_call.framebuffer.interface.height)
|
||||||
@@ -426,7 +432,7 @@ pub fn writeToTargets(
|
|||||||
|
|
||||||
const sample_count = pipeline_data.multisample.rasterization_samples.toInt();
|
const sample_count = pipeline_data.multisample.rasterization_samples.toInt();
|
||||||
for (0..sample_count) |sample_index| {
|
for (0..sample_count) |sample_index| {
|
||||||
if (!sampleMaskEnablesSample(pipeline_data.multisample, fragment_sample_mask, sample_index))
|
if (!sampleMaskEnablesSample(pipeline_data.multisample, coverage_sample_mask, fragment_sample_mask, sample_index))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var stencil_state: ?vk.StencilOpState = null;
|
var stencil_state: ?vk.StencilOpState = null;
|
||||||
@@ -505,23 +511,23 @@ pub fn writeToTargets(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sampleMaskEnablesAnySample(multisample: anytype, fragment_sample_mask: ?vk.SampleMask) bool {
|
fn sampleMaskEnablesAnySample(multisample: anytype, coverage_sample_mask: ?vk.SampleMask, fragment_sample_mask: ?vk.SampleMask) bool {
|
||||||
const sample_count = multisample.rasterization_samples.toInt();
|
const sample_count = multisample.rasterization_samples.toInt();
|
||||||
if (multisample.sample_mask == null and fragment_sample_mask == null)
|
if (multisample.sample_mask == null and coverage_sample_mask == null and fragment_sample_mask == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (multisample.sample_mask) |pipeline_sample_mask| {
|
if (multisample.sample_mask) |pipeline_sample_mask| {
|
||||||
for (pipeline_sample_mask, 0..) |word, word_index| {
|
for (pipeline_sample_mask, 0..) |word, word_index| {
|
||||||
if (sampleMaskWordEnablesAnySample(sample_count, word_index, word, fragment_sample_mask))
|
if (sampleMaskWordEnablesAnySample(sample_count, word_index, word, coverage_sample_mask, fragment_sample_mask))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sampleMaskWordEnablesAnySample(sample_count, 0, std.math.maxInt(vk.SampleMask), fragment_sample_mask);
|
return sampleMaskWordEnablesAnySample(sample_count, 0, std.math.maxInt(vk.SampleMask), coverage_sample_mask, fragment_sample_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sampleMaskWordEnablesAnySample(sample_count: usize, word_index: usize, pipeline_word: vk.SampleMask, fragment_sample_mask: ?vk.SampleMask) bool {
|
fn sampleMaskWordEnablesAnySample(sample_count: usize, word_index: usize, pipeline_word: vk.SampleMask, coverage_sample_mask: ?vk.SampleMask, fragment_sample_mask: ?vk.SampleMask) bool {
|
||||||
const remaining_samples = sample_count -| (word_index * 32);
|
const remaining_samples = sample_count -| (word_index * 32);
|
||||||
const active_bits = @min(remaining_samples, 32);
|
const active_bits = @min(remaining_samples, 32);
|
||||||
if (active_bits == 0)
|
if (active_bits == 0)
|
||||||
@@ -532,11 +538,12 @@ fn sampleMaskWordEnablesAnySample(sample_count: usize, word_index: usize, pipeli
|
|||||||
else
|
else
|
||||||
(@as(vk.SampleMask, 1) << @intCast(active_bits)) - 1;
|
(@as(vk.SampleMask, 1) << @intCast(active_bits)) - 1;
|
||||||
|
|
||||||
|
const coverage_word = if (word_index == 0) coverage_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
||||||
const fragment_word = if (word_index == 0) fragment_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
const fragment_word = if (word_index == 0) fragment_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
||||||
return ((pipeline_word & fragment_word) & active_mask) != 0;
|
return ((pipeline_word & coverage_word & fragment_word) & active_mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sampleMaskEnablesSample(multisample: anytype, fragment_sample_mask: ?vk.SampleMask, sample_index: usize) bool {
|
fn sampleMaskEnablesSample(multisample: anytype, coverage_sample_mask: ?vk.SampleMask, fragment_sample_mask: ?vk.SampleMask, sample_index: usize) bool {
|
||||||
if (sample_index >= multisample.rasterization_samples.toInt())
|
if (sample_index >= multisample.rasterization_samples.toInt())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -549,6 +556,7 @@ fn sampleMaskEnablesSample(multisample: anytype, fragment_sample_mask: ?vk.Sampl
|
|||||||
else
|
else
|
||||||
std.math.maxInt(vk.SampleMask);
|
std.math.maxInt(vk.SampleMask);
|
||||||
|
|
||||||
|
const coverage_word = if (word_index == 0) coverage_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
||||||
const fragment_word = if (word_index == 0) fragment_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
const fragment_word = if (word_index == 0) fragment_sample_mask orelse std.math.maxInt(vk.SampleMask) else std.math.maxInt(vk.SampleMask);
|
||||||
return (pipeline_word & fragment_word & bit) != 0;
|
return (pipeline_word & coverage_word & fragment_word & bit) != 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ inline fn edgeFunction(a: F32x4, b: F32x4, p: F32x4) f32 {
|
|||||||
inline fn isInclusiveEdge(a: F32x4, b: F32x4) bool {
|
inline fn isInclusiveEdge(a: F32x4, b: F32x4) bool {
|
||||||
const dx = b[0] - a[0];
|
const dx = b[0] - a[0];
|
||||||
const dy = b[1] - a[1];
|
const dy = b[1] - a[1];
|
||||||
return dy < 0.0 or (dy == 0.0 and dx > 0.0);
|
return dy > 0.0 or (dy == 0.0 and dx < 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn edgeContainsPixel(a: F32x4, b: F32x4, edge_value: f32, area: f32) bool {
|
inline fn edgeContainsPixel(a: F32x4, b: F32x4, edge_value: f32, area: f32) bool {
|
||||||
@@ -139,6 +139,56 @@ inline fn edgeContainsPixel(a: F32x4, b: F32x4, edge_value: f32, area: f32) bool
|
|||||||
edge_value < 0.0 or (edge_value == 0.0 and isInclusiveEdge(b, a));
|
edge_value < 0.0 or (edge_value == 0.0 and isInclusiveEdge(b, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fn standardSamplePosition(sample_count: usize, sample_index: usize) struct { x: f32, y: f32 } {
|
||||||
|
return switch (sample_count) {
|
||||||
|
1 => .{ .x = 0.5, .y = 0.5 },
|
||||||
|
2 => switch (sample_index) {
|
||||||
|
0 => .{ .x = 0.75, .y = 0.75 },
|
||||||
|
1 => .{ .x = 0.25, .y = 0.25 },
|
||||||
|
else => .{ .x = 0.5, .y = 0.5 },
|
||||||
|
},
|
||||||
|
4 => switch (sample_index) {
|
||||||
|
0 => .{ .x = 0.375, .y = 0.125 },
|
||||||
|
1 => .{ .x = 0.875, .y = 0.375 },
|
||||||
|
2 => .{ .x = 0.125, .y = 0.625 },
|
||||||
|
3 => .{ .x = 0.625, .y = 0.875 },
|
||||||
|
else => .{ .x = 0.5, .y = 0.5 },
|
||||||
|
},
|
||||||
|
else => .{ .x = 0.5, .y = 0.5 },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn triangleCoverageMask(data: RunData, x: i32, y: i32, sample_count: usize) vk.SampleMask {
|
||||||
|
var mask: vk.SampleMask = 0;
|
||||||
|
for (0..sample_count) |sample_index| {
|
||||||
|
if (sample_index >= @bitSizeOf(vk.SampleMask))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const sample_pos = standardSamplePosition(sample_count, sample_index);
|
||||||
|
const p = zm.f32x4(
|
||||||
|
@as(f32, @floatFromInt(x)) + sample_pos.x,
|
||||||
|
@as(f32, @floatFromInt(y)) + sample_pos.y,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const w0 = edgeFunction(data.v1.position, data.v2.position, p);
|
||||||
|
const w1 = edgeFunction(data.v2.position, data.v0.position, p);
|
||||||
|
const w2 = edgeFunction(data.v0.position, data.v1.position, p);
|
||||||
|
|
||||||
|
const inside =
|
||||||
|
edgeContainsPixel(data.v1.position, data.v2.position, w0, data.area) and
|
||||||
|
edgeContainsPixel(data.v2.position, data.v0.position, w1, data.area) and
|
||||||
|
edgeContainsPixel(data.v0.position, data.v1.position, w2, data.area);
|
||||||
|
|
||||||
|
if (inside) {
|
||||||
|
const bit_index: u5 = @intCast(sample_index);
|
||||||
|
mask |= @as(vk.SampleMask, 1) << bit_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
fn runWrapper(data: RunData) void {
|
fn runWrapper(data: RunData) void {
|
||||||
@call(.always_inline, run, .{data}) catch |err| {
|
@call(.always_inline, run, .{data}) catch |err| {
|
||||||
std.log.scoped(.@"Rasterization stage").err("triangle fill mode catched a '{s}'", .{@errorName(err)});
|
std.log.scoped(.@"Rasterization stage").err("triangle fill mode catched a '{s}'", .{@errorName(err)});
|
||||||
@@ -159,20 +209,18 @@ inline fn run(data: RunData) !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pipeline_data = data.draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
||||||
|
const sample_count = pipeline_data.multisample.rasterization_samples.toInt();
|
||||||
|
const coverage_sample_mask = triangleCoverageMask(data, x, y, sample_count);
|
||||||
|
if (coverage_sample_mask == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
const p = zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, 0.0, 1.0);
|
const p = zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, 0.0, 1.0);
|
||||||
|
|
||||||
const w0 = edgeFunction(data.v1.position, data.v2.position, p);
|
const w0 = edgeFunction(data.v1.position, data.v2.position, p);
|
||||||
const w1 = edgeFunction(data.v2.position, data.v0.position, p);
|
const w1 = edgeFunction(data.v2.position, data.v0.position, p);
|
||||||
const w2 = edgeFunction(data.v0.position, data.v1.position, p);
|
const w2 = edgeFunction(data.v0.position, data.v1.position, p);
|
||||||
|
|
||||||
const inside =
|
|
||||||
edgeContainsPixel(data.v1.position, data.v2.position, w0, data.area) and
|
|
||||||
edgeContainsPixel(data.v2.position, data.v0.position, w1, data.area) and
|
|
||||||
edgeContainsPixel(data.v0.position, data.v1.position, w2, data.area);
|
|
||||||
|
|
||||||
if (!inside)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const b0 = w0 / data.area;
|
const b0 = w0 / data.area;
|
||||||
const b1 = w1 / data.area;
|
const b1 = w1 / data.area;
|
||||||
const b2 = w2 / data.area;
|
const b2 = w2 / data.area;
|
||||||
@@ -252,6 +300,7 @@ inline fn run(data: RunData) !void {
|
|||||||
@intCast(x),
|
@intCast(x),
|
||||||
@intCast(y),
|
@intCast(y),
|
||||||
fragment_result.depth orelse z,
|
fragment_result.depth orelse z,
|
||||||
|
coverage_sample_mask,
|
||||||
fragment_result.sample_mask,
|
fragment_result.sample_mask,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user