diff --git a/core/hw/pvr/pvr_regs.cpp b/core/hw/pvr/pvr_regs.cpp index d8f6cbff4..42917a9f8 100644 --- a/core/hw/pvr/pvr_regs.cpp +++ b/core/hw/pvr/pvr_regs.cpp @@ -6,10 +6,6 @@ bool pal_needs_update=true; bool fog_needs_update=true; -u32 _pal_rev_256[4]={0}; -u32 _pal_rev_16[64]={0}; -u32 pal_rev_256[4]={0}; -u32 pal_rev_16[64]={0}; u8 pvr_regs[pvr_RegSize]; @@ -95,16 +91,9 @@ void pvr_WriteReg(u32 paddr,u32 data) return; } - if (addr>=PALETTE_RAM_START_addr) + if (addr>=PALETTE_RAM_START_addr && PvrReg(addr,u32)!=data) { - if (PvrReg(addr,u32)!=data) - { - u32 pal=(addr/4)&1023; - - pal_needs_update=true; - _pal_rev_256[pal>>8]++; - _pal_rev_16[pal>>4]++; - } + pal_needs_update=true; } if (addr>=FOG_TABLE_START_addr && addr<=FOG_TABLE_END_addr && PvrReg(addr,u32)!=data) diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp index 8b4fa96c5..a49d6adee 100644 --- a/core/rend/TexCache.cpp +++ b/core/rend/TexCache.cpp @@ -14,6 +14,8 @@ u32 palette_index; bool KillTex=false; u32 palette16_ram[1024]; u32 palette32_ram[1024]; +u32 pal_hash_256[4]; +u32 pal_hash_16[64]; u32 detwiddle[2][8][1024]; //input : address in the yyyyyxxxxx format @@ -70,12 +72,25 @@ void BuildTwiddleTables() static OnLoad btt(&BuildTwiddleTables); +// FNV-1a hashing algorithm +#define HASH_OFFSET 2166136261 +#define HASH_PRIME 16777619 + +#define HASH_PALETTE(palette_hash, bpp) do { u32 &hash = palette_hash[i >> bpp]; \ + if ((i & ((1 << bpp) - 1)) == 0) \ + hash = HASH_OFFSET; \ + u8 *p = (u8 *)&palette32_ram[i]; \ + hash = (hash ^ p[0]) * HASH_PRIME; \ + hash = (hash ^ p[1]) * HASH_PRIME; \ + hash = (hash ^ p[2]) * HASH_PRIME; \ + hash = (hash ^ p[3]) * HASH_PRIME; } while (false) +#define HASH_PALETTE_16() HASH_PALETTE(pal_hash_16, 4) +#define HASH_PALETTE_256() HASH_PALETTE(pal_hash_256, 8) + void palette_update() { if (pal_needs_update==false) return; - memcpy(pal_rev_256,_pal_rev_256,sizeof(pal_rev_256)); - memcpy(pal_rev_16,_pal_rev_16,sizeof(pal_rev_16)); pal_needs_update=false; switch(PAL_RAM_CTRL&3) @@ -85,6 +100,8 @@ void palette_update() { palette16_ram[i] = ARGB1555(PALETTE_RAM[i]); palette32_ram[i] = ARGB1555_32(PALETTE_RAM[i]); + HASH_PALETTE_16(); + HASH_PALETTE_256(); } break; @@ -93,6 +110,8 @@ void palette_update() { palette16_ram[i] = ARGB565(PALETTE_RAM[i]); palette32_ram[i] = ARGB565_32(PALETTE_RAM[i]); + HASH_PALETTE_16(); + HASH_PALETTE_256(); } break; @@ -101,6 +120,8 @@ void palette_update() { palette16_ram[i] = ARGB4444(PALETTE_RAM[i]); palette32_ram[i] = ARGB4444_32(PALETTE_RAM[i]); + HASH_PALETTE_16(); + HASH_PALETTE_256(); } break; @@ -109,6 +130,8 @@ void palette_update() { palette16_ram[i] = ARGB8888(PALETTE_RAM[i]); palette32_ram[i] = ARGB8888_32(PALETTE_RAM[i]); + HASH_PALETTE_16(); + HASH_PALETTE_256(); } break; } diff --git a/core/rend/TexCache.h b/core/rend/TexCache.h index 52a2a0c17..d87481260 100644 --- a/core/rend/TexCache.h +++ b/core/rend/TexCache.h @@ -6,10 +6,8 @@ extern u32 palette_index; extern u32 palette16_ram[1024]; extern u32 palette32_ram[1024]; extern bool pal_needs_update,fog_needs_update,KillTex; -extern u32 pal_rev_256[4]; -extern u32 pal_rev_16[64]; -extern u32 _pal_rev_256[4]; -extern u32 _pal_rev_16[64]; +extern u32 pal_hash_256[4]; +extern u32 pal_hash_16[64]; extern u32 detwiddle[2][8][1024]; diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index b48a873b4..28da0ee05 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -238,8 +238,7 @@ struct TextureCacheData u32 Updates; //used for palette updates - u32 pal_local_rev; //local palette rev - u32* pal_table_rev; //table palette rev pointer + u32 palette_hash; // Palette hash at time of last update u32 indirect_color_ptr; //palette color table index for pal. tex //VQ quantizers table for VQ tex //a texture can't be both VQ and PAL at the same time @@ -264,6 +263,11 @@ struct TextureCacheData printf(" id=%d\n", texID); } + bool IsPaletted() + { + return tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8; + } + //Create GL texture from tsp/tcw void Create(bool isGL) { @@ -294,19 +298,9 @@ struct TextureCacheData //PAL texture if (tex->bpp==4) - { - pal_table_rev=&pal_rev_16[tcw.PalSelect]; indirect_color_ptr=tcw.PalSelect<<4; - } else if (tex->bpp==8) - { - pal_table_rev=&pal_rev_256[tcw.PalSelect>>4]; indirect_color_ptr=(tcw.PalSelect>>4)<<8; - } - else - { - pal_table_rev=0; - } //VQ table (if VQ tex) if (tcw.VQ_Comp) @@ -383,12 +377,17 @@ struct TextureCacheData GLuint textype=tex->type; bool has_alpha = false; - if (pal_table_rev) + if (IsPaletted()) { textype=PAL_TYPE[PAL_RAM_CTRL&3]; - pal_local_rev=*pal_table_rev; //make sure to update the local rev, so it won't have to redo the tex if (textype == GL_UNSIGNED_INT_8_8_8_8) has_alpha = true; + + // Get the palette hash to check for future updates + if (tcw.PixelFmt == PixelPal4) + palette_hash = pal_hash_16[tcw.PalSelect]; + else + palette_hash = pal_hash_256[tcw.PalSelect >> 4]; } palette_index=indirect_color_ptr; //might be used if pal. tex @@ -420,7 +419,7 @@ struct TextureCacheData || w * h > settings.rend.MaxFilteredTextureSize * settings.rend.MaxFilteredTextureSize // Don't process textures that are too big || tcw.PixelFmt == PixelYUV) // Don't process YUV textures - && (pal_table_rev == NULL || textype != GL_UNSIGNED_INT_8_8_8_8) + && (!IsPaletted() || textype != GL_UNSIGNED_INT_8_8_8_8) && texconv != NULL) need_32bit_buffer = false; // TODO avoid upscaling/depost. textures that change too often @@ -526,8 +525,13 @@ struct TextureCacheData } } - //true if : dirty or paletted texture and revs don't match - bool NeedsUpdate() { return (dirty) || (pal_table_rev!=0 && *pal_table_rev!=pal_local_rev); } + //true if : dirty or paletted texture and hashes don't match + bool NeedsUpdate() { + bool rc = dirty + || (tcw.PixelFmt == PixelPal4 && palette_hash != pal_hash_16[tcw.PalSelect]) + || (tcw.PixelFmt == PixelPal8 && palette_hash != pal_hash_256[tcw.PalSelect >> 4]); + return rc; + } void Delete() { @@ -800,7 +804,10 @@ TextureCacheData *getTextureCacheData(TSP tsp, TCW tcw) { u64 key = tsp.full & TSPTextureCacheMask.full; if (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8) // Paletted textures have a palette selection that must be part of the key - key |= (u64)tcw.full << 32; + // We also add the palette type to the key to avoid thrashing the cache + // when the palette type is changed. If the palette type is changed back in the future, + // this texture will stil be available. + key |= ((u64)tcw.full << 32) | ((PAL_RAM_CTRL & 3) << 6); else key |= (u64)(tcw.full & TCWTextureCacheMask.full) << 32;