aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/textures/astc.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 19:32:48 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 19:32:48 -0400
commit2bd0285a383652b086f51ef779f083f0bce62670 (patch)
treebe36f7c4d86f893baeebbc3bc542a6009c4b9871 /src/video_core/textures/astc.cpp
parentdcf9ed1b33352a27fceef84c3cf9292424c658db (diff)
Texture cache: stop the churn, the per-frame image leak and garbage textures
- Unmapped GPU addresses get a stand-in CPU address fixed by the GPU address. A fresh one per lookup meant FindImage never found an image there again: title 1's bloom chain at 0xf0000-0x15b600 was re-created on every use (~5,400 images per 600 frames), filling VRAM. - ASTC whose blocks carry no alpha (exact endpoint-mode scan reusing the decoder's block parsing) is re-compressed to BC1 instead of BC3, half the size; about 70% of title 1's ASTC qualifies. Copies between BC1 and BC3 hosts are skipped (their guest data is uploaded instead). EDEN_NX2_ASTC_BC1=0 turns it off. - Deleting an image cancels every decode still queued for it. An image re-decoded mid-decode has two; the first to finish cleared IsDecoding, the second was not cancelled and was uploaded into the next image to take the slot: garbage textures (the title logo, road patches) and a staging overrun when that image was smaller. - Diagnostics: images created and deleted per 600 frames by shape, collector deletions, async decodes, BC1/BC3 split; collector thresholds overridable (EDEN_NX2_TC_EXPECTED_MIB/CRITICAL_MIB); GPU ASTC decode wait timing (EDEN_NX2_ASTC_FLUSH=1 submits without it). Title 1 attract loop: device memory 4.8-5.1 GB instead of 5.9-6.1 GB, no decoded textures evicted, ~17 -> 22-23 fps.
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