mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-12 17:58:29 +12:00
332 lines
No EOL
12 KiB
C++
332 lines
No EOL
12 KiB
C++
#pragma once
|
|
|
|
#include "util/helpers/helpers.h"
|
|
#include "Cemu/ExpressionParser/ExpressionParser.h"
|
|
#include "Cafe/HW/Latte/Renderer/RendererOuputShader.h"
|
|
#include "util/helpers/Serializer.h"
|
|
#include "Cafe/OS/RPL/rpl.h"
|
|
#include "Cemu/PPCAssembler/ppcAssembler.h"
|
|
#include <variant>
|
|
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
|
#include "GraphicPack2Patches.h"
|
|
#include "util/IniParser/IniParser.h"
|
|
|
|
class GraphicPack2
|
|
{
|
|
public:
|
|
enum class GP_SHADER_TYPE : uint8
|
|
{
|
|
PIXEL = 0,
|
|
VERTEX = 1,
|
|
GEOMETRY = 2,
|
|
};
|
|
|
|
enum
|
|
{
|
|
GFXPACK_VERSION_5 = 5,
|
|
GFXPACK_VERSION_6 = 6, // added memory extensions
|
|
GFXPACK_VERSION_7 = 7, // added fine-grained origin control in patch format (no more forced 4 byte alignment), .string directive (an alias to .byte) and support for more than one constant per data directive
|
|
};
|
|
|
|
struct TextureRule
|
|
{
|
|
// filter (texture must match these settings)
|
|
struct FILTER_SETTINGS
|
|
{
|
|
enum class MEM1_FILTER {
|
|
BOTH,
|
|
INSIDE,
|
|
OUTSIDE,
|
|
};
|
|
sint32 width = -1;
|
|
sint32 height = -1;
|
|
sint32 depth = -1;
|
|
MEM1_FILTER inMEM1 = MEM1_FILTER::BOTH;
|
|
std::vector<sint32> format_whitelist{};
|
|
std::vector<sint32> format_blacklist{};
|
|
std::vector<sint32> tilemode_whitelist{};
|
|
std::vector<sint32> tilemode_blacklist{};
|
|
} filter_settings;
|
|
// overwrite (if match found, these settings are overwritten)
|
|
struct OVERWRITE_SETTINGS
|
|
{
|
|
sint32 width = -1;
|
|
sint32 height = -1;
|
|
sint32 depth = -1;
|
|
sint32 format = -1;
|
|
sint32 lod_bias = -1; // in 1/64th steps
|
|
sint32 relative_lod_bias = -1; // in 1/64th steps
|
|
sint32 anistropic_value = -1; // 1<<n
|
|
} overwrite_settings;
|
|
};
|
|
|
|
struct CustomShader
|
|
{
|
|
std::string source;
|
|
uint64 shader_base_hash;
|
|
uint64 shader_aux_hash;
|
|
GP_SHADER_TYPE type;
|
|
bool isPreVulkanShader{}; // set to true for V3 packs since the shaders are not compatible with the Vulkan renderer
|
|
};
|
|
|
|
enum VarType
|
|
{
|
|
kDouble = 0,
|
|
kInt = 1,
|
|
};
|
|
using PresetVar = std::pair<VarType, double>;
|
|
|
|
struct Preset
|
|
{
|
|
std::string category; // preset category (empty for default)
|
|
std::string name; // displayed name
|
|
std::string condition;
|
|
std::unordered_map<std::string, PresetVar> variables;
|
|
bool active = false; // selected/active preset
|
|
bool visible = true; // set by condition or true
|
|
bool is_default = false; // selected by default
|
|
|
|
Preset(std::string_view name, std::unordered_map<std::string, PresetVar> vars)
|
|
: name(name), variables(std::move(vars)) {}
|
|
|
|
Preset(std::string_view category, std::string_view name, std::unordered_map<std::string, PresetVar> vars)
|
|
: category(category), name(name), variables(std::move(vars)) {}
|
|
|
|
Preset(std::string_view category, std::string_view name, std::string_view condition, std::unordered_map<std::string, PresetVar> vars)
|
|
: category(category), name(name), condition(condition), variables(std::move(vars)) {}
|
|
};
|
|
using PresetPtr = std::shared_ptr<Preset>;
|
|
|
|
GraphicPack2(fs::path rulesPath, IniParser& rules);
|
|
|
|
bool IsEnabled() const { return m_enabled; }
|
|
bool IsActivated() const { return m_activated; }
|
|
sint32 GetVersion() const { return m_version; }
|
|
const fs::path GetRulesPath() const { return m_rulesPath; }
|
|
std::string GetNormalizedPathString() const;
|
|
bool RequiresRestart(bool changeEnableState, bool changePreset);
|
|
bool Reload();
|
|
|
|
bool HasName() const { return !m_name.empty(); }
|
|
|
|
const std::string& GetName() const { return m_name.empty() ? m_virtualPath : m_name; }
|
|
const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy
|
|
const std::string& GetDescription() const { return m_description; }
|
|
bool IsDefaultEnabled() const { return m_default_enabled; }
|
|
|
|
void SetEnabled(bool state) { m_enabled = state; }
|
|
|
|
bool ContainsTitleId(uint64_t title_id) const;
|
|
const std::vector<uint64_t>& GetTitleIds() const { return m_title_ids; }
|
|
bool HasCustomVSyncFrequency() const { return m_vsync_frequency >= 1; }
|
|
sint32 GetCustomVSyncFrequency() const { return m_vsync_frequency; }
|
|
|
|
// texture rules
|
|
const std::vector<TextureRule>& GetTextureRules() const { return m_texture_rules; }
|
|
|
|
// presets
|
|
[[nodiscard]] bool HasActivePreset() const;
|
|
[[nodiscard]] std::string GetActivePreset(std::string_view category = "") const;
|
|
[[nodiscard]] std::vector<PresetPtr> GetActivePresets() const;
|
|
[[nodiscard]] bool IsPresetVisible(const PresetPtr& preset) const;
|
|
[[nodiscard]] std::optional<PresetVar> GetPresetVariable(const std::vector<PresetPtr>& presets, std::string_view var_name) const;
|
|
|
|
void ValidatePresetSelections();
|
|
bool SetActivePreset(std::string_view category, std::string_view name, bool update_visibility = true);
|
|
bool SetActivePreset(std::string_view name);
|
|
void UpdatePresetVisibility();
|
|
|
|
void AddConstantsForCurrentPreset(ExpressionParser& ep);
|
|
bool ResolvePresetConstant(const std::string& varname, double& value) const;
|
|
|
|
[[nodiscard]] const std::vector<PresetPtr>& GetPresets() const { return m_presets; }
|
|
[[nodiscard]] std::unordered_map<std::string, std::vector<PresetPtr>> GetCategorizedPresets(std::vector<std::string>& order) const;
|
|
|
|
// shaders
|
|
void LoadShaders();
|
|
bool HasShaders() const;
|
|
const std::vector<CustomShader>& GetCustomShaders() const { return m_custom_shaders; }
|
|
|
|
static const std::string* FindCustomShaderSource(uint64 shaderBaseHash, uint64 shaderAuxHash, GP_SHADER_TYPE type, bool isVulkanRenderer);
|
|
|
|
const std::string& GetOutputShaderSource() const { return m_output_shader_source; }
|
|
const std::string& GetDownscalingShaderSource() const { return m_downscaling_shader_source; }
|
|
const std::string& GetUpscalingShaderSource() const { return m_upscaling_shader_source; }
|
|
RendererOutputShader* GetOuputShader(bool render_upside_down);
|
|
RendererOutputShader* GetUpscalingShader(bool render_upside_down);
|
|
RendererOutputShader* GetDownscalingShader(bool render_upside_down);
|
|
LatteTextureView::MagFilter GetUpscalingMagFilter() const { return m_output_settings.upscale_filter; }
|
|
LatteTextureView::MagFilter GetDownscalingMagFilter() const { return m_output_settings.downscale_filter; }
|
|
|
|
// static methods
|
|
static void LoadAll();
|
|
|
|
static const std::vector<std::shared_ptr<GraphicPack2>>& GetGraphicPacks() { return s_graphic_packs; }
|
|
static const std::vector<std::shared_ptr<GraphicPack2>>& GetActiveGraphicPacks() { return s_active_graphic_packs; }
|
|
static void LoadGraphicPack(fs::path graphicPackPath);
|
|
static bool LoadGraphicPack(const fs::path& rulesPath, class IniParser& rules);
|
|
static bool ActivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);
|
|
static bool DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);
|
|
static void ClearGraphicPacks();
|
|
static void WaitUntilReady(); // wait until all graphic packs finished activation
|
|
|
|
static void ActivateForCurrentTitle();
|
|
static void Reset();
|
|
|
|
private:
|
|
bool Activate();
|
|
bool Deactivate();
|
|
|
|
static std::vector<std::shared_ptr<GraphicPack2>> s_graphic_packs;
|
|
static std::vector<std::shared_ptr<GraphicPack2>> s_active_graphic_packs;
|
|
static std::atomic_bool s_isReady;
|
|
|
|
template<typename TType>
|
|
void FillPresetConstants(TExpressionParser<TType>& parser) const
|
|
{
|
|
// fils preset variables with priority
|
|
// active && visible > active > default
|
|
const auto active_presets = GetActivePresets();
|
|
for(const auto& preset : active_presets)
|
|
{
|
|
if(preset->visible)
|
|
{
|
|
for (auto& var : preset->variables)
|
|
parser.AddConstant(var.first, (TType)var.second.second);
|
|
}
|
|
}
|
|
for(const auto& preset : active_presets)
|
|
{
|
|
if(!preset->visible)
|
|
{
|
|
for (auto& var : preset->variables)
|
|
parser.TryAddConstant(var.first, (TType)var.second.second);
|
|
}
|
|
}
|
|
|
|
for (auto& var : m_preset_vars)
|
|
parser.TryAddConstant(var.first, (TType)var.second.second);
|
|
}
|
|
|
|
fs::path m_rulesPath;
|
|
|
|
sint32 m_version;
|
|
std::string m_name;
|
|
std::string m_virtualPath;
|
|
std::string m_description;
|
|
|
|
bool m_default_enabled = false;
|
|
|
|
// filter
|
|
std::optional<RendererAPI> m_renderer_api;
|
|
std::optional<GfxVendor> m_gfx_vendor;
|
|
|
|
bool m_enabled = false;
|
|
bool m_activated = false; // set if the graphic pack is currently used by the running game
|
|
std::vector<uint64_t> m_title_ids;
|
|
bool m_patchedFilesLoaded = false; // set to true once patched files are loaded
|
|
|
|
sint32 m_vsync_frequency = -1;
|
|
sint32 m_fs_priority = 100;
|
|
|
|
struct
|
|
{
|
|
LatteTextureView::MagFilter upscale_filter = LatteTextureView::MagFilter::kLinear;
|
|
LatteTextureView::MagFilter downscale_filter = LatteTextureView::MagFilter::kLinear;
|
|
} m_output_settings;
|
|
|
|
std::vector<PresetPtr> m_presets;
|
|
// default preset vars
|
|
std::unordered_map<std::string, PresetVar> m_preset_vars;
|
|
|
|
std::vector<CustomShader> m_custom_shaders;
|
|
std::vector<TextureRule> m_texture_rules;
|
|
std::string m_output_shader_source, m_upscaling_shader_source, m_downscaling_shader_source;
|
|
std::unique_ptr<RendererOutputShader> m_output_shader, m_upscaling_shader, m_downscaling_shader, m_output_shader_ud, m_upscaling_shader_ud, m_downscaling_shader_ud;
|
|
|
|
template<typename T>
|
|
bool ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const;
|
|
|
|
template<typename T>
|
|
std::vector<T> ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const;
|
|
|
|
std::unordered_map<std::string, PresetVar> ParsePresetVars(IniParser& rules) const;
|
|
|
|
std::vector<uint64> ParseTitleIds(IniParser& rules, const char* option_name) const;
|
|
|
|
CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type) const;
|
|
void ApplyShaderPresets(std::string& shader_source) const;
|
|
void LoadReplacedFiles();
|
|
void _iterateReplacedFiles(const fs::path& currentPath, bool isAOC);
|
|
|
|
// ram mappings
|
|
std::vector<std::pair<MPTR, MPTR>> m_ramMappings;
|
|
|
|
// patches
|
|
void LoadPatchFiles(); // loads Cemuhook or Cemu patches
|
|
bool LoadCemuPatches();
|
|
|
|
void ParseCemuhookPatchesTxtInternal(MemStreamReader& patchesStream);
|
|
bool ParseCemuPatchesTxtInternal(MemStreamReader& patchesStream);
|
|
void CancelParsingPatches();
|
|
|
|
void ApplyPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl);
|
|
void UndoPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl);
|
|
|
|
void AddPatchGroup(PatchGroup* group);
|
|
sint32 GetLengthWithoutComment(const char* str, size_t length);
|
|
void LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg);
|
|
|
|
std::vector<PatchGroup*> list_patchGroups;
|
|
|
|
static std::recursive_mutex mtx_patches;
|
|
static std::vector<const RPLModule*> list_modules;
|
|
|
|
public:
|
|
static std::vector<std::pair<MPTR, MPTR>> GetActiveRAMMappings();
|
|
void EnablePatches();
|
|
void UnloadPatches();
|
|
bool HasPatches();
|
|
const std::vector<PatchGroup*>& GetPatchGroups();
|
|
void ApplyPatchesForModule(const RPLModule* rpl);
|
|
void RevertPatchesForModule(const RPLModule* rpl);
|
|
|
|
static void NotifyModuleLoaded(const RPLModule* rpl);
|
|
static void NotifyModuleUnloaded(const RPLModule* rpl);
|
|
};
|
|
|
|
using GraphicPackPtr = std::shared_ptr<GraphicPack2>;
|
|
|
|
template <typename T>
|
|
bool GraphicPack2::ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const
|
|
{
|
|
auto option_value = iniParser.FindOption(option_name);
|
|
if (option_value)
|
|
{
|
|
*value_out = parser.Evaluate<T>(*option_value);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
std::vector<T> GraphicPack2::ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const
|
|
{
|
|
std::vector<T> result;
|
|
|
|
auto option_text = iniParser.FindOption(option_name);
|
|
if (!option_text)
|
|
return result;
|
|
|
|
for(auto& token : Tokenize(*option_text, ','))
|
|
{
|
|
try
|
|
{
|
|
result.emplace_back(parser.Evaluate<T>(token));
|
|
}
|
|
catch (const std::invalid_argument&) {}
|
|
}
|
|
|
|
return result;
|
|
} |