mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
- DDS files with mips stored level 0's file reference in level 1 too, so it was freed twice. - The VFS was deleted on config changes (and ini reloads) while load tasks still used it. Now each cached texture waits for its task and releases its file references through the old VFS first, and reloads afterwards. - A failed ini reload turns replacement off instead of leaving it on without a VFS. - Release file references on purge. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
163 lines
5.5 KiB
C++
163 lines
5.5 KiB
C++
// Copyright (c) 2016- 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 "ppsspp_config.h"
|
|
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include "Common/CommonFuncs.h"
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/MemoryUtil.h"
|
|
#include "Common/File/Path.h"
|
|
#include "Common/File/VFS/VFS.h"
|
|
#include "Common/GPU/DataFormat.h"
|
|
|
|
#include "GPU/Common/TextureDecoder.h"
|
|
#include "GPU/Common/ReplacedTexture.h"
|
|
#include "GPU/ge_constants.h"
|
|
|
|
class IniFile;
|
|
class TextureCacheCommon;
|
|
class TextureReplacer;
|
|
class ReplacedTextureTask;
|
|
class LimitedWaitable;
|
|
class VFSBackend;
|
|
|
|
struct SavedTextureCacheData {
|
|
int levelW[8]{};
|
|
int levelH[8]{};
|
|
bool levelSaved[8]{};
|
|
double lastTimeSaved = 0.0;
|
|
};
|
|
|
|
namespace std {
|
|
template <>
|
|
struct hash<ReplacementCacheKey> {
|
|
size_t operator()(const ReplacementCacheKey &k) const {
|
|
return std::hash<u64>()(k.cachekey ^ ((u64)k.hash << 32));
|
|
}
|
|
};
|
|
}
|
|
|
|
struct ReplacedTextureDecodeInfo {
|
|
u64 cachekey;
|
|
u32 hash;
|
|
u32 addr;
|
|
bool isVideo;
|
|
bool isFinal;
|
|
Draw::DataFormat fmt;
|
|
};
|
|
|
|
enum class ReplacerDecimateMode {
|
|
NEW_FRAME,
|
|
FORCE_PRESSURE,
|
|
ALL,
|
|
};
|
|
|
|
class TextureReplacer {
|
|
public:
|
|
// The draw context is checked for supported texture formats.
|
|
TextureReplacer(Draw::DrawContext *draw);
|
|
~TextureReplacer();
|
|
|
|
void NotifyConfigChanged();
|
|
|
|
bool Enabled() const { return replaceEnabled_ || saveEnabled_; } // used to check hashing method etc.
|
|
bool ReplaceEnabled() const { return replaceEnabled_; }
|
|
bool SaveEnabled() const { return saveEnabled_; }
|
|
|
|
u32 ComputeHash(u32 addr, int bufw, int w, int h, bool swizzled, GETextureFormat fmt, u16 maxSeenV);
|
|
|
|
// Returns nullptr if not found.
|
|
ReplacedTexture *FindReplacement(ReplacementCacheKey key, int w, int h);
|
|
|
|
// For testing: point the replacer at a texture pack directory and load its
|
|
// ini, without touching the global config. Returns true on success.
|
|
bool LoadPackForTesting(const Path &basePath, std::string *error);
|
|
|
|
// Check if a NotifyTextureDecoded for this texture is desired (used to avoid reads from write-combined memory.)
|
|
bool WillSave(const ReplacedTextureDecodeInfo &replacedInfo) const;
|
|
|
|
// Notify that a new texture was decoded. May already be upscaled, saves the data passed.
|
|
// If the replacer knows about this one already, texture will be passed in, otherwise nullptr.
|
|
void NotifyTextureDecoded(ReplacedTexture *texture, const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int origW, int origH, int scaledW, int scaledH);
|
|
|
|
void Decimate(ReplacerDecimateMode mode);
|
|
|
|
static bool GenerateIni(const std::string &gameID, Path &generatedFilename);
|
|
static bool IniExists(const std::string &gameID);
|
|
|
|
int GetNumTrackedTextures() const { return (int)cache_.size(); }
|
|
int GetNumCachedReplacedTextures() const { return (int)levelCache_.size(); }
|
|
|
|
static std::string HashName(ReplacementCacheKey key, int level);
|
|
|
|
protected:
|
|
bool FindFiltering(ReplacementCacheKey key, TextureFiltering *forceFiltering);
|
|
|
|
bool LoadIni(std::string *error, bool notify = true);
|
|
void DeleteVFS();
|
|
bool LoadIniValues(IniFile &ini, VFSBackend *dir, bool isOverride, std::string *error);
|
|
void ParseHashRange(const std::string &key, const std::string &value);
|
|
void ParseFiltering(const std::string &key, const std::string &value);
|
|
void ParseReduceHashRange(const std::string& key, const std::string& value);
|
|
bool LookupHashRange(u32 addr, int w, int h, int *newW, int *newH);
|
|
float LookupReduceHashRange(int w, int h);
|
|
std::string LookupHashFile(ReplacementCacheKey key, bool *foundAlias, bool *ignored);
|
|
|
|
bool replaceEnabled_ = false;
|
|
bool saveEnabled_ = false;
|
|
bool ignoreAddress_ = false;
|
|
bool reduceHash_ = false;
|
|
bool ignoreMipmap_ = false;
|
|
int skipLastDXT1Blocks128x64_ = 0;
|
|
int skipLastDXT1Blocks128x128_ = 0;
|
|
|
|
float reduceHashGlobalValue = 0.5f; // Global value for textures dump pngs of all sizes, 0.5 by default but can be set in textures.ini
|
|
|
|
double lastTextureCacheSizeGB_ = 0.0;
|
|
std::string gameID_;
|
|
Path basePath_;
|
|
Path newTextureDir_;
|
|
ReplacedTextureHash textureHash_ = ReplacedTextureHash::QUICK;
|
|
|
|
VFSBackend *vfs_ = nullptr;
|
|
bool vfsIsZip_ = false;
|
|
|
|
GPUFormatSupport formatSupport_{};
|
|
|
|
typedef std::pair<int, int> WidthHeightPair;
|
|
std::unordered_map<u64, WidthHeightPair> hashranges_;
|
|
std::unordered_map<u64, float> reducehashranges_;
|
|
|
|
std::unordered_map<ReplacementCacheKey, std::string> aliases_;
|
|
std::unordered_map<ReplacementCacheKey, TextureFiltering> filtering_;
|
|
|
|
std::unordered_map<ReplacementCacheKey, ReplacedTextureRef> cache_;
|
|
std::unordered_map<ReplacementCacheKey, SavedTextureCacheData> savedCache_;
|
|
|
|
// the key is either from aliases_, in which case it's a |-separated sequence of texture filenames of the levels of a texture.
|
|
// alternatively the key is from the generated texture filename.
|
|
std::unordered_map<std::string, ReplacedTexture *> levelCache_;
|
|
};
|