aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/textures/astc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/textures/astc.cpp')
-rw-r--r--src/video_core/textures/astc.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index 0b6d06c49a..950ce28d6b 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -2038,4 +2038,69 @@ void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height,
}
}
+bool IsOpaque(std::span<const uint8_t> data) {
+ // Endpoint modes with an alpha channel: LDR luminance+alpha (4, 5), RGB scale + two alpha
+ // (10), LDR RGBA (12, 13) and HDR RGBA (14, 15).
+ constexpr u32 AlphaModes = (1U << 4) | (1U << 5) | (1U << 10) | (1U << 12) | (1U << 13) |
+ (1U << 14) | (1U << 15);
+ for (size_t offset = 0; offset + 16 <= data.size(); offset += 16) {
+ const std::span<const u8> block = data.subspan(offset, 16);
+ InputBitStream strm(block);
+ const TexelWeightParams params = DecodeBlockInfo(strm);
+ if (params.m_bError) {
+ continue; // decodes to the opaque error colour
+ }
+ if (params.m_bVoidExtentLDR || params.m_bVoidExtentHDR) {
+ // One RGBA16 colour in bits 64-127: UNORM16, or FP16 for HDR.
+ const u32 alpha = block[14] | (u32{block[15]} << 8);
+ if (alpha != (params.m_bVoidExtentHDR ? 0x3C00U : 0xFFFFU)) {
+ return false;
+ }
+ continue;
+ }
+ const u32 partitions = strm.ReadBits<2>() + 1;
+ if (partitions == 4 && params.m_bDualPlane) {
+ continue;
+ }
+ if (partitions == 1) {
+ if ((AlphaModes >> strm.ReadBits<4>()) & 1) {
+ return false;
+ }
+ continue;
+ }
+ strm.ReadBits<10>(); // partition index
+ const u32 base_cem = strm.ReadBits<6>();
+ const u32 base_mode = base_cem & 3;
+ if (base_mode == 0) {
+ if ((AlphaModes >> (base_cem >> 2)) & 1) {
+ return false;
+ }
+ continue;
+ }
+ // The rest of the per-partition modes sit just below the weights (DecompressBlock).
+ const u32 weight_bits = params.GetPackedBitSize();
+ if (weight_bits < 24 || weight_bits > 96) {
+ continue;
+ }
+ const u32 extra_bits = partitions == 2 ? 2 : partitions == 3 ? 5 : 8;
+ const u32 extra_offset = 128 - weight_bits - extra_bits;
+ u32 extra = 0;
+ for (u32 bit = 0; bit < extra_bits; ++bit) {
+ const u32 position = extra_offset + bit;
+ extra |= ((block[position / 8] >> (position % 8)) & 1U) << bit;
+ }
+ u32 cem = ((extra << 6) | base_cem) >> 2;
+ const u32 classes = cem;
+ cem >>= partitions;
+ for (u32 i = 0; i < partitions; ++i) {
+ const u32 mode = ((base_mode - (((classes >> i) & 1) != 0 ? 0 : 1)) << 2) |
+ ((cem >> (2 * i)) & 3);
+ if ((AlphaModes >> mode) & 1) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
} // namespace Tegra::Texture::ASTC