diff --git a/CMakeLists.txt b/CMakeLists.txt index befa7c5113..f0cb7c538f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1002,6 +1002,8 @@ add_library(GPU OBJECT GPU/Common/VertexDecoderCommon.h GPU/Common/IndexGenerator.cpp GPU/Common/IndexGenerator.h + GPU/Common/TextureDecoder.cpp + GPU/Common/TextureDecoder.h GPU/GLES/GLES_GPU.cpp GPU/GLES/GLES_GPU.h GPU/GLES/FragmentShaderGenerator.cpp diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp new file mode 100644 index 0000000000..964343cb2f --- /dev/null +++ b/GPU/Common/TextureDecoder.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPU/Common/TextureDecoder.h" + +// TODO: Move some common things into here. \ No newline at end of file diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h new file mode 100644 index 0000000000..72bdd3d637 --- /dev/null +++ b/GPU/Common/TextureDecoder.h @@ -0,0 +1,74 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Core/MemMap.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUState.h" + +static const u8 textureBitsPerPixel[16] = { + 16, //GE_TFMT_5650, + 16, //GE_TFMT_5551, + 16, //GE_TFMT_4444, + 32, //GE_TFMT_8888, + 4, //GE_TFMT_CLUT4, + 8, //GE_TFMT_CLUT8, + 16, //GE_TFMT_CLUT16, + 32, //GE_TFMT_CLUT32, + 4, //GE_TFMT_DXT1, + 8, //GE_TFMT_DXT3, + 8, //GE_TFMT_DXT5, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, +}; + +// Masks to downalign bufw to 16 bytes, and wrap at 2048. +static const u32 textureAlignMask16[16] = { + 0x7FF & ~(((8 * 16) / 16) - 1), //GE_TFMT_5650, + 0x7FF & ~(((8 * 16) / 16) - 1), //GE_TFMT_5551, + 0x7FF & ~(((8 * 16) / 16) - 1), //GE_TFMT_4444, + 0x7FF & ~(((8 * 16) / 32) - 1), //GE_TFMT_8888, + 0x7FF & ~(((8 * 16) / 4) - 1), //GE_TFMT_CLUT4, + 0x7FF & ~(((8 * 16) / 8) - 1), //GE_TFMT_CLUT8, + 0x7FF & ~(((8 * 16) / 16) - 1), //GE_TFMT_CLUT16, + 0x7FF & ~(((8 * 16) / 32) - 1), //GE_TFMT_CLUT32, + 0x7FF & ~(((8 * 16) / 4) - 1), //GE_TFMT_DXT1, + 0x7FF & ~(((8 * 16) / 8) - 1), //GE_TFMT_DXT3, + 0x7FF & ~(((8 * 16) / 8) - 1), //GE_TFMT_DXT5, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, + 0, // INVALID, +}; + +static inline u32 GetTextureBufw(int level, u32 texaddr, GETextureFormat format) { + // This is a hack to allow for us to draw the huge PPGe texture, which is always in kernel ram. + if (texaddr < PSP_GetUserMemoryBase()) + return gstate.texbufwidth[level] & 0x1FFF; + + u32 bufw = gstate.texbufwidth[level] & textureAlignMask16[format]; + if (bufw == 0) { + // If it's less than 16 bytes, use 16 bytes. + bufw = (8 * 16) / textureBitsPerPixel[format]; + } + return bufw; +} \ No newline at end of file diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index f2c0a31fcc..869e6566b5 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -24,6 +24,7 @@ #include "GPU/GPUState.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/FramebufferDX9.h" +#include "GPU/Common/TextureDecoder.h" #include "Core/Config.h" #include "ext/xxhash.h" @@ -44,12 +45,6 @@ namespace DX9 { #define TEXCACHE_DECIMATION_INTERVAL 13 extern int g_iNumVideos; -static inline u32 GetLevelBufw(int level, u32 texaddr) { - // Special rules for kernel textures (PPGe): - if (texaddr < PSP_GetUserMemoryBase()) - return gstate.texbufwidth[level] & 0x1FFF; - return gstate.texbufwidth[level] & 0x7FF; -} TextureCacheDX9::TextureCacheDX9() : clearCacheNextFrame_(false), lowMemoryMode_(false), clutBuf_(NULL) { lastBoundTexture = INVALID_TEX; @@ -407,8 +402,7 @@ inline void DeIndexTexture4Optimal(ClutT *dest, const u32 texaddr, int length, C DeIndexTexture4Optimal(dest, indexed, length, color); } -void *TextureCacheDX9::readIndexedTex(int level, u32 texaddr, int bytesPerIndex, u32 dstFmt) { - int bufw = GetLevelBufw(level, texaddr); +void *TextureCacheDX9::ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, u32 dstFmt, int bufw) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); int length = bufw * h; @@ -801,25 +795,6 @@ void TextureCacheDX9::StartFrame() { } } -static const u8 bitsPerPixel[16] = { - 16, //GE_TFMT_5650, - 16, //GE_TFMT_5551, - 16, //GE_TFMT_4444, - 32, //GE_TFMT_8888, - 4, //GE_TFMT_CLUT4, - 8, //GE_TFMT_CLUT8, - 16, //GE_TFMT_CLUT16, - 32, //GE_TFMT_CLUT32, - 4, //GE_TFMT_DXT1, - 8, //GE_TFMT_DXT3, - 8, //GE_TFMT_DXT5, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, -}; - static inline u32 MiniHash(const u32 *ptr) { return ptr[0]; } @@ -856,7 +831,7 @@ static inline u32 QuickClutHash(const u8 *clut, u32 bytes) { } static inline u32 QuickTexHash(u32 addr, int bufw, int w, int h, GETextureFormat format) { - const u32 sizeInRAM = (bitsPerPixel[format] * bufw * h) / 8; + const u32 sizeInRAM = (textureBitsPerPixel[format] * bufw * h) / 8; const u32 *checkp = (const u32 *) Memory::GetPointer(addr); u32 check = 0; @@ -1083,7 +1058,7 @@ void TextureCacheDX9::SetTexture() { int w = gstate.getTextureWidth(0); int h = gstate.getTextureHeight(0); - int bufw = GetLevelBufw(0, texaddr); + int bufw = GetTextureBufw(0, texaddr, format); int maxLevel = ((gstate.texmode >> 16) & 0x7); u32 texhash = MiniHash((const u32 *)Memory::GetPointer(texaddr)); @@ -1236,7 +1211,7 @@ void TextureCacheDX9::SetTexture() { // This would overestimate the size in many case so we underestimate instead // to avoid excessive clearing caused by cache invalidations. - entry->sizeInRAM = (bitsPerPixel[format] * bufw * h / 2) / 8; + entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; entry->fullhash = fullhash == 0 ? QuickTexHash(texaddr, bufw, w, h, format) : fullhash; entry->cluthash = cluthash; @@ -1300,7 +1275,7 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma u32 texaddr = (gstate.texaddr[level] & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000); - int bufw = GetLevelBufw(level, texaddr); + int bufw = GetTextureBufw(level, texaddr, format); int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); @@ -1310,9 +1285,6 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma case GE_TFMT_CLUT4: { dstFmt = getClutDestFormat(clutformat); - // Don't allow this to be less than 16 bytes (32 * 4 / 8 = 16.) - if (bufw < 32) - bufw = 32; const bool mipmapShareClut = (gstate.texmode & 0x100) == 0; const int clutSharingOffset = mipmapShareClut ? 0 : level * 16; @@ -1371,34 +1343,26 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma break; case GE_TFMT_CLUT8: - if (bufw < 8) - bufw = 8; dstFmt = getClutDestFormat(gstate.getClutPaletteFormat()); texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = readIndexedTex(level, texaddr, 1, dstFmt); + finalBuf = ReadIndexedTex(level, texaddr, 1, dstFmt, bufw); break; case GE_TFMT_CLUT16: - if (bufw < 8) - bufw = 8; dstFmt = getClutDestFormat(gstate.getClutPaletteFormat()); texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = readIndexedTex(level, texaddr, 2, dstFmt); + finalBuf = ReadIndexedTex(level, texaddr, 2, dstFmt, bufw); break; case GE_TFMT_CLUT32: - if (bufw < 4) - bufw = 4; dstFmt = getClutDestFormat(gstate.getClutPaletteFormat()); texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()]; - finalBuf = readIndexedTex(level, texaddr, 4, dstFmt); + finalBuf = ReadIndexedTex(level, texaddr, 4, dstFmt, bufw); break; case GE_TFMT_4444: case GE_TFMT_5551: case GE_TFMT_5650: - if (bufw < 8) - bufw = 8; if (format == GE_TFMT_4444) dstFmt = D3DFMT_A4R4G4B4; else if (format == GE_TFMT_5551) @@ -1422,8 +1386,6 @@ void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteForma break; case GE_TFMT_8888: - if (bufw < 4) - bufw = 4; dstFmt = D3DFMT_A8R8G8B8; if (!gstate.isTextureSwizzled()) { // Special case: if we don't need to deal with packing, we don't need to copy. diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h index 1accc7cbba..e336aef9d0 100644 --- a/GPU/Directx9/TextureCacheDX9.h +++ b/GPU/Directx9/TextureCacheDX9.h @@ -118,7 +118,7 @@ private: void Decimate(); // Run this once per frame to get rid of old textures. void *UnswizzleFromMem(u32 texaddr, u32 bufw, u32 bytesPerPixel, u32 level); - void *readIndexedTex(int level, u32 texaddr, int bytesPerIndex, u32 dstFmt); + void *ReadIndexedTex(int level, u32 texaddr, int bytesPerIndex, u32 dstFmt, int bufw); void UpdateSamplingParams(TexCacheEntry &entry, bool force); void LoadTextureLevel(TexCacheEntry &entry, int level, bool replaceImages); void *DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &texByteAlign, u32 &dstFmt); diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 50ee98027d..ed64d839b6 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -24,6 +24,7 @@ #include "GPU/GPUState.h" #include "GPU/GLES/TextureCache.h" #include "GPU/GLES/Framebuffer.h" +#include "GPU/Common/TextureDecoder.h" #include "Core/Config.h" #include "ext/xxhash.h" @@ -45,13 +46,6 @@ extern int g_iNumVideos; -static inline u32 GetLevelBufw(int level, u32 texaddr) { - // Special rules for kernel textures (PPGe): - if (texaddr < PSP_GetUserMemoryBase()) - return gstate.texbufwidth[level] & 0x1FFF; - return gstate.texbufwidth[level] & 0x7FF; -} - TextureCache::TextureCache() : clearCacheNextFrame_(false), lowMemoryMode_(false), clutBuf_(NULL) { lastBoundTexture = -1; decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; @@ -776,45 +770,6 @@ void TextureCache::StartFrame() { } } -static const u8 bitsPerPixel[16] = { - 16, //GE_TFMT_5650, - 16, //GE_TFMT_5551, - 16, //GE_TFMT_4444, - 32, //GE_TFMT_8888, - 4, //GE_TFMT_CLUT4, - 8, //GE_TFMT_CLUT8, - 16, //GE_TFMT_CLUT16, - 32, //GE_TFMT_CLUT32, - 4, //GE_TFMT_DXT1, - 8, //GE_TFMT_DXT3, - 8, //GE_TFMT_DXT5, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, -}; - -// Masks to downalign bufw to 16 bytes. -static const u32 alignMask16[16] = { - ~(((8 * 16) / 16) - 1), //GE_TFMT_5650, - ~(((8 * 16) / 16) - 1), //GE_TFMT_5551, - ~(((8 * 16) / 16) - 1), //GE_TFMT_4444, - ~(((8 * 16) / 32) - 1), //GE_TFMT_8888, - ~(((8 * 16) / 4) - 1), //GE_TFMT_CLUT4, - ~(((8 * 16) / 8) - 1), //GE_TFMT_CLUT8, - ~(((8 * 16) / 16) - 1), //GE_TFMT_CLUT16, - ~(((8 * 16) / 32) - 1), //GE_TFMT_CLUT32, - ~(((8 * 16) / 4) - 1), //GE_TFMT_DXT1, - ~(((8 * 16) / 8) - 1), //GE_TFMT_DXT3, - ~(((8 * 16) / 8) - 1), //GE_TFMT_DXT5, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, - 0, // INVALID, -}; - static inline u32 MiniHash(const u32 *ptr) { return ptr[0]; } @@ -851,7 +806,7 @@ static inline u32 QuickClutHash(const u8 *clut, u32 bytes) { } static inline u32 QuickTexHash(u32 addr, int bufw, int w, int h, GETextureFormat format) { - const u32 sizeInRAM = (bitsPerPixel[format] * bufw * h) / 8; + const u32 sizeInRAM = (textureBitsPerPixel[format] * bufw * h) / 8; const u32 *checkp = (const u32 *) Memory::GetPointer(addr); u32 check = 0; @@ -1055,10 +1010,10 @@ void TextureCache::SetTexture() { } else { cluthash = 0; } - + + int bufw = GetTextureBufw(0, texaddr, format); int w = gstate.getTextureWidth(0); int h = gstate.getTextureHeight(0); - int bufw = GetLevelBufw(0, texaddr); int maxLevel = ((gstate.texmode >> 16) & 0x7); u32 texhash = MiniHash((const u32 *)Memory::GetPointer(texaddr)); @@ -1211,7 +1166,7 @@ void TextureCache::SetTexture() { // This would overestimate the size in many case so we underestimate instead // to avoid excessive clearing caused by cache invalidations. - entry->sizeInRAM = (bitsPerPixel[format] * bufw * h / 2) / 8; + entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; entry->fullhash = fullhash == 0 ? QuickTexHash(texaddr, bufw, w, h, format) : fullhash; entry->cluthash = cluthash; @@ -1308,12 +1263,7 @@ void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat c u32 texaddr = (gstate.texaddr[level] & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000); - int bufw = GetLevelBufw(level, texaddr) & alignMask16[format]; - if (bufw == 0) { - // If it's less than 16 bytes, use 16 bytes. - bufw = (8 * 16) / bitsPerPixel[format]; - } - + int bufw = GetTextureBufw(level, texaddr, format); int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); const u8 *texptr = Memory::GetPointer(texaddr); @@ -1678,8 +1628,7 @@ bool TextureCache::DecodeTexture(u8* output, GPUgstate state) GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); u8 level = 0; - int bufw = GetLevelBufw(level, texaddr); - + int bufw = GetTextureBufw(level, texaddr, format); int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 5b0cdeffdb..53c81f509d 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -193,6 +193,7 @@ + @@ -243,6 +244,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index fca0d1d5fe..f0c80dbbf8 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -138,6 +138,9 @@ DirectX9\helper + + Common + @@ -254,6 +257,9 @@ DirectX9\helper + + Common + diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 2dc63b57ea..cac7e23371 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -19,6 +19,7 @@ #include "Core/Reporting.h" #include "GPU/GPUState.h" +#include "GPU/Common/TextureDecoder.h" #include "GPU/Software/SoftGpu.h" #include "GPU/Software/Rasterizer.h" #include "GPU/Software/Colors.h" @@ -171,8 +172,7 @@ static inline u32 SampleNearest(int level, unsigned int u, unsigned int v) u32 texaddr = (gstate.texaddr[level] & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000); u8* srcptr = (u8*)Memory::GetPointer(texaddr); // TODO: not sure if this is the right place to load from...? - // Special rules for kernel textures (PPGe), TODO: Verify! - int texbufwidth = (texaddr < PSP_GetUserMemoryBase()) ? gstate.texbufwidth[level] & 0x1FFF : gstate.texbufwidth[level] & 0x7FF; + int texbufwidth = GetTextureBufw(level, texaddr, texfmt); // TODO: Should probably check if textures are aligned properly... diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 289af36d7c..0ac3ac0af5 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -194,6 +194,7 @@ LOCAL_SRC_FILES := \ $(SRC)/GPU/GeDisasm.cpp \ $(SRC)/GPU/Common/IndexGenerator.cpp.arm \ $(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \ + $(SRC)/GPU/Common/TextureDecoder.cpp \ $(SRC)/GPU/GLES/Framebuffer.cpp \ $(SRC)/GPU/GLES/GLES_GPU.cpp.arm \ $(SRC)/GPU/GLES/TextureCache.cpp.arm \