From 5b61c03b7fa38685b39a445b6e54a85fcac3a509 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:11:47 -0700 Subject: [PATCH 1/6] Avoid accidental sign ext for > 24 bit clut shift. --- GPU/Common/DepalettizeShaderCommon.cpp | 2 +- GPU/GPUState.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 48e1a375fa..e511f42ee9 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -88,7 +88,7 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat) { texturePixels = 512; if (shift) { - WRITE(p, " index = ((index >> %i) & 0x%02x)", shift, mask); + WRITE(p, " index = (int(uint(index) >> %i) & 0x%02x)", shift, mask); } else { WRITE(p, " index = (index & 0x%02x)", mask); } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 36f71cc6db..0559f84bda 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -309,7 +309,7 @@ struct GPUgstate int getClutIndexShift() const { return (clutformat >> 2) & 0x1F; } int getClutIndexMask() const { return (clutformat >> 8) & 0xFF; } int getClutIndexStartPos() const { return ((clutformat >> 16) & 0x1F) << 4; } - int transformClutIndex(int index) const { return ((index >> getClutIndexShift()) & getClutIndexMask()) | getClutIndexStartPos(); } + u32 transformClutIndex(u32 index) const { return ((index >> getClutIndexShift()) & getClutIndexMask()) | getClutIndexStartPos(); } bool isClutIndexSimple() const { return (clutformat & ~3) == 0xC500FF00; } // Meaning, no special mask, shift, or start pos. bool isTextureSwizzled() const { return texmode & 1; } bool isClutSharedForMipmaps() const { return (texmode & 0x100) == 0; } From c8fc9b0bf3cc55900289c271d6f65fbbb79e8284 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:31:00 -0700 Subject: [PATCH 2/6] Cleanup some incorrect handling of clut offset. --- GPU/Common/DepalettizeShaderCommon.cpp | 1 + GPU/Directx9/TextureCacheDX9.cpp | 5 ++--- GPU/GLES/TextureCache.cpp | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index e511f42ee9..36bd191a97 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -213,6 +213,7 @@ void GenerateDepalShaderFloat(char *buffer, GEBufferFormat pixelFormat, ShaderLa } // Offset by half a texel (plus clutBase) to turn NEAREST filtering into FLOOR. + // Technically, the clutBase should be |'d, not added, but that's hard with floats. float texel_offset = ((float)clutBase + 0.5f) / texturePixels; sprintf(offset, " + %f", texel_offset); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index ab26b71b3f..37a8c57425 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -973,11 +973,10 @@ void TextureCacheDX9::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebu dxstate.viewport.restore(); const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - const u32 clutBase = gstate.getClutIndexStartPos(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); - const u32 clutExtendedColors = (clutTotalBytes_ / bytesPerColor) + clutBase; + const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; - TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(gstate.getClutPaletteFormat()), clutExtendedColors, clutExtendedColors, 1); + TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(gstate.getClutPaletteFormat()), clutTotalColors, clutTotalColors, 1); gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL; gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE; } else { diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 0939ca8f47..db059644d5 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -992,13 +992,18 @@ void TextureCache::UpdateCurrentClut() { const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. + // + // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. + // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash + // unrelated old entries for small palettes. + // Adding clutBaseBytes may just be mitigating this for some usage patterns. const u32 clutExtendedBytes = clutTotalBytes_ + clutBaseBytes; clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); // Avoid a copy when we don't need to convert colors. if (UseBGRA8888() || clutFormat != GE_CMODE_32BIT_ABGR8888) { - const int numColors = (clutMaxBytes_ + clutBaseBytes) / (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); + const int numColors = clutMaxBytes_ / (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); ConvertColors(clutBufConverted_, clutBufRaw_, getClutDestFormat(clutFormat), numColors); clutBuf_ = clutBufConverted_; } else { @@ -1147,11 +1152,10 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffe framebufferManager_->RebindFramebuffer(); const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); - const u32 clutBase = gstate.getClutIndexStartPos(); const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); - const u32 clutExtendedColors = (clutTotalBytes_ / bytesPerColor) + clutBase; + const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; - TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(gstate.getClutPaletteFormat()), clutExtendedColors, clutExtendedColors, 1); + TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormat(gstate.getClutPaletteFormat()), clutTotalColors, clutTotalColors, 1); gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL; gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE; } else { From 6e50a0b2743da8d7486ad5e400e9962962f3976e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:36:08 -0700 Subject: [PATCH 3/6] Allow depal palette entries to repeat. This is what happens if the base is 0x10 in 8888 mode (means | 0x100.) --- GPU/Directx9/DepalettizeShaderDX9.cpp | 2 +- GPU/GLES/DepalettizeShader.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Directx9/DepalettizeShaderDX9.cpp b/GPU/Directx9/DepalettizeShaderDX9.cpp index decf55a60b..8cfc8cb7de 100644 --- a/GPU/Directx9/DepalettizeShaderDX9.cpp +++ b/GPU/Directx9/DepalettizeShaderDX9.cpp @@ -109,7 +109,7 @@ LPDIRECT3DTEXTURE9 DepalShaderCacheDX9::GetClutTexture(const u32 clutID, u32 *ra memcpy(rect.pBits, rawClut, 1024); tex->texture->UnlockRect(0); - pD3Ddevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pD3Ddevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); pD3Ddevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); pD3Ddevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); pD3Ddevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); diff --git a/GPU/GLES/DepalettizeShader.cpp b/GPU/GLES/DepalettizeShader.cpp index 6bb010860a..111a7a06bf 100644 --- a/GPU/GLES/DepalettizeShader.cpp +++ b/GPU/GLES/DepalettizeShader.cpp @@ -152,7 +152,7 @@ GLuint DepalShaderCache::GetClutTexture(const u32 clutID, u32 *rawClut) { glTexImage2D(GL_TEXTURE_2D, 0, components, texturePixels, 1, 0, components2, dstFmt, (void *)rawClut); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); From 5822faabf914b06e6f728700879aa4fbb7441bf1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:42:58 -0700 Subject: [PATCH 4/6] Make sure to wrap clut indexes at 1024 bytes. So that's 256 for 32-bit and 512 for 16-bit. --- GPU/GPUState.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 0559f84bda..81c367c370 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -309,7 +309,11 @@ struct GPUgstate int getClutIndexShift() const { return (clutformat >> 2) & 0x1F; } int getClutIndexMask() const { return (clutformat >> 8) & 0xFF; } int getClutIndexStartPos() const { return ((clutformat >> 16) & 0x1F) << 4; } - u32 transformClutIndex(u32 index) const { return ((index >> getClutIndexShift()) & getClutIndexMask()) | getClutIndexStartPos(); } + u32 transformClutIndex(u32 index) const { + // We need to wrap any entries beyond the first 1024 bytes. + u32 mask = getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 0xFF : 0x1FF; + return ((index >> getClutIndexShift()) & getClutIndexMask()) | (getClutIndexStartPos() & mask); + } bool isClutIndexSimple() const { return (clutformat & ~3) == 0xC500FF00; } // Meaning, no special mask, shift, or start pos. bool isTextureSwizzled() const { return texmode & 1; } bool isClutSharedForMipmaps() const { return (texmode & 0x100) == 0; } From ab67c49ae96de1406927907cf035fa4af40329da Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:43:36 -0700 Subject: [PATCH 5/6] Make sure we don't hash outside max bytes. If we've never even loaded that much, play it safe. --- GPU/Directx9/TextureCacheDX9.cpp | 7 ++++++- GPU/GLES/TextureCache.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 37a8c57425..bf615185ef 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -865,7 +865,12 @@ void TextureCacheDX9::UpdateCurrentClut() { const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. - const u32 clutExtendedBytes = clutTotalBytes_ + clutBaseBytes; + // + // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. + // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash + // unrelated old entries for small palettes. + // Adding clutBaseBytes may just be mitigating this for some usage patterns. + const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); clutBuf_ = clutBufRaw_; diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index db059644d5..9357ca3881 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -997,7 +997,7 @@ void TextureCache::UpdateCurrentClut() { // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash // unrelated old entries for small palettes. // Adding clutBaseBytes may just be mitigating this for some usage patterns. - const u32 clutExtendedBytes = clutTotalBytes_ + clutBaseBytes; + const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); From 4fa50a9a50b5a6ad70d30d04f02cb5631d73d46a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 26 Apr 2015 00:50:47 -0700 Subject: [PATCH 6/6] Reduce clut allocation size a bit. Really think this probably should only be 1024 bytes, but need to work out some more details before shrinking all the way. --- GPU/Directx9/TextureCacheDX9.cpp | 10 +++++----- GPU/GLES/TextureCache.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index bf615185ef..5b14e75aab 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -70,14 +70,14 @@ TextureCacheDX9::TextureCacheDX9() : cacheSizeEstimate_(0), secondCacheSizeEstim tmpTexBuf16.resize(1024 * 512); // 1MB tmpTexBufRearrange.resize(1024 * 512); // 2MB - // Aren't these way too big? - clutBufConverted_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB - clutBufRaw_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB + // TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut. + clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB + clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB // Zap these so that reads from uninitialized parts of the CLUT look the same in // release and debug - memset(clutBufConverted_, 0, 4096 * sizeof(u32)); - memset(clutBufRaw_, 0, 4096 * sizeof(u32)); + memset(clutBufConverted_, 0, 1024 * sizeof(u32)); + memset(clutBufRaw_, 0, 1024 * sizeof(u32)); D3DCAPS9 pCaps; ZeroMemory(&pCaps, sizeof(pCaps)); diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 9357ca3881..77ef5cf4e4 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -75,14 +75,14 @@ TextureCache::TextureCache() : cacheSizeEstimate_(0), secondCacheSizeEstimate_(0 tmpTexBuf16.resize(1024 * 512); // 1MB tmpTexBufRearrange.resize(1024 * 512); // 2MB - // Aren't these way too big? - clutBufConverted_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB - clutBufRaw_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB + // TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut. + clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB + clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB // Zap these so that reads from uninitialized parts of the CLUT look the same in // release and debug - memset(clutBufConverted_, 0, 4096 * sizeof(u32)); - memset(clutBufRaw_, 0, 4096 * sizeof(u32)); + memset(clutBufConverted_, 0, 1024 * sizeof(u32)); + memset(clutBufRaw_, 0, 1024 * sizeof(u32)); glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyLevel); SetupTextureDecoder();