Skip to content

Commit

Permalink
rend: yet another hash fix of vq textures
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
flyinghead committed Nov 13, 2023
1 parent 46eab50 commit 4cd90d8
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 48 deletions.
79 changes: 40 additions & 39 deletions core/rend/TexCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
{
Expand Down Expand Up @@ -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;

{
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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())
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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<u32> pb0;
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -757,15 +758,15 @@ 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);
}
else
{
pb8.init(width, height);
texconv8(&pb8, &vram[sa], stride, height);
texconv8(&pb8, &vram[mmStartAddress], stride, height);
}
temp_tex_buffer = pb8.data();
}
Expand All @@ -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<u16> pb0;
Expand All @@ -791,15 +792,15 @@ 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);
}
else
{
pb16.init(width, height);
texconv(&pb16,(u8*)&vram[sa],stride,height);
texconv(&pb16,(u8*)&vram[mmStartAddress],stride,height);
}
temp_tex_buffer = pb16.data();
}
Expand Down
10 changes: 5 additions & 5 deletions core/rend/TexCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <utility>

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];
Expand Down Expand Up @@ -446,7 +447,6 @@ void texture_TW(PixelBuffer<typename PixelConvertor::unpacked_type>* pb, const u
template<class PixelConvertor>
void texture_VQ(PixelBuffer<typename PixelConvertor::unpacked_type>* 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;
Expand Down Expand Up @@ -578,10 +578,10 @@ class BaseTextureCacheData
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;
Expand All @@ -605,12 +605,12 @@ class BaseTextureCacheData

// 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

Expand Down
8 changes: 4 additions & 4 deletions core/rend/boxart/pvrparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 4cd90d8

Please sign in to comment.