fixing all image operation tests
Test / build_and_test (push) Successful in 26s
Build / build (push) Successful in 1m3s

This commit is contained in:
2026-06-01 22:13:43 +02:00
parent 19c8d84e05
commit 6dc82d4a68
14 changed files with 514 additions and 132 deletions
+2 -2
View File
@@ -26,8 +26,8 @@
.hash = "N-V-__8AAMpOQxkHCKTw9i-NwmmQ3ks1ndFDXcVLlic4KjK3", .hash = "N-V-__8AAMpOQxkHCKTw9i-NwmmQ3ks1ndFDXcVLlic4KjK3",
}, },
.SPIRV_Interpreter = .{ .SPIRV_Interpreter = .{
.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#e993162d4eebc8efa3b8a795da8c107a38ba5858", .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#9c355fe126d0142ac6d1fae48633993864c90d61",
.hash = "SPIRV_Interpreter-0.0.1-ajmpn-55BQAOM0GSLiRt-IflVvVg5tRyOyHpBjXz5XdZ", .hash = "SPIRV_Interpreter-0.0.1-ajmpn867BQA-J2PA4fGQGnb3WcNtqd_3_W7-goaEocC5",
.lazy = true, .lazy = true,
}, },
//.SPIRV_Interpreter = .{ //.SPIRV_Interpreter = .{
+2 -2
View File
@@ -168,7 +168,7 @@ pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, fra
if (clear_mask.color_bit) { if (clear_mask.color_bit) {
try blitter.clear( try blitter.clear(
(impl.clear_values orelse return VkError.Unknown)[index], (impl.clear_values orelse return VkError.Unknown)[index],
try image.getClearFormat(), try SoftImage.getClearFormatFor(attachment.format),
image, image,
attachment.format, attachment.format,
attachment.subresource_range, attachment.subresource_range,
@@ -401,7 +401,7 @@ pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, re
}; };
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.image));
const clear_format = try image.getClearFormat(); const clear_format = try SoftImage.getClearFormatFor(image_view.format);
const range: vk.ImageSubresourceRange = .{ const range: vk.ImageSubresourceRange = .{
.aspect_mask = impl.attachment.aspect_mask, .aspect_mask = impl.attachment.aspect_mask,
+8 -2
View File
@@ -49,7 +49,10 @@ pub fn resolveAttachments(self: *Self, render_pass: *SoftRenderPass, subpass_ind
const dst_image_view = self.interface.attachments[resolve.attachment]; const dst_image_view = self.interface.attachments[resolve.attachment];
const dst_image: *SoftImage = @alignCast(@fieldParentPtr("interface", dst_image_view.image)); const dst_image: *SoftImage = @alignCast(@fieldParentPtr("interface", dst_image_view.image));
try blitter.resolve(src_image, dst_image, .{ try blitter.resolveWithFormats(
src_image,
dst_image,
.{
.src_subresource = .{ .src_subresource = .{
.aspect_mask = src_image_view.subresource_range.aspect_mask, .aspect_mask = src_image_view.subresource_range.aspect_mask,
.base_array_layer = src_image_view.subresource_range.base_array_layer, .base_array_layer = src_image_view.subresource_range.base_array_layer,
@@ -65,7 +68,10 @@ pub fn resolveAttachments(self: *Self, render_pass: *SoftRenderPass, subpass_ind
}, },
.dst_offset = .{ .x = 0, .y = 0, .z = 0 }, .dst_offset = .{ .x = 0, .y = 0, .z = 0 },
.extent = src_image.getMipLevelExtent(src_image_view.subresource_range.base_mip_level), .extent = src_image.getMipLevelExtent(src_image_view.subresource_range.base_mip_level),
}); },
src_image_view.format,
dst_image_view.format,
);
} }
} }
} }
+8 -4
View File
@@ -102,9 +102,13 @@ pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements
} }
pub fn getClearFormat(self: *Self) VkError!vk.Format { pub fn getClearFormat(self: *Self) VkError!vk.Format {
return if (base.c.vkuFormatIsSINT(@intCast(@intFromEnum(self.interface.format)))) return getClearFormatFor(self.interface.format);
}
pub fn getClearFormatFor(format: vk.Format) VkError!vk.Format {
return if (base.format.isSint(format))
.r32g32b32a32_sint .r32g32b32a32_sint
else if (base.c.vkuFormatIsUINT(@intCast(@intFromEnum(self.interface.format)))) else if (base.format.isUint(format))
.r32g32b32a32_uint .r32g32b32a32_uint
else else
.r32g32b32a32_sfloat; .r32g32b32a32_sfloat;
@@ -472,8 +476,8 @@ fn getSubresourceLayout(interface: *const Interface, subresource: vk.ImageSubres
.offset = try self.getSubresourceOffset(subresource.aspect_mask, subresource.mip_level, subresource.array_layer), .offset = try self.getSubresourceOffset(subresource.aspect_mask, subresource.mip_level, subresource.array_layer),
.size = self.getMultiSampledLevelSize(subresource.aspect_mask, subresource.mip_level), .size = self.getMultiSampledLevelSize(subresource.aspect_mask, subresource.mip_level),
.row_pitch = self.interface.getRowPitchMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level), .row_pitch = self.interface.getRowPitchMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level),
.array_pitch = self.interface.getSliceMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level), .array_pitch = self.getLayerSize(subresource.aspect_mask),
.depth_pitch = self.getLayerSize(subresource.aspect_mask), .depth_pitch = self.interface.getSliceMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level),
}; };
} }
+209 -9
View File
@@ -102,6 +102,7 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
.writeImageFloat4 = writeImageFloat4, .writeImageFloat4 = writeImageFloat4,
.writeImageInt4 = writeImageInt4, .writeImageInt4 = writeImageInt4,
.sampleImageFloat4 = sampleImageFloat4, .sampleImageFloat4 = sampleImageFloat4,
.queryImageSize = queryImageSize,
}, },
) catch |err| { ) 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)});
@@ -187,6 +188,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
.writeImageFloat4 = writeImageFloat4, .writeImageFloat4 = writeImageFloat4,
.writeImageInt4 = writeImageInt4, .writeImageInt4 = writeImageInt4,
.sampleImageFloat4 = sampleImageFloat4, .sampleImageFloat4 = sampleImageFloat4,
.queryImageSize = queryImageSize,
}, },
) catch |err| { ) 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)});
@@ -264,16 +266,17 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32)
} else { } else {
const image_view: *SoftImageView = @ptrCast(@alignCast(context)); const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const cube_face: u32 = if (dim == .Cube) @intCast(z) else 0;
pixel = image.readFloat4( pixel = image.readFloat4(
.{ .{
.x = x, .x = x,
.y = y, .y = y,
.z = z, .z = if (dim == .Cube) 0 else z,
}, },
.{ .{
.aspect_mask = image_view.interface.subresource_range.aspect_mask, .aspect_mask = image_view.interface.subresource_range.aspect_mask,
.mip_level = image_view.interface.subresource_range.base_mip_level, .mip_level = image_view.interface.subresource_range.base_mip_level,
.array_layer = image_view.interface.subresource_range.base_array_layer, .array_layer = image_view.interface.subresource_range.base_array_layer + cube_face,
}, },
image_view.interface.format, image_view.interface.format,
) catch return SpvRuntimeError.Unknown; ) catch return SpvRuntimeError.Unknown;
@@ -296,16 +299,17 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32) S
} else { } else {
const image_view: *SoftImageView = @ptrCast(@alignCast(context)); const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const cube_face: u32 = if (dim == .Cube) @intCast(z) else 0;
pixel = image.readInt4( pixel = image.readInt4(
.{ .{
.x = x, .x = x,
.y = y, .y = y,
.z = z, .z = if (dim == .Cube) 0 else z,
}, },
.{ .{
.aspect_mask = image_view.interface.subresource_range.aspect_mask, .aspect_mask = image_view.interface.subresource_range.aspect_mask,
.mip_level = image_view.interface.subresource_range.base_mip_level, .mip_level = image_view.interface.subresource_range.base_mip_level,
.array_layer = image_view.interface.subresource_range.base_array_layer, .array_layer = image_view.interface.subresource_range.base_array_layer + cube_face,
}, },
image_view.interface.format, image_view.interface.format,
) catch return SpvRuntimeError.Unknown; ) catch return SpvRuntimeError.Unknown;
@@ -328,16 +332,17 @@ fn writeImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32
} else { } else {
const image_view: *SoftImageView = @ptrCast(@alignCast(context)); const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const cube_face: u32 = if (dim == .Cube) @intCast(z) else 0;
image.writeFloat4( image.writeFloat4(
.{ .{
.x = x, .x = x,
.y = y, .y = y,
.z = z, .z = if (dim == .Cube) 0 else z,
}, },
.{ .{
.aspect_mask = image_view.interface.subresource_range.aspect_mask, .aspect_mask = image_view.interface.subresource_range.aspect_mask,
.mip_level = image_view.interface.subresource_range.base_mip_level, .mip_level = image_view.interface.subresource_range.base_mip_level,
.array_layer = image_view.interface.subresource_range.base_array_layer, .array_layer = image_view.interface.subresource_range.base_array_layer + cube_face,
}, },
image_view.interface.format, image_view.interface.format,
vec_pixel, vec_pixel,
@@ -355,16 +360,17 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
} else { } else {
const image_view: *SoftImageView = @ptrCast(@alignCast(context)); const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const cube_face: u32 = if (dim == .Cube) @intCast(z) else 0;
image.writeInt4( image.writeInt4(
.{ .{
.x = x, .x = x,
.y = y, .y = y,
.z = z, .z = if (dim == .Cube) 0 else z,
}, },
.{ .{
.aspect_mask = image_view.interface.subresource_range.aspect_mask, .aspect_mask = image_view.interface.subresource_range.aspect_mask,
.mip_level = image_view.interface.subresource_range.base_mip_level, .mip_level = image_view.interface.subresource_range.base_mip_level,
.array_layer = image_view.interface.subresource_range.base_array_layer, .array_layer = image_view.interface.subresource_range.base_array_layer + cube_face,
}, },
image_view.interface.format, image_view.interface.format,
vec_pixel, vec_pixel,
@@ -372,6 +378,157 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
} }
} }
const CubeCoordinate = struct {
face: u32,
u: f32,
v: f32,
};
fn resolveCubeCoordinate(x: f32, y: f32, z: f32) CubeCoordinate {
const ax = @abs(x);
const ay = @abs(y);
const az = @abs(z);
var face: u32 = 0;
var sc: f32 = 0.0;
var tc: f32 = 0.0;
var ma: f32 = 1.0;
if (ax >= ay and ax >= az) {
ma = ax;
if (x >= 0.0) {
face = 0;
sc = -z;
tc = -y;
} else {
face = 1;
sc = z;
tc = -y;
}
} else if (ay >= ax and ay >= az) {
ma = ay;
if (y >= 0.0) {
face = 2;
sc = x;
tc = z;
} else {
face = 3;
sc = x;
tc = -z;
}
} else {
ma = az;
if (z >= 0.0) {
face = 4;
sc = x;
tc = -y;
} else {
face = 5;
sc = -x;
tc = -y;
}
}
const inv_ma = if (ma == 0.0) 0.0 else 1.0 / ma;
return .{
.face = face,
.u = (sc * inv_ma + 1.0) * 0.5,
.v = (tc * inv_ma + 1.0) * 0.5,
};
}
fn cubeDirection(face: u32, u: f32, v: f32) struct { x: f32, y: f32, z: f32 } {
const sc = u * 2.0 - 1.0;
const tc = v * 2.0 - 1.0;
return switch (face) {
0 => .{ .x = 1.0, .y = -tc, .z = -sc },
1 => .{ .x = -1.0, .y = -tc, .z = sc },
2 => .{ .x = sc, .y = 1.0, .z = tc },
3 => .{ .x = sc, .y = -1.0, .z = -tc },
4 => .{ .x = sc, .y = -tc, .z = 1.0 },
5 => .{ .x = -sc, .y = -tc, .z = -1.0 },
else => .{ .x = 0.0, .y = 0.0, .z = 0.0 },
};
}
fn readSampledFloat4(
image: *SoftImage,
image_view: *SoftImageView,
dim: spv.SpvDim,
coord: CubeCoordinate,
ix: i32,
iy: i32,
) VkError!zm.F32x4 {
const width_f: f32 = @floatFromInt(image.interface.extent.width);
const height_f: f32 = @floatFromInt(image.interface.extent.height);
const texel = if (dim == .Cube) blk: {
const dir = cubeDirection(
coord.face,
(@as(f32, @floatFromInt(ix)) + 0.5) / width_f,
(@as(f32, @floatFromInt(iy)) + 0.5) / height_f,
);
break :blk resolveCubeCoordinate(dir.x, dir.y, dir.z);
} else coord;
const result = try image.readFloat4(
.{
.x = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, image.interface.extent.width - 1)
else
std.math.clamp(ix, 0, image.interface.extent.width - 1),
.y = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, image.interface.extent.height - 1)
else
std.math.clamp(iy, 0, image.interface.extent.height - 1),
.z = 0,
},
.{
.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 + texel.face,
},
image_view.interface.format,
);
return result;
}
fn sampleNearestFloat4(image: *SoftImage, image_view: *SoftImageView, dim: spv.SpvDim, coord: CubeCoordinate) VkError!zm.F32x4 {
const width_f: f32 = @floatFromInt(image.interface.extent.width);
const height_f: f32 = @floatFromInt(image.interface.extent.height);
return readSampledFloat4(
image,
image_view,
dim,
coord,
@intFromFloat(coord.u * width_f),
@intFromFloat(coord.v * height_f),
);
}
fn sampleLinearFloat4(image: *SoftImage, image_view: *SoftImageView, dim: spv.SpvDim, coord: CubeCoordinate) VkError!zm.F32x4 {
const width_f: f32 = @floatFromInt(image.interface.extent.width);
const height_f: f32 = @floatFromInt(image.interface.extent.height);
const x = coord.u * width_f - 0.5;
const y = coord.v * height_f - 0.5;
const x0: i32 = @intFromFloat(@floor(x));
const y0: i32 = @intFromFloat(@floor(y));
const x1 = x0 + 1;
const y1 = y0 + 1;
const wx = x - @as(f32, @floatFromInt(x0));
const wy = y - @as(f32, @floatFromInt(y0));
const p00 = try readSampledFloat4(image, image_view, dim, coord, x0, y0);
const p10 = try readSampledFloat4(image, image_view, dim, coord, x1, y0);
const p01 = try readSampledFloat4(image, image_view, dim, coord, x0, y1);
const p11 = try readSampledFloat4(image, image_view, dim, coord, x1, y1);
const row0 = p00 * zm.f32x4s(1.0 - wx) + p10 * zm.f32x4s(wx);
const row1 = p01 * zm.f32x4s(1.0 - wx) + p11 * zm.f32x4s(wx);
return row0 * zm.f32x4s(1.0 - wy) + row1 * zm.f32x4s(wy);
}
fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32) SpvRuntimeError!spv.Runtime.Vec4(f32) { 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); var pixel = zm.f32x4s(0.0);
@@ -385,8 +542,14 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim,
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image)); const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const sampler: *SoftSampler = @ptrCast(@alignCast(context2)); const sampler: *SoftSampler = @ptrCast(@alignCast(context2));
_ = sampler;
if (dim == .Cube) {
const coord = resolveCubeCoordinate(x, y, z);
pixel = switch (sampler.interface.mag_filter) {
.linear => sampleLinearFloat4(image, image_view, dim, coord),
else => sampleNearestFloat4(image, image_view, dim, coord),
} catch return SpvRuntimeError.Unknown;
} else {
pixel = image.readFloat4( pixel = image.readFloat4(
.{ .{
.x = std.math.clamp(@as(i32, @intFromFloat(x * @as(f32, @floatFromInt(image.interface.extent.width)))), 0, image.interface.extent.width - 1), .x = std.math.clamp(@as(i32, @intFromFloat(x * @as(f32, @floatFromInt(image.interface.extent.width)))), 0, image.interface.extent.width - 1),
@@ -401,6 +564,7 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim,
image_view.interface.format, image_view.interface.format,
) catch return SpvRuntimeError.Unknown; ) catch return SpvRuntimeError.Unknown;
} }
}
return .{ return .{
.x = pixel[0], .x = pixel[0],
@@ -409,3 +573,39 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim,
.w = pixel[3], .w = pixel[3],
}; };
} }
fn queryImageSize(context: *anyopaque, dim: spv.SpvDim, arrayed: bool) SpvRuntimeError!spv.Runtime.Vec4(u32) {
if (dim == .Buffer) {
const buffer_view: *SoftBufferView = @ptrCast(@alignCast(context));
const range = if (buffer_view.interface.range == vk.WHOLE_SIZE)
buffer_view.interface.buffer.size - buffer_view.interface.offset
else
buffer_view.interface.range;
return .{
.x = @intCast(@divTrunc(range, base.format.texelSize(buffer_view.interface.format))),
.y = 0,
.z = 0,
.w = 0,
};
}
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const extent = image.getMipLevelExtent(image_view.interface.subresource_range.base_mip_level);
const layers = if (image_view.interface.subresource_range.layer_count == vk.REMAINING_ARRAY_LAYERS)
image.interface.array_layers - image_view.interface.subresource_range.base_array_layer
else
image_view.interface.subresource_range.layer_count;
return switch (dim) {
.@"1D" => if (arrayed)
.{ .x = extent.width, .y = layers, .z = 0, .w = 0 }
else
.{ .x = extent.width, .y = 0, .z = 0, .w = 0 },
.@"2D", .Cube, .Rect => if (arrayed)
.{ .x = extent.width, .y = extent.height, .z = layers, .w = 0 }
else
.{ .x = extent.width, .y = extent.height, .z = 0, .w = 0 },
.@"3D" => .{ .x = extent.width, .y = extent.height, .z = extent.depth, .w = 0 },
else => .{ .x = extent.width, .y = extent.height, .z = layers, .w = 0 },
};
}
+83 -3
View File
@@ -106,7 +106,27 @@ inline fn run(data: RunData) !void {
const rt = &shader.runtimes[data.batch_id].rt; const rt = &shader.runtimes[data.batch_id].rt;
const entry = try rt.getEntryPointByName(shader.entry); const entry = try rt.getEntryPointByName(shader.entry);
const uses_control_barrier = hasControlBarrier(rt.mod.code);
var barrier_runtimes: []spv.Runtime = &.{};
var barrier_statuses: []spv.Runtime.EntryPointStatus = &.{};
if (uses_control_barrier) {
barrier_runtimes = try allocator.alloc(spv.Runtime, data.invocations_per_workgroup);
barrier_statuses = try allocator.alloc(spv.Runtime.EntryPointStatus, data.invocations_per_workgroup);
for (barrier_runtimes) |*barrier_rt| {
barrier_rt.* = try spv.Runtime.init(allocator, rt.mod, rt.image_api);
try barrier_rt.copySpecializationConstantsFrom(allocator, rt);
}
}
defer {
for (barrier_runtimes) |*barrier_rt| {
barrier_rt.deinit(allocator);
}
allocator.free(barrier_runtimes);
allocator.free(barrier_statuses);
}
if (!uses_control_barrier)
try ExecutionDevice.writeDescriptorSets(data.self.state, rt); try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
var group_index: usize = data.batch_id; var group_index: usize = data.batch_id;
@@ -121,15 +141,23 @@ inline fn run(data: RunData) !void {
modulo -= group_y * data.group_count_x; modulo -= group_y * data.group_count_x;
const group_x = modulo; const group_x = modulo;
try setupWorkgroupBuiltins(data.self, rt, .{ const group_count_vec = @Vector(3, u32){
@as(u32, @intCast(data.group_count_x)), @as(u32, @intCast(data.group_count_x)),
@as(u32, @intCast(data.group_count_y)), @as(u32, @intCast(data.group_count_y)),
@as(u32, @intCast(data.group_count_z)), @as(u32, @intCast(data.group_count_z)),
}, .{ };
const group_id_vec = @Vector(3, u32){
@as(u32, @intCast(group_x)), @as(u32, @intCast(group_x)),
@as(u32, @intCast(group_y)), @as(u32, @intCast(group_y)),
@as(u32, @intCast(group_z)), @as(u32, @intCast(group_z)),
}); };
if (uses_control_barrier) {
try runBarrierWorkgroup(data, barrier_runtimes, barrier_statuses, entry, group_count_vec, group_id_vec);
continue;
}
try setupWorkgroupBuiltins(data.self, rt, group_count_vec, group_id_vec);
for (0..data.invocations_per_workgroup) |i| { for (0..data.invocations_per_workgroup) |i| {
const invocation_index = data.self.invocation_index.fetchAdd(1, .monotonic); const invocation_index = data.self.invocation_index.fetchAdd(1, .monotonic);
@@ -163,6 +191,58 @@ inline fn run(data: RunData) !void {
} }
} }
fn runBarrierWorkgroup(
data: RunData,
runtimes: []spv.Runtime,
statuses: []spv.Runtime.EntryPointStatus,
entry: spv.SpvWord,
group_count: @Vector(3, u32),
group_id: @Vector(3, u32),
) !void {
const allocator = data.self.device.device_allocator.allocator();
for (runtimes, 0..) |*rt, i| {
try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
try setupWorkgroupBuiltins(data.self, rt, group_count, group_id);
try setupSubgroupBuiltins(data.self, rt, group_id, i);
statuses[i] = try rt.beginEntryPoint(allocator, entry);
try rt.flushDescriptorSets(allocator);
}
while (true) {
var pending = false;
for (statuses) |status| {
if (status == .barrier) {
pending = true;
break;
}
}
if (!pending)
break;
for (runtimes, 0..) |*rt, i| {
if (statuses[i] == .completed)
continue;
statuses[i] = try rt.continueEntryPoint(allocator);
try rt.flushDescriptorSets(allocator);
}
}
}
/// TODO: Move this in the SPIR-V Interpreter
fn hasControlBarrier(code: []const spv.SpvWord) bool {
var i: usize = 5;
while (i < code.len) {
const opcode_data = code[i];
const word_count = (opcode_data & (~spv.spv.SpvOpCodeMask)) >> spv.spv.SpvWordCountShift;
const opcode: spv.spv.SpvOp = @enumFromInt(opcode_data & spv.spv.SpvOpCodeMask);
if (opcode == .ControlBarrier)
return true;
i += @max(word_count, 1);
}
return false;
}
inline fn dumpResultsTable(allocator: std.mem.Allocator, io: std.Io, rt: *spv.Runtime, is_early: bool) !void { inline fn dumpResultsTable(allocator: std.mem.Allocator, io: std.Io, rt: *spv.Runtime, is_early: bool) !void {
@branchHint(.cold); @branchHint(.cold);
const file = try std.Io.Dir.cwd().createFile( const file = try std.Io.Dir.cwd().createFile(
+1 -1
View File
@@ -71,7 +71,7 @@ pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void {
switch (binding) { switch (binding) {
.buffer => |buffer_data_array| for (buffer_data_array, 0..) |buffer_data, descriptor_index| { .buffer => |buffer_data_array| for (buffer_data_array, 0..) |buffer_data, descriptor_index| {
if (buffer_data.object) |buffer| { if (buffer_data.object) |buffer| {
const map = buffer.mapAsSliceWithOffset(u8, buffer_data.offset, buffer_data.size) catch continue :bindings; const map = buffer.mapAsSliceWithAddedOffset(u8, buffer_data.offset, buffer_data.size) catch continue :bindings;
try rt.writeDescriptorSet( try rt.writeDescriptorSet(
map, map,
@as(u32, @intCast(set_index)), @as(u32, @intCast(set_index)),
+98 -33
View File
@@ -286,6 +286,17 @@ fn sample(src: []const u8, pos: F32x4, dim: F32x4, slice_bytes: usize, pitch_byt
} }
pub fn blitRegion(src: *const SoftImage, dst: *SoftImage, region: vk.ImageBlit, filter: vk.Filter) VkError!void { pub fn blitRegion(src: *const SoftImage, dst: *SoftImage, region: vk.ImageBlit, filter: vk.Filter) VkError!void {
try blitRegionWithFormats(
src,
dst,
region,
filter,
base.format.fromAspect(src.interface.format, region.src_subresource.aspect_mask),
base.format.fromAspect(dst.interface.format, region.dst_subresource.aspect_mask),
);
}
pub fn blitRegionWithFormats(src: *const SoftImage, dst: *SoftImage, region: vk.ImageBlit, filter: vk.Filter, src_format: vk.Format, dst_format: vk.Format) VkError!void {
const io = dst.interface.owner.io(); const io = dst.interface.owner.io();
const timer = std.Io.Timestamp.now(io, .real); const timer = std.Io.Timestamp.now(io, .real);
defer if (comptime base.config.logs != .none) { defer if (comptime base.config.logs != .none) {
@@ -323,13 +334,10 @@ pub fn blitRegion(src: *const SoftImage, dst: *SoftImage, region: vk.ImageBlit,
const y0 = @as(f32, @floatFromInt(src_offset_0.y)) + (0.5 - @as(f32, @floatFromInt(dst_offset_0.y))) * height_ratio; const y0 = @as(f32, @floatFromInt(src_offset_0.y)) + (0.5 - @as(f32, @floatFromInt(dst_offset_0.y))) * height_ratio;
const z0 = @as(f32, @floatFromInt(src_offset_0.z)) + (0.5 - @as(f32, @floatFromInt(dst_offset_0.z))) * depth_ratio; const z0 = @as(f32, @floatFromInt(src_offset_0.z)) + (0.5 - @as(f32, @floatFromInt(dst_offset_0.z))) * depth_ratio;
const src_slice_pitch_bytes = src.interface.getSliceMemSizeForMipLevel(region.src_subresource.aspect_mask, region.src_subresource.mip_level); const src_slice_pitch_bytes = src.getSliceMemSizeForMipLevelWithFormat(region.src_subresource.aspect_mask, region.src_subresource.mip_level, src_format);
const src_row_pitch_bytes = src.interface.getRowPitchMemSizeForMipLevel(region.src_subresource.aspect_mask, region.src_subresource.mip_level); const src_row_pitch_bytes = src.getRowPitchMemSizeForMipLevelWithFormat(region.src_subresource.aspect_mask, region.src_subresource.mip_level, src_format);
const dst_slice_pitch_bytes = dst.interface.getSliceMemSizeForMipLevel(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level); const dst_slice_pitch_bytes = dst.getSliceMemSizeForMipLevelWithFormat(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_format);
const dst_row_pitch_bytes = dst.interface.getRowPitchMemSizeForMipLevel(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level); const dst_row_pitch_bytes = dst.getRowPitchMemSizeForMipLevelWithFormat(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_format);
const src_format = base.format.fromAspect(src.interface.format, region.src_subresource.aspect_mask);
const dst_format = base.format.fromAspect(dst.interface.format, region.dst_subresource.aspect_mask);
const apply_filter = (filter != .nearest); const apply_filter = (filter != .nearest);
const allow_srgb_conversion = apply_filter or base.format.isSrgb(src_format) != base.format.isSrgb(dst_format); const allow_srgb_conversion = apply_filter or base.format.isSrgb(src_format) != base.format.isSrgb(dst_format);
@@ -485,6 +493,16 @@ fn blit(state: State, data: BlitData) void {
/// Using image blitting to resolve /// Using image blitting to resolve
pub inline fn resolve(src: *const SoftImage, dst: *SoftImage, region: vk.ImageResolve) VkError!void { pub inline fn resolve(src: *const SoftImage, dst: *SoftImage, region: vk.ImageResolve) VkError!void {
try resolveWithFormats(
src,
dst,
region,
base.format.fromAspect(src.interface.format, region.src_subresource.aspect_mask),
base.format.fromAspect(dst.interface.format, region.dst_subresource.aspect_mask),
);
}
pub inline fn resolveWithFormats(src: *const SoftImage, dst: *SoftImage, region: vk.ImageResolve, src_format: vk.Format, dst_format: vk.Format) VkError!void {
var blit_region: vk.ImageBlit = .{ var blit_region: vk.ImageBlit = .{
.src_offsets = .{ region.src_offset, region.src_offset }, .src_offsets = .{ region.src_offset, region.src_offset },
.src_subresource = region.src_subresource, .src_subresource = region.src_subresource,
@@ -500,7 +518,7 @@ pub inline fn resolve(src: *const SoftImage, dst: *SoftImage, region: vk.ImageRe
blit_region.dst_offsets[1].y += @intCast(region.extent.height); blit_region.dst_offsets[1].y += @intCast(region.extent.height);
blit_region.dst_offsets[1].z += @intCast(region.extent.depth); blit_region.dst_offsets[1].z += @intCast(region.extent.depth);
try blitRegion(src, dst, blit_region, .nearest); try blitRegionWithFormats(src, dst, blit_region, .nearest, src_format, dst_format);
} }
fn applyScaleAndClamp(base_color: F32x4, state: State, apply_srgb_convertion: bool) F32x4 { fn applyScaleAndClamp(base_color: F32x4, state: State, apply_srgb_convertion: bool) F32x4 {
@@ -532,6 +550,16 @@ fn applyScaleAndClamp(base_color: F32x4, state: State, apply_srgb_convertion: bo
return color; return color;
} }
inline fn normalizedI8(value: u8) f32 {
const signed: i8 = @bitCast(value);
return @max(@as(f32, @floatFromInt(signed)) / @as(f32, @floatFromInt(std.math.maxInt(i8))), -1.0);
}
inline fn normalizedI16(value: u16) f32 {
const signed: i16 = @bitCast(value);
return @max(@as(f32, @floatFromInt(signed)) / @as(f32, @floatFromInt(std.math.maxInt(i16))), -1.0);
}
pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 { pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
var c: F32x4 = .{ 0.0, 0.0, 0.0, 1.0 }; var c: F32x4 = .{ 0.0, 0.0, 0.0, 1.0 };
@@ -543,9 +571,9 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
.r8_sint, .r8_sint,
.r8_snorm, .r8_snorm,
=> c[0] = @as(f32, @floatFromInt(map[0])) / std.math.maxInt(i8), => c[0] = normalizedI8(map[0]),
.r16_snorm => c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map))) / std.math.maxInt(i16), .r16_snorm => c[0] = normalizedI16(std.mem.bytesToValue(u16, map)),
.r16_unorm => c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map))) / std.math.maxInt(u16), .r16_unorm => c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map))) / std.math.maxInt(u16),
.r8g8b8a8_sint, .r8g8b8a8_sint,
@@ -570,15 +598,15 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
.r8g8_sint, .r8g8_sint,
.r8g8_snorm, .r8g8_snorm,
=> { => {
c[0] = @as(f32, @floatFromInt(map[0])) / std.math.maxInt(i8); c[0] = normalizedI8(map[0]);
c[1] = @as(f32, @floatFromInt(map[1])) / std.math.maxInt(i8); c[1] = normalizedI8(map[1]);
}, },
.r8g8b8a8_snorm => { .r8g8b8a8_snorm => {
c[0] = @as(f32, @floatFromInt(map[0])) / std.math.maxInt(i8); c[0] = normalizedI8(map[0]);
c[1] = @as(f32, @floatFromInt(map[1])) / std.math.maxInt(i8); c[1] = normalizedI8(map[1]);
c[2] = @as(f32, @floatFromInt(map[2])) / std.math.maxInt(i8); c[2] = normalizedI8(map[2]);
c[3] = @as(f32, @floatFromInt(map[3])) / std.math.maxInt(i8); c[3] = normalizedI8(map[3]);
}, },
.r4g4b4a4_unorm_pack16 => { .r4g4b4a4_unorm_pack16 => {
@@ -627,8 +655,8 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
}, },
.r16g16_snorm => { .r16g16_snorm => {
c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[0..]))) / std.math.maxInt(i16); c[0] = normalizedI16(std.mem.bytesToValue(u16, map[0..]));
c[1] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[2..]))) / std.math.maxInt(i16); c[1] = normalizedI16(std.mem.bytesToValue(u16, map[2..]));
}, },
.r16g16_unorm => { .r16g16_unorm => {
@@ -666,10 +694,10 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
.r16g16b16a16_sint, .r16g16b16a16_sint,
.r16g16b16a16_snorm, .r16g16b16a16_snorm,
=> { => {
c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[0..]))) / std.math.maxInt(i16); c[0] = normalizedI16(std.mem.bytesToValue(u16, map[0..]));
c[1] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[2..]))) / std.math.maxInt(i16); c[1] = normalizedI16(std.mem.bytesToValue(u16, map[2..]));
c[2] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[4..]))) / std.math.maxInt(i16); c[2] = normalizedI16(std.mem.bytesToValue(u16, map[4..]));
c[3] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map[6..]))) / std.math.maxInt(i16); c[3] = normalizedI16(std.mem.bytesToValue(u16, map[6..]));
}, },
.r16g16b16a16_sfloat => c = std.mem.bytesToValue(@Vector(4, f16), map), .r16g16b16a16_sfloat => c = std.mem.bytesToValue(@Vector(4, f16), map),
@@ -704,10 +732,10 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
.a8b8g8r8_snorm_pack32, .a8b8g8r8_snorm_pack32,
=> { => {
const pack = std.mem.bytesToValue(@Vector(4, u8), map); const pack = std.mem.bytesToValue(@Vector(4, u8), map);
c[0] = @as(f32, @floatFromInt(pack[0])) / std.math.maxInt(i8); c[0] = normalizedI8(pack[0]);
c[1] = @as(f32, @floatFromInt(pack[1])) / std.math.maxInt(i8); c[1] = normalizedI8(pack[1]);
c[2] = @as(f32, @floatFromInt(pack[2])) / std.math.maxInt(i8); c[2] = normalizedI8(pack[2]);
c[3] = @as(f32, @floatFromInt(pack[3])) / std.math.maxInt(i8); c[3] = normalizedI8(pack[3]);
}, },
.a2b10g10r10_uint_pack32, .a2b10g10r10_uint_pack32,
@@ -1093,37 +1121,55 @@ pub fn writeFloat4(c: F32x4, map: []u8, dst_format: vk.Format) void {
} }
} }
inline fn signExtendI8(value: u8) u32 {
return @bitCast(@as(i32, @as(i8, @bitCast(value))));
}
inline fn signExtendI16(value: u16) u32 {
return @bitCast(@as(i32, @as(i16, @bitCast(value))));
}
pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 { pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
var c: U32x4 = .{ 0, 0, 0, 1 }; var c: U32x4 = .{ 0, 0, 0, 1 };
switch (src_format) { switch (src_format) {
.r8_sint,
.r8_uint, .r8_uint,
.s8_uint, .s8_uint,
=> c[0] = map[0], => c[0] = map[0],
.r16_sint, .r8_sint => c[0] = signExtendI8(map[0]),
.r16_uint, .r16_uint,
=> c[0] = std.mem.bytesToValue(u16, map), => c[0] = std.mem.bytesToValue(u16, map),
.r16_sint => c[0] = signExtendI16(std.mem.bytesToValue(u16, map)),
.r32_sint, .r32_sint,
.r32_uint, .r32_uint,
=> c[0] = std.mem.bytesToValue(u32, map), => c[0] = std.mem.bytesToValue(u32, map),
.r8g8_sint,
.r8g8_uint, .r8g8_uint,
=> { => {
c[0] = map[0]; c[0] = map[0];
c[1] = map[1]; c[1] = map[1];
}, },
.r16g16_sint, .r8g8_sint => {
c[0] = signExtendI8(map[0]);
c[1] = signExtendI8(map[1]);
},
.r16g16_uint, .r16g16_uint,
=> { => {
c[0] = std.mem.bytesToValue(u16, map[0..]); c[0] = std.mem.bytesToValue(u16, map[0..]);
c[1] = std.mem.bytesToValue(u16, map[2..]); c[1] = std.mem.bytesToValue(u16, map[2..]);
}, },
.r16g16_sint => {
c[0] = signExtendI16(std.mem.bytesToValue(u16, map[0..]));
c[1] = signExtendI16(std.mem.bytesToValue(u16, map[2..]));
},
.r32g32_sint, .r32g32_sint,
.r32g32_uint, .r32g32_uint,
=> { => {
@@ -1131,7 +1177,6 @@ pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
c[1] = std.mem.bytesToValue(u32, map[4..]); c[1] = std.mem.bytesToValue(u32, map[4..]);
}, },
.r8g8b8a8_sint,
.r8g8b8a8_uint, .r8g8b8a8_uint,
=> { => {
c[0] = map[0]; c[0] = map[0];
@@ -1140,7 +1185,13 @@ pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
c[3] = map[3]; c[3] = map[3];
}, },
.r16g16b16a16_sint, .r8g8b8a8_sint => {
c[0] = signExtendI8(map[0]);
c[1] = signExtendI8(map[1]);
c[2] = signExtendI8(map[2]);
c[3] = signExtendI8(map[3]);
},
.r16g16b16a16_uint, .r16g16b16a16_uint,
=> { => {
c[0] = std.mem.bytesToValue(u16, map[0..2]); c[0] = std.mem.bytesToValue(u16, map[0..2]);
@@ -1149,12 +1200,18 @@ pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
c[3] = std.mem.bytesToValue(u16, map[6..8]); c[3] = std.mem.bytesToValue(u16, map[6..8]);
}, },
.r16g16b16a16_sint => {
c[0] = signExtendI16(std.mem.bytesToValue(u16, map[0..2]));
c[1] = signExtendI16(std.mem.bytesToValue(u16, map[2..4]));
c[2] = signExtendI16(std.mem.bytesToValue(u16, map[4..6]));
c[3] = signExtendI16(std.mem.bytesToValue(u16, map[6..8]));
},
.r32g32b32a32_sint, .r32g32b32a32_sint,
.r32g32b32a32_uint, .r32g32b32a32_uint,
=> c = std.mem.bytesToValue(U32x4, map), => c = std.mem.bytesToValue(U32x4, map),
.a8b8g8r8_uint_pack32, .a8b8g8r8_uint_pack32,
.a8b8g8r8_sint_pack32,
.a8b8g8r8_unorm_pack32, .a8b8g8r8_unorm_pack32,
.a8b8g8r8_snorm_pack32, .a8b8g8r8_snorm_pack32,
=> { => {
@@ -1165,6 +1222,14 @@ pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
c[3] = pack[3]; c[3] = pack[3];
}, },
.a8b8g8r8_sint_pack32 => {
const pack = std.mem.bytesToValue(@Vector(4, u8), map);
c[0] = signExtendI8(pack[0]);
c[1] = signExtendI8(pack[1]);
c[2] = signExtendI8(pack[2]);
c[3] = signExtendI8(pack[3]);
},
.a2b10g10r10_unorm_pack32, .a2b10g10r10_unorm_pack32,
.a2b10g10r10_uint_pack32, .a2b10g10r10_uint_pack32,
=> { => {
+10 -2
View File
@@ -32,8 +32,9 @@ pub fn shaderInvocation(
mutex.lock(io) catch return SpvRuntimeError.Unknown; mutex.lock(io) catch return SpvRuntimeError.Unknown;
defer mutex.unlock(io); defer mutex.unlock(io);
try rt.populatePushConstants(draw_call.renderer.state.push_constant_blob[0..]);
const entry = try rt.getEntryPointByName(shader.entry); const entry = try rt.getEntryPointByName(shader.entry);
const output_result = try rt.getResultByLocation(0, .output);
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| { for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
const result_word = rt.getResultByLocation(@intCast(location), .input) catch |err| switch (err) { const result_word = rt.getResultByLocation(@intCast(location), .input) catch |err| switch (err) {
@@ -54,8 +55,15 @@ pub fn shaderInvocation(
}; };
var outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(zm.F32x4)]u8 = undefined; var outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(zm.F32x4)]u8 = undefined;
@memset(std.mem.asBytes(&outputs), 0);
try rt.readOutput(std.mem.asBytes(&outputs), output_result); for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
const result_word = rt.getResultByLocation(@intCast(location), .output) catch |err| switch (err) {
SpvRuntimeError.NotFound => continue,
else => return err,
};
try rt.readOutput(&outputs[location], result_word);
}
try rt.flushDescriptorSets(allocator); try rt.flushDescriptorSets(allocator);
+22 -13
View File
@@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const clip = @import("clip.zig"); const clip = @import("clip.zig");
@@ -20,8 +21,15 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics; const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics;
const topology = pipeline_data.input_assembly.topology; const topology = pipeline_data.input_assembly.topology;
const color_attachment = if (draw_call.render_pass.interface.subpasses[renderer.subpass_index].color_attachments) |attachments| attachments[0].attachment else return VkError.InvalidAttachmentDrv; const color_attachments = draw_call.render_pass.interface.subpasses[renderer.subpass_index].color_attachments orelse return VkError.InvalidAttachmentDrv;
const render_target_view: *base.ImageView = draw_call.color_attachments[color_attachment]; const color_attachment_access = allocator.alloc(?common.RenderTargetAccess, color_attachments.len) catch return VkError.OutOfDeviceMemory;
@memset(color_attachment_access, null);
for (color_attachments, color_attachment_access) |attachment_ref, *access| {
if (attachment_ref.attachment == vk.ATTACHMENT_UNUSED)
continue;
const render_target_view: *base.ImageView = draw_call.color_attachments[attachment_ref.attachment];
const render_target: *SoftImage = @alignCast(@fieldParentPtr("interface", render_target_view.image)); const render_target: *SoftImage = @alignCast(@fieldParentPtr("interface", render_target_view.image));
const color_range = render_target_view.subresource_range; const color_range = render_target_view.subresource_range;
@@ -33,13 +41,14 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
color_range.base_array_layer, color_range.base_array_layer,
); );
const color_attachment_subresource_size = render_target.getLayerSize(color_range.aspect_mask); const color_attachment_subresource_size = render_target.getLayerSize(color_range.aspect_mask);
const color_attachment_access: common.RenderTargetAccess = .{ access.* = .{
.mutex = undefined, .mutex = undefined,
.base = try render_target.mapAsSliceWithAddedOffset(u8, color_attachment_subresource_offset, color_attachment_subresource_size), .base = try render_target.mapAsSliceWithAddedOffset(u8, color_attachment_subresource_offset, color_attachment_subresource_size),
.row_pitch = render_target.getRowPitchMemSizeForMipLevelWithFormat(color_range.aspect_mask, color_range.base_mip_level, color_format), .row_pitch = render_target.getRowPitchMemSizeForMipLevelWithFormat(color_range.aspect_mask, color_range.base_mip_level, color_format),
.texel_size = base.format.texelSize(color_format), .texel_size = base.format.texelSize(color_format),
.format = color_format, .format = color_format,
}; };
}
const depth_attachment_view: ?*base.ImageView = if (draw_call.depth_attachment) |view| view else null; const depth_attachment_view: ?*base.ImageView = if (draw_call.depth_attachment) |view| view else null;
const depth_attachment: ?*SoftImage = if (depth_attachment_view) |view| @alignCast(@fieldParentPtr("interface", view.image)) else null; const depth_attachment: ?*SoftImage = if (depth_attachment_view) |view| @alignCast(@fieldParentPtr("interface", view.image)) else null;
@@ -60,7 +69,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
break :blk .{ break :blk .{
.mutex = .init, .mutex = .init,
.base = try depth_attachment.?.mapAsSliceWithAddedOffset(u8, attachment_subresource_offset, attachment_subresource_size), .base = try depth_attachment.?.mapAsSliceWithAddedOffset(u8, attachment_subresource_offset, attachment_subresource_size),
.row_pitch = render_target.getRowPitchMemSizeForMipLevelWithFormat(depth_range.aspect_mask, depth_range.base_mip_level, depth_format), .row_pitch = depth_attachment.?.getRowPitchMemSizeForMipLevelWithFormat(depth_range.aspect_mask, depth_range.base_mip_level, depth_format),
.texel_size = base.format.texelSize(depth_format), .texel_size = base.format.texelSize(depth_format),
.format = depth_format, .format = depth_format,
}; };
@@ -80,7 +89,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
v0, v0,
v1, v1,
v2, v2,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
}, },
@@ -97,7 +106,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
v0, v0,
v1, v1,
v2, v2,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
} }
@@ -116,7 +125,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
v0, v0,
v1, v1,
v2, v2,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
} else { } else {
@@ -127,7 +136,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
v1, v1,
v0, v0,
v2, v2,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
} }
@@ -143,7 +152,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
draw_call, draw_call,
v0, v0,
v1, v1,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
}, },
@@ -157,7 +166,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
draw_call, draw_call,
v0, v0,
v1, v1,
&color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
); );
} }
@@ -173,7 +182,7 @@ fn clipTransformAndRasterizeLine(
draw_call: *DrawCall, draw_call: *DrawCall,
v0: *Vertex, v0: *Vertex,
v1: *Vertex, v1: *Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
) VkError!void { ) VkError!void {
const clipped_line = (try clip.clipLine(allocator, v0, v1)) orelse return; const clipped_line = (try clip.clipLine(allocator, v0, v1)) orelse return;
@@ -201,7 +210,7 @@ fn clipTransformAndRasterizeTriangle(
v0: *Vertex, v0: *Vertex,
v1: *Vertex, v1: *Vertex,
v2: *Vertex, v2: *Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
) VkError!void { ) VkError!void {
const clipped_polygon = try clip.clipTriangle(allocator, v0, v1, v2); const clipped_polygon = try clip.clipTriangle(allocator, v0, v1, v2);
@@ -238,7 +247,7 @@ fn rasterizeTriangle(
v0: *Vertex, v0: *Vertex,
v1: *Vertex, v1: *Vertex,
v2: *Vertex, v2: *Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
) VkError!void { ) VkError!void {
if (try triangleIsCulled(renderer, v0, v1, v2)) if (try triangleIsCulled(renderer, v0, v1, v2))
+2 -2
View File
@@ -28,7 +28,7 @@ const RunData = struct {
end_vertex: *Renderer.Vertex, end_vertex: *Renderer.Vertex,
start_step: usize, start_step: usize,
end_step: usize, end_step: usize,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
}; };
@@ -37,7 +37,7 @@ pub fn drawLine(
draw_call: *Renderer.DrawCall, draw_call: *Renderer.DrawCall,
v0: *Renderer.Vertex, v0: *Renderer.Vertex,
v1: *Renderer.Vertex, v1: *Renderer.Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
) VkError!void { ) VkError!void {
const io = draw_call.renderer.device.interface.io(); const io = draw_call.renderer.device.interface.io();
+14 -13
View File
@@ -101,10 +101,15 @@ inline fn interpolateF32x4(value0: F32x4, value1: F32x4, value2: F32x4, b0: f32,
return (value0 * zm.f32x4s(b0)) + (value1 * zm.f32x4s(b1)) + (value2 * zm.f32x4s(b2)); return (value0 * zm.f32x4s(b0)) + (value1 * zm.f32x4s(b1)) + (value2 * zm.f32x4s(b2));
} }
inline fn fragmentOutputFloat4(output: [@sizeOf(F32x4)]u8, format: vk.Format) F32x4 {
const color = std.mem.bytesToValue(F32x4, &output);
return if (base.format.isSrgb(format)) zm.rgbToSrgb(color) else color;
}
pub fn writeToTargets( pub fn writeToTargets(
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(F32x4)]u8, outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][@sizeOf(F32x4)]u8,
draw_call: *Renderer.DrawCall, draw_call: *Renderer.DrawCall,
color_attachment_access: *const RenderTargetAccess, color_attachment_access: []const ?RenderTargetAccess,
depth_attachment_access: ?*RenderTargetAccess, depth_attachment_access: ?*RenderTargetAccess,
x: usize, x: usize,
y: usize, y: usize,
@@ -112,8 +117,6 @@ pub fn writeToTargets(
) VkError!void { ) VkError!void {
const io = draw_call.renderer.device.interface.io(); const io = draw_call.renderer.device.interface.io();
const color_offset = @as(usize, @intCast(x)) * color_attachment_access.texel_size + @as(usize, @intCast(y)) * color_attachment_access.row_pitch;
// After work depth test to avoid overwritten depth pixels during fragment invocations // After work depth test to avoid overwritten depth pixels during fragment invocations
if (depth_attachment_access) |depth| { if (depth_attachment_access) |depth| {
const depth_offset = @as(usize, @intCast(x)) * depth.texel_size + @as(usize, @intCast(y)) * depth.row_pitch; const depth_offset = @as(usize, @intCast(x)) * depth.texel_size + @as(usize, @intCast(y)) * depth.row_pitch;
@@ -125,18 +128,16 @@ pub fn writeToTargets(
if (z >= depth_value[0]) if (z >= depth_value[0])
return; return;
blitter.writeFloat4(zm.f32x4s(z), depth.base[depth_offset..], depth.format); blitter.writeFloat4(zm.f32x4s(z), depth.base[depth_offset..], depth.format);
// Doubled line to stay inside the critical section
if (base.format.isUnnormalizedInteger(color_attachment_access.format)) {
blitter.writeInt4(std.mem.bytesToValue(U32x4, &outputs[0]), color_attachment_access.base[color_offset..], color_attachment_access.format);
} else {
blitter.writeFloat4(std.mem.bytesToValue(F32x4, &outputs[0]), color_attachment_access.base[color_offset..], color_attachment_access.format);
} }
for (color_attachment_access, 0..) |maybe_color, location| {
const color = maybe_color orelse continue;
const color_offset = @as(usize, @intCast(x)) * color.texel_size + @as(usize, @intCast(y)) * color.row_pitch;
if (base.format.isUnnormalizedInteger(color.format)) {
blitter.writeInt4(std.mem.bytesToValue(U32x4, &outputs[location]), color.base[color_offset..], color.format);
} else { } else {
if (base.format.isUnnormalizedInteger(color_attachment_access.format)) { blitter.writeFloat4(fragmentOutputFloat4(outputs[location], color.format), color.base[color_offset..], color.format);
blitter.writeInt4(std.mem.bytesToValue(U32x4, &outputs[0]), color_attachment_access.base[color_offset..], color_attachment_access.format);
} else {
blitter.writeFloat4(std.mem.bytesToValue(F32x4, &outputs[0]), color_attachment_access.base[color_offset..], color_attachment_access.format);
} }
} }
} }
+2 -2
View File
@@ -26,7 +26,7 @@ const RunData = struct {
v0: Renderer.Vertex, v0: Renderer.Vertex,
v1: Renderer.Vertex, v1: Renderer.Vertex,
v2: Renderer.Vertex, v2: Renderer.Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
}; };
@@ -36,7 +36,7 @@ pub fn drawTriangle(
v0: *Renderer.Vertex, v0: *Renderer.Vertex,
v1: *Renderer.Vertex, v1: *Renderer.Vertex,
v2: *Renderer.Vertex, v2: *Renderer.Vertex,
color_attachment_access: *const common.RenderTargetAccess, color_attachment_access: []const ?common.RenderTargetAccess,
depth_attachment_access: ?*common.RenderTargetAccess, depth_attachment_access: ?*common.RenderTargetAccess,
) VkError!void { ) VkError!void {
const io = draw_call.renderer.device.interface.io(); const io = draw_call.renderer.device.interface.io();
+10 -1
View File
@@ -11,6 +11,11 @@ const Self = @This();
pub const ObjectType: vk.ObjectType = .sampler; pub const ObjectType: vk.ObjectType = .sampler;
owner: *Device, owner: *Device,
mag_filter: vk.Filter,
min_filter: vk.Filter,
address_mode_u: vk.SamplerAddressMode,
address_mode_v: vk.SamplerAddressMode,
address_mode_w: vk.SamplerAddressMode,
vtable: *const VTable, vtable: *const VTable,
@@ -20,9 +25,13 @@ pub const VTable = struct {
pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.SamplerCreateInfo) VkError!Self { pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.SamplerCreateInfo) VkError!Self {
_ = allocator; _ = allocator;
_ = info;
return .{ return .{
.owner = device, .owner = device,
.mag_filter = info.mag_filter,
.min_filter = info.min_filter,
.address_mode_u = info.address_mode_u,
.address_mode_v = info.address_mode_v,
.address_mode_w = info.address_mode_w,
.vtable = undefined, .vtable = undefined,
}; };
} }