diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index b7585bff44..b6101053e0 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -272,8 +272,9 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) for (int i = 0; i < param.GetFilenameCount(); i++) { int textureColor = 0xFFFFFFFF; + auto fileInfo = param.GetFileInfo(i); - if (param.GetFileInfo(i).size == 0 && param.GetFileInfo(i).textureData == 0) + if (fileInfo.size == 0 && fileInfo.texture != NULL) textureColor = 0xFF777777; // Calc save image position on screen @@ -300,13 +301,12 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) int tw = 256; int th = 256; - if (param.GetFileInfo(i).textureData != 0) { - tw = param.GetFileInfo(i).textureWidth; - th = param.GetFileInfo(i).textureHeight; - PPGeSetTexture(param.GetFileInfo(i).textureData, param.GetFileInfo(i).textureWidth, param.GetFileInfo(i).textureHeight); + if (fileInfo.texture != NULL) { + fileInfo.texture->SetTexture(); + tw = fileInfo.texture->Width(); + th = fileInfo.texture->Height(); PPGeDrawImage(x, y, w, h, 0, 0, 1, 1, tw, th, textureColor); - } else - PPGeDisableTexture(); + } PPGeSetDefaultTexture(); displayCount++; } @@ -322,8 +322,9 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) void PSPSaveDialog::DisplaySaveIcon() { int textureColor = CalcFadedColor(0xFFFFFFFF); + auto curSave = param.GetFileInfo(currentSelectedSave); - if (param.GetFileInfo(currentSelectedSave).size == 0) + if (curSave.size == 0) textureColor = CalcFadedColor(0xFF777777); // Calc save image position on screen @@ -334,14 +335,15 @@ void PSPSaveDialog::DisplaySaveIcon() int tw = 256; int th = 256; - if (param.GetFileInfo(currentSelectedSave).textureData != 0) { - tw = param.GetFileInfo(currentSelectedSave).textureWidth; - th = param.GetFileInfo(currentSelectedSave).textureHeight; - PPGeSetTexture(param.GetFileInfo(currentSelectedSave).textureData, param.GetFileInfo(currentSelectedSave).textureWidth, param.GetFileInfo(currentSelectedSave).textureHeight); - } else + if (curSave.texture != NULL) { + curSave.texture->SetTexture(); + tw = curSave.texture->Width(); + th = curSave.texture->Height(); + } else { PPGeDisableTexture(); - PPGeDrawImage(x, y, w, h, 0, 0 ,1 ,1 ,tw, th, textureColor); - if (param.GetFileInfo(currentSelectedSave).textureData != 0) + } + PPGeDrawImage(x, y, w, h, 0, 0, 1, 1, tw, th, textureColor); + if (curSave.texture != NULL) PPGeSetDefaultTexture(); } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 70d69e15e3..4003860ce7 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -1094,20 +1094,20 @@ void SavedataParam::Clear() { for (int i = 0; i < saveNameListDataCount; i++) { - if (saveDataList[i].textureData != 0 && saveDataList[i].size != 0) - kernelMemory.Free(saveDataList[i].textureData); - saveDataList[i].textureData = 0; + if (saveDataList[i].texture != NULL) + delete saveDataList[i].texture; + saveDataList[i].texture = NULL; } - delete[] saveDataList; + delete [] saveDataList; saveDataList = 0; saveDataListCount = 0; } if (noSaveIcon) { - if(noSaveIcon->textureData != 0) - kernelMemory.Free(noSaveIcon->textureData); - noSaveIcon->textureData = 0; + if (noSaveIcon->texture != NULL) + delete noSaveIcon->texture; + noSaveIcon->texture = NULL; delete noSaveIcon; noSaveIcon = 0; } @@ -1242,33 +1242,6 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) return 0; } -bool SavedataParam::CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info) -{ - unsigned char *textureData; - int w,h; - - int success = pngLoadPtr(pngData, (int)pngSize, &w, &h, &textureData, false); - - u32 texSize = w*h*4; - u32 atlasPtr; - if (success) - atlasPtr = kernelMemory.Alloc(texSize, true, "SaveData Icon"); - if (success && atlasPtr != (u32)-1) - { - info.textureData = atlasPtr; - Memory::Memcpy(atlasPtr, textureData, texSize); - free(textureData); - info.textureWidth = w; - info.textureHeight = h; - } - else - { - WARN_LOG(SCEUTILITY, "Unable to load PNG data for savedata."); - return false; - } - return true; -} - void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName) { saveInfo.size = info.size; @@ -1277,7 +1250,12 @@ void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std:: saveInfo.modif_time = info.mtime; // Start with a blank slate. - saveInfo.textureData = 0; + if (saveInfo.texture != NULL) { + if (!noSaveIcon || saveInfo.texture != noSaveIcon->texture) { + delete saveInfo.texture; + } + saveInfo.texture = NULL; + } saveInfo.title[0] = 0; saveInfo.saveTitle[0] = 0; saveInfo.saveDetail[0] = 0; @@ -1287,12 +1265,7 @@ void SavedataParam::SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std:: std::string fileDataPath2 = savePath + GetGameName(pspParam) + saveName + "/" + ICON0_FILENAME; PSPFileInfo info2 = pspFileSystem.GetFileInfo(fileDataPath2); if (info2.exists) - { - u8 *textureDataPNG = new u8[(size_t)info2.size]; - ReadPSPFile(fileDataPath2, &textureDataPNG, info2.size, NULL); - CreatePNGIcon(textureDataPNG, (int)info2.size, saveInfo); - delete[] textureDataPNG; - } + saveInfo.texture = new PPGeImage(fileDataPath2); // Load info in PARAM.SFO fileDataPath2 = savePath + GetGameName(pspParam) + saveName + "/" + SFO_FILENAME; @@ -1323,7 +1296,12 @@ void SavedataParam::ClearFileInfo(SaveFileInfo &saveInfo, std::string saveName) saveInfo.size = 0; saveInfo.saveName = saveName; saveInfo.idx = 0; - saveInfo.textureData = 0; + if (saveInfo.texture != NULL) { + if (!noSaveIcon || saveInfo.texture != noSaveIcon->texture) { + delete saveInfo.texture; + } + saveInfo.texture = NULL; + } if (GetPspParam()->newData.IsValid() && GetPspParam()->newData->buf.IsValid()) { @@ -1332,11 +1310,9 @@ void SavedataParam::ClearFileInfo(SaveFileInfo &saveInfo, std::string saveName) { noSaveIcon = new SaveFileInfo(); PspUtilitySavedataFileData *newData = GetPspParam()->newData; - CreatePNGIcon(newData->buf, (int)newData->size, *noSaveIcon); + noSaveIcon->texture = new PPGeImage(newData->buf.ptr, (SceSize)newData->size); } - saveInfo.textureData = noSaveIcon->textureData; - saveInfo.textureWidth = noSaveIcon->textureWidth; - saveInfo.textureHeight = noSaveIcon->textureHeight; + saveInfo.texture = noSaveIcon->texture; } } diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 46b4608755..234fec649c 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -21,6 +21,7 @@ #include "Core/HLE/sceRtc.h" #include "Core/System.h" #include "Core/Dialog/PSPDialog.h" +#include "Core/Util/PPGeDraw.h" #include "Common/CommonTypes.h" #undef st_ctime @@ -250,12 +251,9 @@ struct SaveFileInfo tm modif_time; - u32 textureData; - int textureWidth; - int textureHeight; + PPGeImage *texture; - SaveFileInfo() : size(0), saveName(""), idx(0), - textureData(0), textureWidth(0), textureHeight(0) + SaveFileInfo() : size(0), saveName(""), idx(0), texture(NULL) { memset(title, 0, 128); memset(saveTitle, 0, 128); @@ -265,7 +263,7 @@ struct SaveFileInfo void DoState(PointerWrap &p) { - auto s = p.Section("SaveFileInfo", 1); + auto s = p.Section("SaveFileInfo", 1, 2); if (!s) return; @@ -278,9 +276,30 @@ struct SaveFileInfo p.DoArray(saveDetail, sizeof(saveDetail)); p.Do(modif_time); - p.Do(textureData); - p.Do(textureWidth); - p.Do(textureHeight); + + if (s <= 1) { + u32 textureData; + int textureWidth; + int textureHeight; + p.Do(textureData); + p.Do(textureWidth); + p.Do(textureHeight); + + if (textureData != 0) { + // Must be MODE_READ. + texture = new PPGeImage(""); + texture->CompatLoad(textureData, textureWidth, textureHeight); + } + } else { + bool hasTexture = texture != NULL; + p.Do(hasTexture); + if (hasTexture) { + if (p.mode == p.MODE_READ) { + texture = new PPGeImage(""); + } + texture->DoState(p); + } + } } }; @@ -337,7 +356,6 @@ public: private: void Clear(); - bool CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info); void SetFileInfo(int idx, PSPFileInfo &info, std::string saveName); void SetFileInfo(SaveFileInfo &saveInfo, PSPFileInfo &info, std::string saveName); void ClearFileInfo(SaveFileInfo &saveInfo, std::string saveName); diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index e25954cafc..613c952388 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "Core/Util/PPGeDraw.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -24,6 +25,7 @@ #include "Core/HLE/sceGe.h" #include "Core/MemMap.h" #include "image/zim_load.h" +#include "image/png_load.h" #include "util/text/utf8.h" #include "Core/System.h" @@ -802,3 +804,112 @@ void PPGeDisableTexture() WriteCmd(GE_CMD_TEXTUREMAPENABLE, 0); } +std::vector PPGeImage::loadedTextures_; + +PPGeImage::PPGeImage(const std::string &pspFilename) + : filename_(pspFilename), texture_(0) { +} + +PPGeImage::PPGeImage(u32 pngPointer, size_t pngSize) + : filename_(""), png_(pngPointer), size_(pngSize) { +} + +PPGeImage::~PPGeImage() { + Free(); +} + +bool PPGeImage::Load() { + Free(); + + // In case it fails to load. + width_ = 0; + height_ = 0; + + unsigned char *textureData; + int success; + if (filename_.empty()) { + success = pngLoadPtr(Memory::GetPointer(png_), size_, &width_, &height_, &textureData, false); + } else { + std::string pngData; + if (pspFileSystem.ReadEntireFile(filename_, pngData) < 0) { + WARN_LOG(SCEGE, "Bad PPGeImage - cannot load file"); + return false; + } + + success = pngLoadPtr((const unsigned char *)&pngData[0], pngData.size(), &width_, &height_, &textureData, false); + } + if (!success) { + WARN_LOG(SCEGE, "Bad PPGeImage - not a valid png"); + return false; + } + + u32 texSize = width_ * height_ * 4; + texture_ = __PPGeDoAlloc(texSize, true, "Savedata Icon"); + if (texture_ == 0) { + WARN_LOG(SCEGE, "Bad PPGeImage - unable to allocate space for texture"); + return false; + } + + Memory::Memcpy(texture_, textureData, texSize); + free(textureData); + + lastFrame_ = gpuStats.numFlips; + loadedTextures_.push_back(this); + return true; +} + +void PPGeImage::Free() { + if (texture_ != 0) { + kernelMemory.Free(texture_); + texture_ = 0; + loadedTextures_.erase(std::remove(loadedTextures_.begin(), loadedTextures_.end(), this), loadedTextures_.end()); + } +} + +void PPGeImage::DoState(PointerWrap &p) { + auto s = p.Section("PPGeImage", 1); + if (!s) + return; + + p.Do(filename_); + p.Do(png_); + p.Do(size_); + p.Do(texture_); + p.Do(width_); + p.Do(height_); + p.Do(lastFrame_); +} + +void PPGeImage::CompatLoad(u32 texture, int width, int height) { + // Won't be reloadable, so don't add to loadedTextures_. + texture_ = texture; + width_ = width; + height_ = height; +} + +void PPGeImage::Decimate() { + static const int TOO_OLD_AGE = 30; + int tooOldFrame = gpuStats.numFlips - TOO_OLD_AGE; + for (size_t i = 0; i < loadedTextures_.size(); ++i) { + if (loadedTextures_[i]->lastFrame_ < tooOldFrame) { + loadedTextures_[i]->Free(); + // That altered loadedTextures_. + --i; + } + } +} + +void PPGeImage::SetTexture() { + if (texture_ == 0) { + Decimate(); + Load(); + } + + if (texture_ != 0) { + lastFrame_ = gpuStats.numFlips; + PPGeSetTexture(texture_, width_, height_); + } else { + PPGeDisableTexture(); + } +} + diff --git a/Core/Util/PPGeDraw.h b/Core/Util/PPGeDraw.h index bda1c4ea81..61ed4085e0 100644 --- a/Core/Util/PPGeDraw.h +++ b/Core/Util/PPGeDraw.h @@ -103,6 +103,48 @@ void PPGeDrawImage(int atlasImage, float x, float y, int align, u32 color = 0xFF void PPGeDrawImage(int atlasImage, float x, float y, float w, float h, int align, u32 color = 0xFFFFFFFF); void PPGeDrawImage(float x, float y, float w, float h, float u1, float v1, float u2, float v2, int tw, int th, u32 color); +class PPGeImage { +public: + PPGeImage(const std::string &pspFilename); + PPGeImage(u32 pngPointer, size_t pngSize); + ~PPGeImage(); + + void SetTexture(); + + // Does not normally need to be called (except to force preloading.) + bool Load(); + void Free(); + + void DoState(PointerWrap &p); + + // Do not use, only for savestate upgrading. + void CompatLoad(u32 texture, int width, int height); + + int Width() { + return width_; + } + + int Height() { + return height_; + } + +private: + static void Decimate(); + static std::vector loadedTextures_; + + std::string filename_; + + // Only valid if filename_.empty(). + u32 png_; + size_t size_; + + u32 texture_; + int width_; + int height_; + + int lastFrame_; +}; + void PPGeDrawRect(float x1, float y1, float x2, float y2, u32 color); void PPGeSetDefaultTexture();