// 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 #include #include #include #include #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 { size_t operator()(const ReplacementCacheKey &k) const { return std::hash()(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: TextureReplacer(const TextureReplacer &) = delete; TextureReplacer &operator=(const TextureReplacer &) = delete; // 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, bool enableSaving = false); // 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); // Whether this texture, which must have a palette (CLUT4 or CLUT8), is saved as an 8-bit palette PNG // with NotifyIndexedTextureDecoded instead of an RGBA one, see saveIndexed in textures.ini. bool WillSaveIndexed(const ReplacedTextureDecodeInfo &replacedInfo) const; // Whether the indices of this texture have been saved already, for any of its palettes. bool HasSavedIndexed(const ReplacedTextureDecodeInfo &replacedInfo) const; // Saves the indices (one byte each) with the palette that they get from the game's CLUT, numColors long. // The file name has the CLUT hash zeroed and ends in _indexed. void NotifyIndexedTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const u8 *indices, int pitch, const u32 *palette, int numColors, int w, int h); 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); // How the indices of a replacement from the [indexed] section get their colors. enum class IndexedMode : uint8_t { NONE, CPU, // Colored with the CLUT when the texture is built. GPU, // Uploaded as indices, colored in the shader. }; IndexedMode LookupIndexed(ReplacementCacheKey key) const; // Which textures with a palette are saved as palette PNGs. enum class SaveIndexedMode : uint8_t { OFF, LISTED, // Only the ones in the [indexed] section. ALL, }; ReplacementCacheKey IndexedSaveKey(const ReplacedTextureDecodeInfo &replacedInfo) const; 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 ParseIndexed(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; SaveIndexedMode saveIndexed_ = SaveIndexedMode::OFF; 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 WidthHeightPair; std::unordered_map hashranges_; std::unordered_map reducehashranges_; std::unordered_map aliases_; std::unordered_map filtering_; // Replacements that hold palette indices instead of colors, from the [indexed] section. std::unordered_map indexed_; std::unordered_map cache_; std::unordered_map 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 levelCache_; };