mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-17 00:10:31 +02:00
saveIndexed = true in [options] saves the CLUT4/CLUT8 textures listed in [indexed] as palette PNGs, saveIndexed = all saves every one of them. The file is named <hash>_indexed.png, with the CLUT hash zeroed so one file serves every palette of the texture. The other textures are dumped as before. The indices are decoded from PSP memory and the palette comes from the current CLUT, so the dump looks like the game's texture. Add the file to [hashes] and [indexed] to use it as a replacement. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
192 lines
7.2 KiB
C++
192 lines
7.2 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:
|
|
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<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_;
|
|
// Replacements that hold palette indices instead of colors, from the [indexed] section.
|
|
std::unordered_map<ReplacementCacheKey, IndexedMode> indexed_;
|
|
|
|
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_;
|
|
};
|