adding BC compressed format support
Test / build_and_test (push) Successful in 2m21s
Build / build (push) Successful in 3m58s

This commit is contained in:
2026-07-04 01:17:18 +02:00
parent 3a79103ca3
commit bfc5c3933c
6 changed files with 514 additions and 41 deletions
+2 -2
View File
@@ -32,8 +32,8 @@
// Soft dependencies
.SPIRV_Interpreter = .{
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#50a2de5bb756f96f0e51277fb98825a6fe829433",
.hash = "SPIRV_Interpreter-0.0.1-ajmpnwGMCQBT5uWJ847m9Mpa-0NrGaugEN0FewoXgC_2",
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#6e1fa9db32f3e596e30d60f94b2909f3609ec03a",
.hash = "SPIRV_Interpreter-0.0.1-ajmpn_CXCQB0GIcZz8ioOFOW9yLr5Ka-Qir3v3Y1r5Bi",
.lazy = true,
},
//.SPIRV_Interpreter = .{
+45 -13
View File
@@ -55,6 +55,7 @@ const vk = @import("vulkan");
const base = @import("base");
const lib = @import("lib.zig");
const blitter = @import("device/blitter.zig");
const compressed = @import("device/compressed.zig");
const F32x4 = blitter.F32x4;
const U32x4 = blitter.U32x4;
@@ -156,9 +157,13 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
const src_format = self.interface.formatFromAspect(region.src_subresource.aspect_mask);
const bytes_per_block = base.format.texelSize(src_format);
const block_width = base.format.blockWidth(src_format);
const block_height = base.format.blockHeight(src_format);
const src_extent = self.getMipLevelExtent(region.src_subresource.mip_level);
const dst_extent = dst.getMipLevelExtent(region.dst_subresource.mip_level);
const copy_block_width = base.format.blockCountX(src_format, region.extent.width);
const copy_block_height = base.format.blockCountY(src_format, region.extent.height);
const one_is_3D = (self.interface.image_type == .@"3d") != (dst.interface.image_type == .@"3d");
const both_are_3D = (self.interface.image_type == .@"3d") and (dst.interface.image_type == .@"3d");
@@ -178,12 +183,16 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
const slice_count = if (both_are_3D) region.extent.depth else self.interface.samples.toInt();
const is_single_slice = (slice_count == 1);
const is_single_row = (region.extent.height == 1) and is_single_slice;
const is_entire_row = (region.extent.width == src_extent.width) and (region.extent.width == dst_extent.width);
const is_single_row = (copy_block_height == 1) and is_single_slice;
const is_entire_row = (region.extent.width == src_extent.width) and (region.extent.width == dst_extent.width) and
(@mod(@as(usize, @intCast(region.src_offset.x)), block_width) == 0) and
(@mod(@as(usize, @intCast(region.dst_offset.x)), block_width) == 0);
const is_entire_slice = is_entire_row and
(region.extent.height == src_extent.height) and
(region.extent.height == dst_extent.height) and
(@mod(@as(usize, @intCast(region.src_offset.y)), block_height) == 0) and
(@mod(@as(usize, @intCast(region.dst_offset.y)), block_height) == 0) and
(src_depth_pitch_bytes == dst_depth_pitch_bytes);
const src_texel_offset = try self.getTexelMemoryOffset(region.src_offset, .{
@@ -202,12 +211,12 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
for (0..layer_count) |_| {
if (is_single_row) {
const copy_size = region.extent.width * bytes_per_block;
const copy_size = copy_block_width * bytes_per_block;
if (dst_map.len < copy_size or src_map.len < copy_size)
break;
@memcpy(dst_map[0..copy_size], src_map[0..copy_size]);
} else if (is_entire_row and is_single_slice) {
const copy_size = region.extent.height * src_row_pitch_bytes;
const copy_size = copy_block_height * src_row_pitch_bytes;
if (dst_map.len < copy_size or src_map.len < copy_size)
break;
@memcpy(dst_map[0..copy_size], src_map[0..copy_size]);
@@ -217,7 +226,7 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
break;
@memcpy(dst_map[0..copy_size], src_map[0..copy_size]);
} else if (is_entire_row) {
const slice_size = region.extent.height * src_row_pitch_bytes;
const slice_size = copy_block_height * src_row_pitch_bytes;
var src_slice_memory = src_map[0..];
var dst_slice_memory = dst_map[0..];
@@ -229,7 +238,7 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
dst_slice_memory = if (dst_slice_memory.len < dst_depth_pitch_bytes) break else dst_slice_memory[dst_depth_pitch_bytes..];
}
} else {
const row_size = region.extent.width * bytes_per_block;
const row_size = copy_block_width * bytes_per_block;
var src_slice_memory = src_map[0..];
var dst_slice_memory = dst_map[0..];
@@ -237,7 +246,7 @@ pub fn copyToImageSingleAspect(self: *const Self, dst: *Self, region: vk.ImageCo
var src_row_memory = src_slice_memory[0..];
var dst_row_memory = dst_slice_memory[0..];
for (0..region.extent.height) |_| {
for (0..copy_block_height) |_| {
if (dst_row_memory.len < row_size or src_row_memory.len < row_size)
break;
@memcpy(dst_row_memory[0..row_size], src_row_memory[0..row_size]);
@@ -323,8 +332,12 @@ pub fn copy(
};
const bytes_per_block = base.format.texelSize(format);
const memory_row_pitch_bytes = extent.width * bytes_per_block;
const memory_slice_pitch_bytes = extent.height * memory_row_pitch_bytes;
const copy_block_width = base.format.blockCountX(format, image_extent.width);
const copy_block_height = base.format.blockCountY(format, image_extent.height);
const memory_block_width = base.format.blockCountX(format, extent.width);
const memory_block_height = base.format.blockCountY(format, extent.height);
const memory_row_pitch_bytes = memory_block_width * bytes_per_block;
const memory_slice_pitch_bytes = memory_block_height * memory_row_pitch_bytes;
const image_texel_offset = try self.getTexelMemoryOffset(image_offset, .{
.aspect_mask = image_subresource.aspect_mask,
@@ -346,7 +359,7 @@ pub fn copy(
const layer_count = if (image_subresource.layer_count == vk.REMAINING_ARRAY_LAYERS) self.interface.array_layers - image_subresource.base_array_layer else image_subresource.layer_count;
const copy_size = image_extent.width * bytes_per_block;
const copy_size = copy_block_width * bytes_per_block;
for (0..layer_count) |_| {
var src_layer_memory = src_memory[0..];
@@ -356,7 +369,7 @@ pub fn copy(
var src_slice_memory = src_layer_memory[0..];
var dst_slice_memory = dst_layer_memory[0..];
for (0..image_extent.height) |_| {
for (0..copy_block_height) |_| {
if (dst_slice_memory.len < copy_size or src_slice_memory.len < copy_size)
break;
@memcpy(dst_slice_memory[0..copy_size], src_slice_memory[0..copy_size]);
@@ -375,6 +388,14 @@ pub fn readFloat4(self: *Self, offset: vk.Offset3D, subresource: vk.ImageSubreso
const texel_size = base.format.texelSize(format);
const texel_offset = try self.getTexelMemoryOffset(offset, subresource);
const map = try self.mapAsSliceWithAddedOffset(u8, texel_offset, texel_size);
if (base.format.isCompressed(format)) {
return compressed.readFloat4(
map,
format,
@mod(@as(usize, @intCast(offset.x)), base.format.blockWidth(format)),
@mod(@as(usize, @intCast(offset.y)), base.format.blockHeight(format)),
);
}
return blitter.readFloat4(map, format);
}
@@ -389,6 +410,16 @@ pub fn writeFloat4(self: *Self, offset: vk.Offset3D, subresource: vk.ImageSubres
const texel_size = base.format.texelSize(format);
const texel_offset = try self.getTexelMemoryOffset(offset, subresource);
const map = try self.mapAsSliceWithAddedOffset(u8, texel_offset, texel_size);
if (base.format.isCompressed(format)) {
compressed.writeFloat4(
map,
format,
@mod(@as(usize, @intCast(offset.x)), base.format.blockWidth(format)),
@mod(@as(usize, @intCast(offset.y)), base.format.blockHeight(format)),
pixel,
);
return;
}
blitter.writeFloat4(pixel, map, format);
}
@@ -400,9 +431,10 @@ pub fn writeInt4(self: *Self, offset: vk.Offset3D, subresource: vk.ImageSubresou
}
pub fn getTexelMemoryOffsetInSubresource(self: *const Self, offset: vk.Offset3D, subresource: vk.ImageSubresource) usize {
const format = base.format.fromAspect(self.interface.format, subresource.aspect_mask);
return @as(usize, @intCast(offset.z)) * self.interface.getSliceMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level) +
@as(usize, @intCast(offset.y)) * self.interface.getRowPitchMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level) +
@as(usize, @intCast(offset.x)) * base.format.texelSize(base.format.fromAspect(self.interface.format, subresource.aspect_mask));
@divFloor(@as(usize, @intCast(offset.y)), base.format.blockHeight(format)) * self.interface.getRowPitchMemSizeForMipLevel(subresource.aspect_mask, subresource.mip_level) +
@divFloor(@as(usize, @intCast(offset.x)), base.format.blockWidth(format)) * base.format.texelSize(format);
}
pub fn getTexelMemoryOffset(self: *const Self, offset: vk.Offset3D, subresource: vk.ImageSubresource) VkError!usize {
+46 -16
View File
@@ -335,22 +335,22 @@ pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.
.r32g32b32a32_sfloat,
.b10g11r11_ufloat_pack32,
.e5b9g9r9_ufloat_pack32,
//.bc1_rgb_unorm_block,
//.bc1_rgb_srgb_block,
//.bc1_rgba_unorm_block,
//.bc1_rgba_srgb_block,
//.bc2_unorm_block,
//.bc2_srgb_block,
//.bc3_unorm_block,
//.bc3_srgb_block,
//.bc4_unorm_block,
//.bc4_snorm_block,
//.bc5_unorm_block,
//.bc5_snorm_block,
//.bc6h_ufloat_block,
//.bc6h_sfloat_block,
//.bc7_unorm_block,
//.bc7_srgb_block,
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
.bc2_unorm_block,
.bc2_srgb_block,
.bc3_unorm_block,
.bc3_srgb_block,
.bc4_unorm_block,
.bc4_snorm_block,
.bc5_unorm_block,
.bc5_snorm_block,
.bc6h_ufloat_block,
.bc6h_sfloat_block,
.bc7_unorm_block,
.bc7_srgb_block,
//.etc2_r8g8b8_unorm_block,
//.etc2_r8g8b8_srgb_block,
//.etc2_r8g8b8a1_unorm_block,
@@ -446,6 +446,33 @@ pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.
else => {},
}
switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
.bc2_unorm_block,
.bc2_srgb_block,
.bc3_unorm_block,
.bc3_srgb_block,
.bc4_unorm_block,
.bc4_snorm_block,
.bc5_unorm_block,
.bc5_snorm_block,
.bc6h_ufloat_block,
.bc6h_sfloat_block,
.bc7_unorm_block,
.bc7_srgb_block,
=> {
properties.optimal_tiling_features.blit_src_bit = true;
properties.optimal_tiling_features.sampled_image_bit = true;
properties.optimal_tiling_features.sampled_image_filter_linear_bit = true;
properties.optimal_tiling_features.transfer_dst_bit = true;
properties.optimal_tiling_features.transfer_src_bit = true;
},
else => {},
}
switch (format) {
// Vulkan 1.0 mandatory storage image formats supporting atomic operations
.r32_uint,
@@ -819,6 +846,9 @@ fn isFormatSupported(
tiling: vk.ImageTiling,
usage: vk.ImageUsageFlags,
) VkError!bool {
if (base.format.isCompressed(format) and (usage.transfer_src_bit or usage.transfer_dst_bit))
return false;
const format_properties = try self.interface.getFormatProperties(format);
const format_features = switch (tiling) {
.linear => format_properties.linear_tiling_features,
+273
View File
@@ -0,0 +1,273 @@
const std = @import("std");
const vk = @import("vulkan");
const base = @import("base");
const zm = base.zm;
pub const F32x4 = zm.F32x4;
pub fn isBc1(format: vk.Format) bool {
return switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
=> true,
else => false,
};
}
pub fn readFloat4(block: []const u8, format: vk.Format, x_in_block: usize, y_in_block: usize) F32x4 {
return switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
=> readBc1(block, format, x_in_block, y_in_block),
.bc4_unorm_block,
.bc4_snorm_block,
=> .{ readBc4(block, format, x_in_block, y_in_block), 0.0, 0.0, 1.0 },
.bc5_unorm_block,
.bc5_snorm_block,
=> readBc5(block, format, x_in_block, y_in_block),
else => blk: {
base.unsupported("Compressed read from format {any}", .{format});
break :blk .{ 0.0, 0.0, 0.0, 1.0 };
},
};
}
pub fn writeFloat4(block: []u8, format: vk.Format, x_in_block: usize, y_in_block: usize, color: F32x4) void {
switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
=> writeBc1Texel(block, format, x_in_block, y_in_block, color),
else => base.unsupported("Compressed write to format {any}", .{format}),
}
}
fn readBc1(block: []const u8, format: vk.Format, x_in_block: usize, y_in_block: usize) F32x4 {
std.debug.assert(block.len >= 8);
std.debug.assert(x_in_block < 4);
std.debug.assert(y_in_block < 4);
const color_0 = std.mem.bytesToValue(u16, block[0..2]);
const color_1 = std.mem.bytesToValue(u16, block[2..4]);
const selectors = std.mem.bytesToValue(u32, block[4..8]);
const selector_shift: u5 = @intCast(2 * (y_in_block * 4 + x_in_block));
const selector = (selectors >> selector_shift) & 0x3;
const has_alpha = format == .bc1_rgba_unorm_block or format == .bc1_rgba_srgb_block;
var palette: [4]F32x4 = undefined;
palette[0] = decodeRgb565(color_0);
palette[1] = decodeRgb565(color_1);
if (color_0 > color_1 or !has_alpha) {
palette[2] = mix(palette[0], palette[1], 2.0 / 3.0, 1.0 / 3.0, 1.0);
palette[3] = mix(palette[0], palette[1], 1.0 / 3.0, 2.0 / 3.0, 1.0);
} else {
palette[2] = mix(palette[0], palette[1], 0.5, 0.5, 1.0);
palette[3] = .{ 0.0, 0.0, 0.0, 0.0 };
}
return palette[@intCast(selector)];
}
fn readBc4(block: []const u8, format: vk.Format, x_in_block: usize, y_in_block: usize) f32 {
std.debug.assert(block.len >= 8);
std.debug.assert(x_in_block < 4);
std.debug.assert(y_in_block < 4);
const selector_shift: u6 = @intCast(3 * (y_in_block * 4 + x_in_block));
const selectors = std.mem.bytesToValue(u64, block[0..8]) >> 16;
const selector: usize = @intCast((selectors >> selector_shift) & 0x7);
return switch (format) {
.bc4_unorm_block,
.bc5_unorm_block,
=> readBc4Unorm(block, selector),
.bc4_snorm_block,
.bc5_snorm_block,
=> readBc4Snorm(block, selector),
else => unreachable,
};
}
fn readBc5(block: []const u8, format: vk.Format, x_in_block: usize, y_in_block: usize) F32x4 {
std.debug.assert(block.len >= 16);
return .{
readBc4(block[0..8], format, x_in_block, y_in_block),
readBc4(block[8..16], format, x_in_block, y_in_block),
0.0,
1.0,
};
}
fn readBc4Unorm(block: []const u8, selector: usize) f32 {
const endpoint_0 = @as(f32, @floatFromInt(block[0])) / 255.0;
const endpoint_1 = @as(f32, @floatFromInt(block[1])) / 255.0;
var palette: [8]f32 = undefined;
palette[0] = endpoint_0;
palette[1] = endpoint_1;
if (block[0] > block[1]) {
palette[2] = (6.0 * endpoint_0 + 1.0 * endpoint_1) / 7.0;
palette[3] = (5.0 * endpoint_0 + 2.0 * endpoint_1) / 7.0;
palette[4] = (4.0 * endpoint_0 + 3.0 * endpoint_1) / 7.0;
palette[5] = (3.0 * endpoint_0 + 4.0 * endpoint_1) / 7.0;
palette[6] = (2.0 * endpoint_0 + 5.0 * endpoint_1) / 7.0;
palette[7] = (1.0 * endpoint_0 + 6.0 * endpoint_1) / 7.0;
} else {
palette[2] = (4.0 * endpoint_0 + 1.0 * endpoint_1) / 5.0;
palette[3] = (3.0 * endpoint_0 + 2.0 * endpoint_1) / 5.0;
palette[4] = (2.0 * endpoint_0 + 3.0 * endpoint_1) / 5.0;
palette[5] = (1.0 * endpoint_0 + 4.0 * endpoint_1) / 5.0;
palette[6] = 0.0;
palette[7] = 1.0;
}
return palette[selector];
}
fn readBc4Snorm(block: []const u8, selector: usize) f32 {
const raw_0: i8 = @bitCast(block[0]);
const raw_1: i8 = @bitCast(block[1]);
const endpoint_0 = decodeBcSnorm(raw_0);
const endpoint_1 = decodeBcSnorm(raw_1);
var palette: [8]f32 = undefined;
palette[0] = endpoint_0;
palette[1] = endpoint_1;
if (raw_0 > raw_1) {
palette[2] = (6.0 * endpoint_0 + 1.0 * endpoint_1) / 7.0;
palette[3] = (5.0 * endpoint_0 + 2.0 * endpoint_1) / 7.0;
palette[4] = (4.0 * endpoint_0 + 3.0 * endpoint_1) / 7.0;
palette[5] = (3.0 * endpoint_0 + 4.0 * endpoint_1) / 7.0;
palette[6] = (2.0 * endpoint_0 + 5.0 * endpoint_1) / 7.0;
palette[7] = (1.0 * endpoint_0 + 6.0 * endpoint_1) / 7.0;
} else {
palette[2] = (4.0 * endpoint_0 + 1.0 * endpoint_1) / 5.0;
palette[3] = (3.0 * endpoint_0 + 2.0 * endpoint_1) / 5.0;
palette[4] = (2.0 * endpoint_0 + 3.0 * endpoint_1) / 5.0;
palette[5] = (1.0 * endpoint_0 + 4.0 * endpoint_1) / 5.0;
palette[6] = -1.0;
palette[7] = 1.0;
}
return palette[selector];
}
fn decodeBcSnorm(value: i8) f32 {
return @max(@as(f32, @floatFromInt(value)) / 127.0, -1.0);
}
fn writeBc1Texel(block: []u8, format: vk.Format, x_in_block: usize, y_in_block: usize, color: F32x4) void {
var pixels: [16]F32x4 = undefined;
for (&pixels, 0..) |*pixel, i| {
pixel.* = readBc1(block, format, i & 3, i >> 2);
}
pixels[y_in_block * 4 + x_in_block] = color;
encodeBc1(block, format, pixels);
}
pub fn encodeBc1(block: []u8, format: vk.Format, pixels: [16]F32x4) void {
std.debug.assert(block.len >= 8);
var min_color: F32x4 = .{ 1.0, 1.0, 1.0, 1.0 };
var max_color: F32x4 = .{ 0.0, 0.0, 0.0, 1.0 };
var has_alpha = false;
for (pixels) |pixel| {
if (pixel[3] < 0.5) {
has_alpha = true;
continue;
}
min_color[0] = @min(min_color[0], pixel[0]);
min_color[1] = @min(min_color[1], pixel[1]);
min_color[2] = @min(min_color[2], pixel[2]);
max_color[0] = @max(max_color[0], pixel[0]);
max_color[1] = @max(max_color[1], pixel[1]);
max_color[2] = @max(max_color[2], pixel[2]);
}
var color_0 = encodeRgb565(max_color);
var color_1 = encodeRgb565(min_color);
const supports_alpha = format == .bc1_rgba_unorm_block or format == .bc1_rgba_srgb_block;
if (has_alpha and supports_alpha) {
if (color_0 > color_1)
std.mem.swap(u16, &color_0, &color_1);
} else if (color_0 <= color_1) {
std.mem.swap(u16, &color_0, &color_1);
}
std.mem.bytesAsValue(u16, block[0..2]).* = color_0;
std.mem.bytesAsValue(u16, block[2..4]).* = color_1;
var selectors: u32 = 0;
for (pixels, 0..) |pixel, i| {
const selector = nearestSelector(pixel, color_0, color_1, supports_alpha);
selectors |= @as(u32, selector) << @intCast(2 * i);
}
std.mem.bytesAsValue(u32, block[4..8]).* = selectors;
}
fn nearestSelector(color: F32x4, color_0: u16, color_1: u16, supports_alpha: bool) u2 {
if (supports_alpha and color[3] < 0.5 and color_0 <= color_1)
return 3;
var palette: [4]F32x4 = undefined;
palette[0] = decodeRgb565(color_0);
palette[1] = decodeRgb565(color_1);
if (color_0 > color_1 or !supports_alpha) {
palette[2] = mix(palette[0], palette[1], 2.0 / 3.0, 1.0 / 3.0, 1.0);
palette[3] = mix(palette[0], palette[1], 1.0 / 3.0, 2.0 / 3.0, 1.0);
} else {
palette[2] = mix(palette[0], palette[1], 0.5, 0.5, 1.0);
palette[3] = .{ 0.0, 0.0, 0.0, 0.0 };
}
var best_selector: u2 = 0;
var best_distance = std.math.floatMax(f32);
for (palette, 0..) |entry, i| {
if (i == 3 and supports_alpha and color_0 <= color_1 and color[3] >= 0.5)
continue;
const dr = color[0] - entry[0];
const dg = color[1] - entry[1];
const db = color[2] - entry[2];
const distance = dr * dr + dg * dg + db * db;
if (distance < best_distance) {
best_distance = distance;
best_selector = @intCast(i);
}
}
return best_selector;
}
fn decodeRgb565(value: u16) F32x4 {
return .{
@as(f32, @floatFromInt((value >> 11) & 0x1f)) / 31.0,
@as(f32, @floatFromInt((value >> 5) & 0x3f)) / 63.0,
@as(f32, @floatFromInt(value & 0x1f)) / 31.0,
1.0,
};
}
fn encodeRgb565(color: F32x4) u16 {
const clamped = std.math.clamp(color, zm.f32x4s(0.0), zm.f32x4s(1.0));
const r: u16 = @intFromFloat(@round(clamped[0] * 31.0));
const g: u16 = @intFromFloat(@round(clamped[1] * 63.0));
const b: u16 = @intFromFloat(@round(clamped[2] * 31.0));
return (r << 11) | (g << 5) | b;
}
fn mix(a: F32x4, b: F32x4, a_weight: f32, b_weight: f32, alpha: f32) F32x4 {
return .{
a[0] * a_weight + b[0] * b_weight,
a[1] * a_weight + b[1] * b_weight,
a[2] * a_weight + b[2] * b_weight,
alpha,
};
}
+2 -6
View File
@@ -70,12 +70,8 @@ pub fn shaderInvocation(
};
if (rt.getBuiltinResult(.FragCoord)) |frag_coord_word| {
const pixel_x: i32 = @intFromFloat(position[0]);
const pixel_y: i32 = @intFromFloat(position[1]);
const dx: f32 = if (@mod(pixel_x, 2) == 0) 1.0 else -1.0;
const dy: f32 = if (@mod(pixel_y, 2) == 0) 1.0 else -1.0;
const frag_coord_dx = zm.f32x4(dx, 0.0, 0.0, 0.0);
const frag_coord_dy = zm.f32x4(0.0, dy, 0.0, 0.0);
const frag_coord_dx = zm.f32x4(1.0, 0.0, 0.0, 0.0);
const frag_coord_dy = zm.f32x4(0.0, 1.0, 0.0, 0.0);
try rt.setDerivativeFromMemory(allocator, frag_coord_word, std.mem.asBytes(&frag_coord_dx), std.mem.asBytes(&frag_coord_dy));
}
+146 -4
View File
@@ -40,6 +40,150 @@ pub inline fn texelSize(format: vk.Format) usize {
return lib.c.vkuFormatTexelBlockSize(@intCast(@intFromEnum(format)));
}
pub inline fn isCompressed(format: vk.Format) bool {
return blockWidth(format) > 1 or blockHeight(format) > 1;
}
pub inline fn blockWidth(format: vk.Format) usize {
return switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
.bc2_unorm_block,
.bc2_srgb_block,
.bc3_unorm_block,
.bc3_srgb_block,
.bc4_unorm_block,
.bc4_snorm_block,
.bc5_unorm_block,
.bc5_snorm_block,
.bc6h_ufloat_block,
.bc6h_sfloat_block,
.bc7_unorm_block,
.bc7_srgb_block,
.eac_r11_unorm_block,
.eac_r11_snorm_block,
.eac_r11g11_unorm_block,
.eac_r11g11_snorm_block,
.etc2_r8g8b8_unorm_block,
.etc2_r8g8b8_srgb_block,
.etc2_r8g8b8a1_unorm_block,
.etc2_r8g8b8a1_srgb_block,
.etc2_r8g8b8a8_unorm_block,
.etc2_r8g8b8a8_srgb_block,
.astc_4x_4_unorm_block,
.astc_4x_4_srgb_block,
=> 4,
.astc_5x_4_unorm_block,
.astc_5x_5_unorm_block,
.astc_5x_4_srgb_block,
.astc_5x_5_srgb_block,
=> 5,
.astc_6x_5_unorm_block,
.astc_6x_6_unorm_block,
.astc_6x_5_srgb_block,
.astc_6x_6_srgb_block,
=> 6,
.astc_8x_5_unorm_block,
.astc_8x_6_unorm_block,
.astc_8x_8_unorm_block,
.astc_8x_5_srgb_block,
.astc_8x_6_srgb_block,
.astc_8x_8_srgb_block,
=> 8,
.astc_1_0x_5_unorm_block,
.astc_1_0x_6_unorm_block,
.astc_1_0x_8_unorm_block,
.astc_1_0x_10_unorm_block,
.astc_1_0x_5_srgb_block,
.astc_1_0x_6_srgb_block,
.astc_1_0x_8_srgb_block,
.astc_1_0x_10_srgb_block,
=> 10,
.astc_1_2x_10_unorm_block,
.astc_1_2x_12_unorm_block,
.astc_1_2x_10_srgb_block,
.astc_1_2x_12_srgb_block,
=> 12,
else => 1,
};
}
pub inline fn blockHeight(format: vk.Format) usize {
return switch (format) {
.bc1_rgb_unorm_block,
.bc1_rgb_srgb_block,
.bc1_rgba_unorm_block,
.bc1_rgba_srgb_block,
.bc2_unorm_block,
.bc2_srgb_block,
.bc3_unorm_block,
.bc3_srgb_block,
.bc4_unorm_block,
.bc4_snorm_block,
.bc5_unorm_block,
.bc5_snorm_block,
.bc6h_ufloat_block,
.bc6h_sfloat_block,
.bc7_unorm_block,
.bc7_srgb_block,
.eac_r11_unorm_block,
.eac_r11_snorm_block,
.eac_r11g11_unorm_block,
.eac_r11g11_snorm_block,
.etc2_r8g8b8_unorm_block,
.etc2_r8g8b8_srgb_block,
.etc2_r8g8b8a1_unorm_block,
.etc2_r8g8b8a1_srgb_block,
.etc2_r8g8b8a8_unorm_block,
.etc2_r8g8b8a8_srgb_block,
.astc_4x_4_unorm_block,
.astc_5x_4_unorm_block,
.astc_4x_4_srgb_block,
.astc_5x_4_srgb_block,
=> 4,
.astc_5x_5_unorm_block,
.astc_6x_5_unorm_block,
.astc_8x_5_unorm_block,
.astc_1_0x_5_unorm_block,
.astc_5x_5_srgb_block,
.astc_6x_5_srgb_block,
.astc_8x_5_srgb_block,
.astc_1_0x_5_srgb_block,
=> 5,
.astc_6x_6_unorm_block,
.astc_8x_6_unorm_block,
.astc_1_0x_6_unorm_block,
.astc_6x_6_srgb_block,
.astc_8x_6_srgb_block,
.astc_1_0x_6_srgb_block,
=> 6,
.astc_8x_8_unorm_block,
.astc_1_0x_8_unorm_block,
.astc_8x_8_srgb_block,
.astc_1_0x_8_srgb_block,
=> 8,
.astc_1_0x_10_unorm_block,
.astc_1_2x_10_unorm_block,
.astc_1_0x_10_srgb_block,
.astc_1_2x_10_srgb_block,
=> 10,
.astc_1_2x_12_unorm_block,
.astc_1_2x_12_srgb_block,
=> 12,
else => 1,
};
}
pub inline fn blockCountX(format: vk.Format, width: usize) usize {
return std.math.divCeil(usize, width, blockWidth(format)) catch unreachable;
}
pub inline fn blockCountY(format: vk.Format, height: usize) usize {
return std.math.divCeil(usize, height, blockHeight(format)) catch unreachable;
}
pub inline fn componentCount(format: vk.Format) usize {
return @intCast(lib.c.vkuFormatComponentCount(@intCast(@intFromEnum(format))));
}
@@ -83,13 +227,11 @@ pub fn supportsColorAttachemendBlend(format: vk.Format) bool {
}
pub inline fn pitchMemSize(format: vk.Format, width: usize) usize {
// To be updated for compressed formats handling
return texelSize(format) * width;
return texelSize(format) * blockCountX(format, width);
}
pub inline fn sliceMemSize(format: vk.Format, width: usize, height: usize) usize {
// To be updated for compressed formats handling
return pitchMemSize(format, width) * height;
return pitchMemSize(format, width) * blockCountY(format, height);
}
pub inline fn isDepthAndStencil(format: vk.Format) bool {