diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index f4923fc041..ef0bec2bd9 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -1958,6 +1958,32 @@ void SavedataParam::DoState(PointerWrap &p) { if (!s) return; + if (p.mode == p.MODE_READ) { + // The load replaces kernel memory, so the icons' texture addresses now belong to whatever + // the loaded state allocated there. Drop them without freeing those. + std::vector oldTextures; + for (int i = 0; saveDataList && i < saveDataListCount; i++) { + if (saveDataList[i].texture) { + oldTextures.push_back(saveDataList[i].texture); + saveDataList[i].texture = nullptr; + } + } + if (noSaveIcon) { + oldTextures.push_back(noSaveIcon->texture); + delete noSaveIcon; + noSaveIcon = nullptr; + } + // Entries may share noSaveIcon's image. + std::sort(oldTextures.begin(), oldTextures.end()); + oldTextures.erase(std::unique(oldTextures.begin(), oldTextures.end()), oldTextures.end()); + for (PPGeImage *texture : oldTextures) { + if (texture) { + texture->Forget(); + delete texture; + } + } + } + // pspParam is handled in PSPSaveDialog. Do(p, selectedSave); Do(p, saveDataListCount); diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index e0b39413ea..a9170f4b6a 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -1451,6 +1451,12 @@ void PPGeImage::Free() { } } +void PPGeImage::Forget() { + texture_ = 0; + loadFailed_ = false; + loadedTextures_.erase(std::remove(loadedTextures_.begin(), loadedTextures_.end(), this), loadedTextures_.end()); +} + void PPGeImage::DoState(PointerWrap &p) { auto s = p.Section("PPGeImage", 1, 2); if (!s) diff --git a/Core/Util/PPGeDraw.h b/Core/Util/PPGeDraw.h index ea0ef8e2fe..06f212d858 100644 --- a/Core/Util/PPGeDraw.h +++ b/Core/Util/PPGeDraw.h @@ -122,6 +122,8 @@ public: // Does not normally need to be called (except to force preloading.) bool Load(); void Free(); + // Drops the texture without freeing its memory, which a savestate load has already replaced. + void Forget(); bool IsValid(); void DoState(PointerWrap &p);