From 4cd90d8ebb8c7a96975fc6f4747c84b1e4a6f4dd Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Mon, 13 Nov 2023 14:37:38 +0100 Subject: [PATCH] rend: yet another hash fix of vq textures The calculated size for vq textures was half the correct value, which affects the texture hash. Calculate the old hash and use it as fallback for backward-compatibility. Issue #1291 Make the texture data start address really point to max mipmap data, no more codebook skipping. --- core/rend/TexCache.cpp | 79 ++++++++++++++++++------------------ core/rend/TexCache.h | 10 ++--- core/rend/boxart/pvrparser.h | 8 ++-- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp index 6709032b5..62459aac2 100644 --- a/core/rend/TexCache.cpp +++ b/core/rend/TexCache.cpp @@ -338,17 +338,17 @@ static const PvrTexInfo *pvrTexInfo = opengl::pvrTexInfo; extern const u32 VQMipPoint[11] = { - 0x00000,//1 - 0x00001,//2 - 0x00002,//4 - 0x00006,//8 - 0x00016,//16 - 0x00056,//32 - 0x00156,//64 - 0x00556,//128 - 0x01556,//256 - 0x05556,//512 - 0x15556//1024 + VQ_CODEBOOK_SIZE + 0x00000, // 1 + VQ_CODEBOOK_SIZE + 0x00001, // 2 + VQ_CODEBOOK_SIZE + 0x00002, // 4 + VQ_CODEBOOK_SIZE + 0x00006, // 8 + VQ_CODEBOOK_SIZE + 0x00016, // 16 + VQ_CODEBOOK_SIZE + 0x00056, // 32 + VQ_CODEBOOK_SIZE + 0x00156, // 64 + VQ_CODEBOOK_SIZE + 0x00556, // 128 + VQ_CODEBOOK_SIZE + 0x01556, // 256 + VQ_CODEBOOK_SIZE + 0x05556, // 512 + VQ_CODEBOOK_SIZE + 0x15556 // 1024 }; extern const u32 OtherMipPoint[11] = { @@ -410,22 +410,22 @@ bool BaseTextureCacheData::NeedsUpdate() { void BaseTextureCacheData::protectVRam() { - u32 end = sa + size - 1; + u32 end = mmStartAddress + size - 1; if (end >= VRAM_SIZE) { WARN_LOG(PVR, "protectVRam: end >= VRAM_SIZE. Tried to lock area out of vram"); end = VRAM_SIZE - 1; } - if (sa_tex > end) + if (startAddress > end) { - WARN_LOG(PVR, "vramlock_Lock: sa_tex > end. Tried to lock negative block"); + WARN_LOG(PVR, "vramlock_Lock: startAddress > end. Tried to lock negative block"); return; } vram_block *block = new vram_block(); block->end = end; - block->start = sa_tex; + block->start = startAddress; block->texture = this; { @@ -482,8 +482,8 @@ BaseTextureCacheData::BaseTextureCacheData(TSP tsp, TCW tcw) //decode info from tsp/tcw into the texture struct tex = &pvrTexInfo[tcw.PixelFmt == PixelReserved ? Pixel1555 : tcw.PixelFmt]; //texture format table entry - sa_tex = (tcw.TexAddr << 3) & VRAM_MASK; //texture start address - sa = sa_tex; //data texture start address (modified for MIPs, as needed) + startAddress = (tcw.TexAddr << 3) & VRAM_MASK; // texture start address + mmStartAddress = startAddress; // data texture start address (modified for MIPs, as needed) width = 8 << tsp.TexU; //tex width height = 8 << tsp.TexV; //tex height @@ -534,16 +534,18 @@ BaseTextureCacheData::BaseTextureCacheData(TSP tsp, TCW tcw) { verify(tex->VQ != NULL || tex->VQ32 != NULL); if (tcw.MipMapped) - sa += VQMipPoint[tsp.TexU + 3]; + mmStartAddress += VQMipPoint[tsp.TexU + 3]; + else + mmStartAddress += VQ_CODEBOOK_SIZE; texconv = tex->VQ; texconv32 = tex->VQ32; - size = width * height / 8 + 256 * 8; + size = width * height / 4; } else { verify(tex->TW != NULL || tex->TW32 != NULL); if (tcw.MipMapped) - sa += OtherMipPoint[tsp.TexU + 3] * tex->bpp / 8; + mmStartAddress += OtherMipPoint[tsp.TexU + 3] * tex->bpp / 8; texconv = tex->TW; texconv32 = tex->TW32; size = width * height * tex->bpp / 8; @@ -556,14 +558,13 @@ void BaseTextureCacheData::ComputeHash() { // Include everything but texaddr, reserved and stride. Palette textures don't have ScanOrder const u32 tcwMask = IsPaletted() ? 0xF8000000 : 0xFC000000; - u32 hashSize = size; if (tcw.VQ_Comp) { // The size for VQ textures wasn't correctly calculated. // We use the old size to compute the hash for backward-compatibility // with existing custom texture packs. - hashSize = size - 256 * 8; - old_vqtexture_hash = XXH32(&vram[sa], hashSize, 7); + int oldSize = width * height / 8; + old_vqtexture_hash = XXH32(&vram[mmStartAddress - VQ_CODEBOOK_SIZE], oldSize, 7); if (IsPaletted()) old_vqtexture_hash ^= palette_hash; old_texture_hash = old_vqtexture_hash; @@ -572,9 +573,9 @@ void BaseTextureCacheData::ComputeHash() XXH32_state_t *state = XXH32_createState(); XXH32_reset(state, 7); // hash vq codebook - XXH32_update(state, &vram[sa_tex], 256 * 8); + XXH32_update(state, &vram[startAddress], VQ_CODEBOOK_SIZE); // hash texture - XXH32_update(state, &vram[sa + 256 * 8], hashSize); + XXH32_update(state, &vram[mmStartAddress], size); texture_hash = XXH32_digest(state); XXH32_freeState(state); if (IsPaletted()) @@ -584,7 +585,7 @@ void BaseTextureCacheData::ComputeHash() else { old_vqtexture_hash = 0; - texture_hash = XXH32(&vram[sa], hashSize, 7); + texture_hash = XXH32(&vram[mmStartAddress], size, 7); if (IsPaletted()) texture_hash ^= palette_hash; old_texture_hash = texture_hash; @@ -630,7 +631,7 @@ bool BaseTextureCacheData::Update() } if (tcw.VQ_Comp) - ::vq_codebook = &vram[sa_tex]; // might be used if VQ tex + ::vq_codebook = &vram[startAddress]; //texture conversion work u32 stride = width; @@ -643,19 +644,19 @@ bool BaseTextureCacheData::Update() } const u32 original_h = height; - if (sa_tex > VRAM_SIZE || sa + size > VRAM_SIZE) + if (startAddress > VRAM_SIZE || mmStartAddress + size > VRAM_SIZE) { height = 0; - if (sa < VRAM_SIZE && sa + size > VRAM_SIZE && tcw.ScanOrder) + if (mmStartAddress < VRAM_SIZE && mmStartAddress + size > VRAM_SIZE && tcw.ScanOrder) { // Shenmue Space Harrier mini-arcade loads a texture that goes beyond the end of VRAM // but only uses the top portion of it - height = (VRAM_SIZE - sa) * 8 / stride / tex->bpp; + height = (VRAM_SIZE - mmStartAddress) * 8 / stride / tex->bpp; size = stride * height * tex->bpp/8; } if (height == 0) { - WARN_LOG(RENDERER, "Warning: invalid texture. Address %08X %08X size %d", sa_tex, sa, size); + WARN_LOG(RENDERER, "Warning: invalid texture. Address %08X %08X size %d", startAddress, mmStartAddress, size); dirty = 1; height = original_h; unprotectVRam(); @@ -706,7 +707,7 @@ bool BaseTextureCacheData::Update() u32 vram_addr; if (tcw.VQ_Comp) { - vram_addr = sa_tex + VQMipPoint[i]; + vram_addr = startAddress + VQMipPoint[i]; if (i == 0) { PixelBuffer pb0; @@ -717,7 +718,7 @@ bool BaseTextureCacheData::Update() } } else - vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8; + vram_addr = startAddress + OtherMipPoint[i] * tex->bpp / 8; if (tcw.PixelFmt == PixelYUV && i == 0) // Special case for YUV at 1x1 LoD pvrTexInfo[Pixel565].TW32(&pb32, &vram[vram_addr], 1, 1); @@ -729,7 +730,7 @@ bool BaseTextureCacheData::Update() else { pb32.init(width, height); - texconv32(&pb32, (u8*)&vram[sa], stride, height); + texconv32(&pb32, (u8*)&vram[mmStartAddress], stride, height); // xBRZ scaling if (textureUpscaling) @@ -757,7 +758,7 @@ bool BaseTextureCacheData::Update() for (u32 i = 0; i <= tsp.TexU + 3u; i++) { pb8.set_mipmap(i); - u32 vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8; + u32 vram_addr = startAddress + OtherMipPoint[i] * tex->bpp / 8; texconv8(&pb8, &vram[vram_addr], 1 << i, 1 << i); } pb8.set_mipmap(0); @@ -765,7 +766,7 @@ bool BaseTextureCacheData::Update() else { pb8.init(width, height); - texconv8(&pb8, &vram[sa], stride, height); + texconv8(&pb8, &vram[mmStartAddress], stride, height); } temp_tex_buffer = pb8.data(); } @@ -780,7 +781,7 @@ bool BaseTextureCacheData::Update() u32 vram_addr; if (tcw.VQ_Comp) { - vram_addr = sa_tex + VQMipPoint[i]; + vram_addr = startAddress + VQMipPoint[i]; if (i == 0) { PixelBuffer pb0; @@ -791,7 +792,7 @@ bool BaseTextureCacheData::Update() } } else - vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8; + vram_addr = startAddress + OtherMipPoint[i] * tex->bpp / 8; texconv(&pb16, (u8*)&vram[vram_addr], 1 << i, 1 << i); } pb16.set_mipmap(0); @@ -799,7 +800,7 @@ bool BaseTextureCacheData::Update() else { pb16.init(width, height); - texconv(&pb16,(u8*)&vram[sa],stride,height); + texconv(&pb16,(u8*)&vram[mmStartAddress],stride,height); } temp_tex_buffer = pb16.data(); } diff --git a/core/rend/TexCache.h b/core/rend/TexCache.h index 62ebb8f10..f25ace56b 100644 --- a/core/rend/TexCache.h +++ b/core/rend/TexCache.h @@ -12,6 +12,7 @@ #include extern const u8 *vq_codebook; +constexpr int VQ_CODEBOOK_SIZE = 256 * 8; extern u32 palette_index; extern u32 palette16_ram[1024]; extern u32 palette32_ram[1024]; @@ -446,7 +447,6 @@ void texture_TW(PixelBuffer* pb, const u template void texture_VQ(PixelBuffer* pb, const u8* p_in, u32 Width, u32 Height) { - p_in += 256 * 4 * 2; // Skip VQ codebook pb->amove(0, 0); const u32 divider = PixelConvertor::xpp * PixelConvertor::ypp; @@ -578,10 +578,10 @@ public: tsp = other.tsp; tcw = other.tcw; tex_type = other.tex_type; - sa_tex = other.sa_tex; + startAddress = other.startAddress; dirty = other.dirty; std::swap(lock_block, other.lock_block); - sa = other.sa; + mmStartAddress = other.mmStartAddress; width = other.width; height = other.height; size = other.size; @@ -605,12 +605,12 @@ public: // Decoded/filtered texture format TextureType tex_type; - u32 sa_tex; // texture data start address in vram + u32 startAddress; // texture data start address in vram u32 dirty; // frame number at which texture was overwritten vram_block* lock_block; - u32 sa; // pixel data start address of max level mipmap + u32 mmStartAddress; // pixel data start address of max level mipmap u16 width, height; // width & height of the texture u32 size; // size in bytes of max level mipmap in vram diff --git a/core/rend/boxart/pvrparser.h b/core/rend/boxart/pvrparser.h index 04590a6fd..3cf699553 100644 --- a/core/rend/boxart/pvrparser.h +++ b/core/rend/boxart/pvrparser.h @@ -141,12 +141,12 @@ static bool pvrParse(const u8 *data, u32 len, u32& width, u32& height, std::vect p += (OtherMipPoint[texU] - 2) * 2; else if (imgType == PvrVQMipmaps) p += VQMipPoint[texU]; + else if (imgType == PvrVQ) + p += VQ_CODEBOOK_SIZE; u32 expectedSize = width * height; - if (imgType == PvrVQ || imgType == PvrVQMipmaps) { - expectedSize /= 4; // 4 pixels per byte - expectedSize += 256 * 4 * 2; // VQ codebook size - } + if (imgType == PvrVQ || imgType == PvrVQMipmaps) + expectedSize /= 4; // 4 pixels per byte else expectedSize *= 2; // 2 bytes per pixel if (end - p < expectedSize)