mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Replacement: Read in texture filtering overrides.
If you're replacing, you can know more information about linear safety for tests.
This commit is contained in:
parent
5d4d8ab418
commit
fb3ad1df4b
@ -76,6 +76,7 @@ bool TextureReplacer::LoadIni() {
|
||||
hash_ = ReplacedTextureHash::QUICK;
|
||||
aliases_.clear();
|
||||
hashranges_.clear();
|
||||
filtering_.clear();
|
||||
|
||||
allowVideo_ = false;
|
||||
ignoreAddress_ = false;
|
||||
@ -183,6 +184,14 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ini.HasSection("filtering")) {
|
||||
auto filters = ini.GetOrCreateSection("filtering")->ToMap();
|
||||
// Format: hashname = nearest or linear
|
||||
for (const auto &item : filters) {
|
||||
ParseFiltering(item.first, item.second);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -221,6 +230,23 @@ void TextureReplacer::ParseHashRange(const std::string &key, const std::string &
|
||||
hashranges_[rangeKey] = WidthHeightPair(toW, toH);
|
||||
}
|
||||
|
||||
void TextureReplacer::ParseFiltering(const std::string &key, const std::string &value) {
|
||||
ReplacementCacheKey itemKey(0, 0);
|
||||
if (sscanf(key.c_str(), "%16llx%8x", &itemKey.cachekey, &itemKey.hash) >= 1) {
|
||||
if (!strcasecmp(value.c_str(), "nearest")) {
|
||||
filtering_[itemKey] = TEX_FILTER_FORCE_NEAREST;
|
||||
} else if (!strcasecmp(value.c_str(), "linear")) {
|
||||
filtering_[itemKey] = TEX_FILTER_FORCE_LINEAR;
|
||||
} else if (!strcasecmp(value.c_str(), "auto")) {
|
||||
filtering_[itemKey] = TEX_FILTER_AUTO;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Unsupported syntax under [filtering]: %s", value.c_str());
|
||||
}
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Unsupported syntax under [filtering]: %s", key.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV) {
|
||||
_dbg_assert_msg_(enabled_, "Replacement not enabled");
|
||||
|
||||
@ -503,45 +529,74 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
|
||||
savedCache_[replacementKey] = saved;
|
||||
}
|
||||
|
||||
std::string TextureReplacer::LookupHashFile(u64 cachekey, u32 hash, int level) {
|
||||
ReplacementAliasKey key(cachekey, hash, level);
|
||||
auto alias = aliases_.find(key);
|
||||
if (alias == aliases_.end()) {
|
||||
// Also check for a few more aliases with zeroed portions:
|
||||
// Only clut hash (very dangerous in theory, in practice not more than missing "just" data hash)
|
||||
key.cachekey = cachekey & 0xFFFFFFFFULL;
|
||||
template <typename Key, typename Value>
|
||||
static typename std::unordered_map<Key, Value>::const_iterator LookupWildcard(const std::unordered_map<Key, Value> &map, Key &key, u64 cachekey, u32 hash, bool ignoreAddress) {
|
||||
auto alias = map.find(key);
|
||||
if (alias != map.end())
|
||||
return alias;
|
||||
|
||||
// Also check for a few more aliases with zeroed portions:
|
||||
// Only clut hash (very dangerous in theory, in practice not more than missing "just" data hash)
|
||||
key.cachekey = cachekey & 0xFFFFFFFFULL;
|
||||
key.hash = 0;
|
||||
alias = map.find(key);
|
||||
if (alias != map.end())
|
||||
return alias;
|
||||
|
||||
if (!ignoreAddress) {
|
||||
// No data hash.
|
||||
key.cachekey = cachekey;
|
||||
key.hash = 0;
|
||||
alias = aliases_.find(key);
|
||||
|
||||
if (!ignoreAddress_ && alias == aliases_.end()) {
|
||||
// No data hash.
|
||||
key.cachekey = cachekey;
|
||||
key.hash = 0;
|
||||
alias = aliases_.find(key);
|
||||
}
|
||||
|
||||
if (alias == aliases_.end()) {
|
||||
// No address.
|
||||
key.cachekey = cachekey & 0xFFFFFFFFULL;
|
||||
key.hash = hash;
|
||||
alias = aliases_.find(key);
|
||||
}
|
||||
|
||||
if (!ignoreAddress_ && alias == aliases_.end()) {
|
||||
// Address, but not clut hash (in case of garbage clut data.)
|
||||
key.cachekey = cachekey & ~0xFFFFFFFFULL;
|
||||
key.hash = hash;
|
||||
alias = aliases_.find(key);
|
||||
}
|
||||
|
||||
if (alias == aliases_.end()) {
|
||||
// Anything with this data hash (a little dangerous.)
|
||||
key.cachekey = 0;
|
||||
key.hash = hash;
|
||||
alias = aliases_.find(key);
|
||||
}
|
||||
alias = map.find(key);
|
||||
if (alias != map.end())
|
||||
return alias;
|
||||
}
|
||||
|
||||
// No address.
|
||||
key.cachekey = cachekey & 0xFFFFFFFFULL;
|
||||
key.hash = hash;
|
||||
alias = map.find(key);
|
||||
if (alias != map.end())
|
||||
return alias;
|
||||
|
||||
if (!ignoreAddress) {
|
||||
// Address, but not clut hash (in case of garbage clut data.)
|
||||
key.cachekey = cachekey & ~0xFFFFFFFFULL;
|
||||
key.hash = hash;
|
||||
alias = map.find(key);
|
||||
if (alias != map.end())
|
||||
return alias;
|
||||
}
|
||||
|
||||
// Anything with this data hash (a little dangerous.)
|
||||
key.cachekey = 0;
|
||||
key.hash = hash;
|
||||
return map.find(key);
|
||||
}
|
||||
|
||||
bool TextureReplacer::FindFiltering(u64 cachekey, u32 hash, TextureFiltering *forceFiltering) {
|
||||
if (!Enabled() || !g_Config.bReplaceTextures) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReplacementCacheKey replacementKey(cachekey, hash);
|
||||
auto filter = LookupWildcard(filtering_, replacementKey, cachekey, hash, ignoreAddress_);
|
||||
if (filter == filtering_.end()) {
|
||||
// Allow a global wildcard.
|
||||
replacementKey.cachekey = 0;
|
||||
replacementKey.hash = 0;
|
||||
filter = filtering_.find(replacementKey);
|
||||
}
|
||||
if (filter != filtering_.end()) {
|
||||
*forceFiltering = filter->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string TextureReplacer::LookupHashFile(u64 cachekey, u32 hash, int level) {
|
||||
ReplacementAliasKey key(cachekey, hash, level);
|
||||
auto alias = LookupWildcard(aliases_, key, cachekey, hash, ignoreAddress_);
|
||||
if (alias != aliases_.end()) {
|
||||
// Note: this will be blank if explicitly ignored.
|
||||
return alias->second;
|
||||
@ -649,13 +704,15 @@ bool TextureReplacer::GenerateIni(const std::string &gameID, std::string *genera
|
||||
fs << "[games]\n";
|
||||
fs << "# Used to make it easier to install, and override settings for other regions.\n";
|
||||
fs << "# Files still have to be copied to each TEXTURES folder.";
|
||||
fs << gameID << " = textures.ini\n";
|
||||
fs << gameID << " = " << INI_FILENAME << "\n";
|
||||
fs << "\n";
|
||||
fs << "[hashes]\n";
|
||||
fs << "# Use / for folders not \\, avoid special characters, and stick to lowercase.\n";
|
||||
fs << "# See wiki for more info.\n";
|
||||
fs << "[hashes]\n";
|
||||
fs << "\n";
|
||||
fs << "[hashranges]\n";
|
||||
fs << "\n";
|
||||
fs << "[filtering]\n";
|
||||
fs.close();
|
||||
}
|
||||
return File::Exists(texturesDirectory + INI_FILENAME);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <vector>
|
||||
#include "Common/Common.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
|
||||
class IniFile;
|
||||
@ -183,6 +184,7 @@ public:
|
||||
u32 ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV);
|
||||
|
||||
ReplacedTexture &FindReplacement(u64 cachekey, u32 hash, int w, int h);
|
||||
bool FindFiltering(u64 cachekey, u32 hash, TextureFiltering *forceFiltering);
|
||||
|
||||
void NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h);
|
||||
|
||||
@ -192,6 +194,7 @@ protected:
|
||||
bool LoadIni();
|
||||
bool LoadIniValues(IniFile &ini, bool isOverride = false);
|
||||
void ParseHashRange(const std::string &key, const std::string &value);
|
||||
void ParseFiltering(const std::string &key, const std::string &value);
|
||||
bool LookupHashRange(u32 addr, int &w, int &h);
|
||||
std::string LookupHashFile(u64 cachekey, u32 hash, int level);
|
||||
std::string HashName(u64 cachekey, u32 hash, int level);
|
||||
@ -209,6 +212,7 @@ protected:
|
||||
typedef std::pair<int, int> WidthHeightPair;
|
||||
std::unordered_map<u64, WidthHeightPair> hashranges_;
|
||||
std::unordered_map<ReplacementAliasKey, std::string> aliases_;
|
||||
std::unordered_map<ReplacementCacheKey, TextureFiltering> filtering_;
|
||||
|
||||
ReplacedTexture none_;
|
||||
std::unordered_map<ReplacementCacheKey, ReplacedTexture> cache_;
|
||||
|
@ -28,12 +28,6 @@
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
|
||||
enum TextureFiltering {
|
||||
TEX_FILTER_AUTO = 1,
|
||||
TEX_FILTER_FORCE_NEAREST = 2,
|
||||
TEX_FILTER_FORCE_LINEAR = 3,
|
||||
};
|
||||
|
||||
enum FramebufferNotification {
|
||||
NOTIFY_FB_CREATED,
|
||||
NOTIFY_FB_UPDATED,
|
||||
@ -53,6 +47,7 @@ enum FramebufferNotificationChannel {
|
||||
#define TEXCACHE_MAX_TEXELS_SCALED (256*256) // Per frame
|
||||
|
||||
struct VirtualFramebuffer;
|
||||
class TextureReplacer;
|
||||
|
||||
namespace Draw {
|
||||
class DrawContext;
|
||||
|
@ -31,6 +31,12 @@ enum CheckAlphaResult {
|
||||
#include "GPU/Common/TextureDecoderNEON.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
enum TextureFiltering {
|
||||
TEX_FILTER_AUTO = 1,
|
||||
TEX_FILTER_FORCE_NEAREST = 2,
|
||||
TEX_FILTER_FORCE_LINEAR = 3,
|
||||
};
|
||||
|
||||
void SetupTextureDecoder();
|
||||
|
||||
// Pitch must be aligned to 16 bits (as is the case on a PSP)
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "Core/Reporting.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
#include "GPU/Common/TextureCacheCommon.h"
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
#include "GPU/Software/SoftGpu.h"
|
||||
#include "GPU/Software/Rasterizer.h"
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
#include "GPU/Common/PostShader.h"
|
||||
#include "GPU/Common/FramebufferManagerCommon.h"
|
||||
#include "GPU/Common/TextureCacheCommon.h"
|
||||
#include "GPU/Common/TextureDecoder.h"
|
||||
#include "GPU/Common/TextureScalerCommon.h"
|
||||
|
||||
#include "Core/Config.h"
|
||||
|
Loading…
Reference in New Issue
Block a user