mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-02 11:03:34 -06:00
* vblank frequency setting fix * force utf-8 encoding upon json serialization/deserialization for path strings
640 lines
30 KiB
C++
640 lines
30 KiB
C++
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <filesystem>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <nlohmann/json.hpp>
|
|
#include "common/logging/log.h"
|
|
#include "common/types.h"
|
|
|
|
#define EmulatorSettings (*EmulatorSettingsImpl::GetInstance())
|
|
|
|
enum HideCursorState : int {
|
|
Never,
|
|
Idle,
|
|
Always,
|
|
};
|
|
|
|
enum UsbBackendType : int {
|
|
Real,
|
|
SkylandersPortal,
|
|
InfinityBase,
|
|
DimensionsToypad,
|
|
};
|
|
|
|
enum GpuReadbacksMode : int {
|
|
Disabled,
|
|
Relaxed,
|
|
Precise,
|
|
};
|
|
|
|
enum class ConfigMode {
|
|
Default,
|
|
Global,
|
|
Clean,
|
|
};
|
|
|
|
enum AudioBackend : int {
|
|
SDL,
|
|
OpenAL,
|
|
// Add more backends as needed
|
|
};
|
|
|
|
template <typename T>
|
|
struct Setting {
|
|
T default_value{};
|
|
T value{};
|
|
std::optional<T> game_specific_value{};
|
|
|
|
Setting() = default;
|
|
// Single-argument ctor: initialises both default_value and value so
|
|
// that CleanMode can always recover the intended factory default.
|
|
/*implicit*/ Setting(T init) : default_value(std::move(init)), value(default_value) {}
|
|
|
|
/// Return the active value under the given mode.
|
|
T get(ConfigMode mode = ConfigMode::Default) const {
|
|
switch (mode) {
|
|
case ConfigMode::Default:
|
|
return game_specific_value.value_or(value);
|
|
case ConfigMode::Global:
|
|
return value;
|
|
case ConfigMode::Clean:
|
|
return default_value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/// Write v to the base layer.
|
|
/// Game-specific overrides are applied exclusively via Load(serial)
|
|
void set(const T& v) {
|
|
value = v;
|
|
}
|
|
|
|
/// Discard the game-specific override; subsequent get(Default) will
|
|
/// fall back to the base value.
|
|
void reset_game_specific() {
|
|
game_specific_value = std::nullopt;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
void to_json(nlohmann::json& j, const Setting<T>& s) {
|
|
j = s.value;
|
|
}
|
|
|
|
template <typename T>
|
|
void from_json(const nlohmann::json& j, Setting<T>& s) {
|
|
s.value = j.get<T>();
|
|
}
|
|
|
|
struct OverrideItem {
|
|
const char* key;
|
|
std::function<void(void* group_ptr, const nlohmann::json& entry,
|
|
std::vector<std::string>& changed)>
|
|
apply;
|
|
/// Return the value that should be written to the per-game config file.
|
|
/// Falls back to base value if no game-specific override is set.
|
|
std::function<nlohmann::json(const void* group_ptr)> get_for_save;
|
|
|
|
/// Clear game_specific_value for this field.
|
|
std::function<void(void* group_ptr)> reset_game_specific;
|
|
};
|
|
|
|
template <typename Struct, typename T>
|
|
inline OverrideItem make_override(const char* key, Setting<T> Struct::* member) {
|
|
return OverrideItem{
|
|
key,
|
|
[member, key](void* base, const nlohmann::json& entry, std::vector<std::string>& changed) {
|
|
LOG_DEBUG(Config, "[make_override] Processing key: {}", key);
|
|
LOG_DEBUG(Config, "[make_override] Entry JSON: {}", entry.dump());
|
|
Struct* obj = reinterpret_cast<Struct*>(base);
|
|
Setting<T>& dst = obj->*member;
|
|
try {
|
|
T newValue = entry.get<T>();
|
|
LOG_DEBUG(Config, "[make_override] Parsed value: {}", newValue);
|
|
LOG_DEBUG(Config, "[make_override] Current value: {}", dst.value);
|
|
if (dst.value != newValue) {
|
|
std::ostringstream oss;
|
|
oss << key << " ( " << dst.value << " → " << newValue << " )";
|
|
changed.push_back(oss.str());
|
|
LOG_DEBUG(Config, "[make_override] Recorded change: {}", oss.str());
|
|
}
|
|
dst.game_specific_value = newValue;
|
|
LOG_DEBUG(Config, "[make_override] Successfully updated {}", key);
|
|
} catch (const std::exception& e) {
|
|
LOG_ERROR(Config, "[make_override] ERROR parsing {}: {}", key, e.what());
|
|
LOG_ERROR(Config, "[make_override] Entry was: {}", entry.dump());
|
|
LOG_ERROR(Config, "[make_override] Type name: {}", entry.type_name());
|
|
}
|
|
},
|
|
|
|
// --- get_for_save -------------------------------------------
|
|
// Returns game_specific_value when present, otherwise base value.
|
|
// This means a freshly-opened game-specific dialog still shows
|
|
// useful (current-global) values rather than empty entries.
|
|
[member](const void* base) -> nlohmann::json {
|
|
const Struct* obj = reinterpret_cast<const Struct*>(base);
|
|
const Setting<T>& src = obj->*member;
|
|
return nlohmann::json(src.game_specific_value.value_or(src.value));
|
|
},
|
|
|
|
// --- reset_game_specific ------------------------------------
|
|
[member](void* base) {
|
|
Struct* obj = reinterpret_cast<Struct*>(base);
|
|
(obj->*member).reset_game_specific();
|
|
}};
|
|
}
|
|
|
|
// -------------------------------
|
|
// Support types
|
|
// -------------------------------
|
|
struct GameInstallDir {
|
|
std::filesystem::path path;
|
|
bool enabled;
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GameInstallDir, path, enabled)
|
|
|
|
// -------------------------------
|
|
// General settings
|
|
// -------------------------------
|
|
struct GeneralSettings {
|
|
Setting<std::vector<GameInstallDir>> install_dirs;
|
|
Setting<std::filesystem::path> addon_install_dir;
|
|
Setting<std::filesystem::path> home_dir;
|
|
Setting<std::filesystem::path> sys_modules_dir;
|
|
Setting<std::filesystem::path> font_dir;
|
|
|
|
Setting<int> volume_slider{100};
|
|
Setting<bool> neo_mode{false};
|
|
Setting<bool> dev_kit_mode{false};
|
|
Setting<int> extra_dmem_in_mbytes{0};
|
|
Setting<bool> psn_signed_in{false};
|
|
Setting<bool> trophy_popup_disabled{false};
|
|
Setting<double> trophy_notification_duration{6.0};
|
|
Setting<std::string> trophy_notification_side{"right"};
|
|
Setting<std::string> log_filter{""};
|
|
Setting<std::string> log_type{"sync"};
|
|
Setting<bool> show_splash{false};
|
|
Setting<bool> identical_log_grouped{true};
|
|
Setting<bool> connected_to_network{false};
|
|
Setting<bool> discord_rpc_enabled{false};
|
|
Setting<bool> show_fps_counter{false};
|
|
Setting<int> console_language{1};
|
|
|
|
// return a vector of override descriptors (runtime, but tiny)
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<GeneralSettings>("volume_slider", &GeneralSettings::volume_slider),
|
|
make_override<GeneralSettings>("neo_mode", &GeneralSettings::neo_mode),
|
|
make_override<GeneralSettings>("dev_kit_mode", &GeneralSettings::dev_kit_mode),
|
|
make_override<GeneralSettings>("extra_dmem_in_mbytes",
|
|
&GeneralSettings::extra_dmem_in_mbytes),
|
|
make_override<GeneralSettings>("psn_signed_in", &GeneralSettings::psn_signed_in),
|
|
make_override<GeneralSettings>("trophy_popup_disabled",
|
|
&GeneralSettings::trophy_popup_disabled),
|
|
make_override<GeneralSettings>("trophy_notification_duration",
|
|
&GeneralSettings::trophy_notification_duration),
|
|
make_override<GeneralSettings>("log_filter", &GeneralSettings::log_filter),
|
|
make_override<GeneralSettings>("log_type", &GeneralSettings::log_type),
|
|
make_override<GeneralSettings>("identical_log_grouped",
|
|
&GeneralSettings::identical_log_grouped),
|
|
make_override<GeneralSettings>("show_splash", &GeneralSettings::show_splash),
|
|
make_override<GeneralSettings>("trophy_notification_side",
|
|
&GeneralSettings::trophy_notification_side),
|
|
make_override<GeneralSettings>("connected_to_network",
|
|
&GeneralSettings::connected_to_network)};
|
|
}
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GeneralSettings, install_dirs, addon_install_dir, home_dir,
|
|
sys_modules_dir, font_dir, volume_slider, neo_mode, dev_kit_mode,
|
|
extra_dmem_in_mbytes, psn_signed_in, trophy_popup_disabled,
|
|
trophy_notification_duration, log_filter, log_type, show_splash,
|
|
identical_log_grouped, trophy_notification_side,
|
|
connected_to_network, discord_rpc_enabled, show_fps_counter,
|
|
console_language)
|
|
|
|
// -------------------------------
|
|
// Debug settings
|
|
// -------------------------------
|
|
struct DebugSettings {
|
|
Setting<bool> separate_logging_enabled{false}; // specific
|
|
Setting<bool> debug_dump{false}; // specific
|
|
Setting<bool> shader_collect{false}; // specific
|
|
Setting<bool> log_enabled{true}; // specific
|
|
Setting<std::string> config_version{""}; // specific
|
|
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<DebugSettings>("debug_dump", &DebugSettings::debug_dump),
|
|
make_override<DebugSettings>("shader_collect", &DebugSettings::shader_collect),
|
|
make_override<DebugSettings>("separate_logging_enabled",
|
|
&DebugSettings::separate_logging_enabled),
|
|
make_override<DebugSettings>("log_enabled", &DebugSettings::log_enabled)};
|
|
}
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(DebugSettings, separate_logging_enabled, debug_dump,
|
|
shader_collect, log_enabled, config_version)
|
|
|
|
// -------------------------------
|
|
// Input settings
|
|
// -------------------------------
|
|
|
|
struct InputSettings {
|
|
Setting<int> cursor_state{HideCursorState::Idle}; // specific
|
|
Setting<int> cursor_hide_timeout{5}; // specific
|
|
Setting<int> usb_device_backend{UsbBackendType::Real}; // specific
|
|
Setting<bool> use_special_pad{false};
|
|
Setting<int> special_pad_class{1};
|
|
Setting<bool> motion_controls_enabled{true}; // specific
|
|
Setting<bool> use_unified_input_config{true};
|
|
Setting<std::string> default_controller_id{""};
|
|
Setting<bool> background_controller_input{false}; // specific
|
|
Setting<s32> camera_id{-1};
|
|
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<InputSettings>("cursor_state", &InputSettings::cursor_state),
|
|
make_override<InputSettings>("cursor_hide_timeout",
|
|
&InputSettings::cursor_hide_timeout),
|
|
make_override<InputSettings>("usb_device_backend", &InputSettings::usb_device_backend),
|
|
make_override<InputSettings>("motion_controls_enabled",
|
|
&InputSettings::motion_controls_enabled),
|
|
make_override<InputSettings>("background_controller_input",
|
|
&InputSettings::background_controller_input),
|
|
make_override<InputSettings>("camera_id", &InputSettings::camera_id)};
|
|
}
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(InputSettings, cursor_state, cursor_hide_timeout,
|
|
usb_device_backend, use_special_pad, special_pad_class,
|
|
motion_controls_enabled, use_unified_input_config,
|
|
default_controller_id, background_controller_input, camera_id)
|
|
// -------------------------------
|
|
// Audio settings
|
|
// -------------------------------
|
|
struct AudioSettings {
|
|
Setting<u32> audio_backend{AudioBackend::SDL};
|
|
Setting<std::string> sdl_mic_device{"Default Device"};
|
|
Setting<std::string> sdl_main_output_device{"Default Device"};
|
|
Setting<std::string> sdl_padSpk_output_device{"Default Device"};
|
|
Setting<std::string> openal_mic_device{"Default Device"};
|
|
Setting<std::string> openal_main_output_device{"Default Device"};
|
|
Setting<std::string> openal_padSpk_output_device{"Default Device"};
|
|
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<AudioSettings>("audio_backend", &AudioSettings::audio_backend),
|
|
make_override<AudioSettings>("sdl_mic_device", &AudioSettings::sdl_mic_device),
|
|
make_override<AudioSettings>("sdl_main_output_device",
|
|
&AudioSettings::sdl_main_output_device),
|
|
make_override<AudioSettings>("sdl_padSpk_output_device",
|
|
&AudioSettings::sdl_padSpk_output_device),
|
|
make_override<AudioSettings>("openal_mic_device", &AudioSettings::openal_mic_device),
|
|
make_override<AudioSettings>("openal_main_output_device",
|
|
&AudioSettings::openal_main_output_device),
|
|
make_override<AudioSettings>("openal_padSpk_output_device",
|
|
&AudioSettings::openal_padSpk_output_device)};
|
|
}
|
|
};
|
|
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioSettings, audio_backend, sdl_mic_device,
|
|
sdl_main_output_device, sdl_padSpk_output_device,
|
|
openal_mic_device, openal_main_output_device,
|
|
openal_padSpk_output_device)
|
|
|
|
// -------------------------------
|
|
// GPU settings
|
|
// -------------------------------
|
|
struct GPUSettings {
|
|
Setting<u32> window_width{1280};
|
|
Setting<u32> window_height{720};
|
|
Setting<u32> internal_screen_width{1280};
|
|
Setting<u32> internal_screen_height{720};
|
|
Setting<bool> null_gpu{false};
|
|
Setting<bool> copy_gpu_buffers{false};
|
|
Setting<u32> readbacks_mode{GpuReadbacksMode::Disabled};
|
|
Setting<bool> readback_linear_images_enabled{false};
|
|
Setting<bool> direct_memory_access_enabled{false};
|
|
Setting<bool> dump_shaders{false};
|
|
Setting<bool> patch_shaders{false};
|
|
Setting<u32> vblank_frequency{60};
|
|
Setting<bool> full_screen{false};
|
|
Setting<std::string> full_screen_mode{"Windowed"};
|
|
Setting<std::string> present_mode{"Mailbox"};
|
|
Setting<bool> hdr_allowed{false};
|
|
Setting<bool> fsr_enabled{false};
|
|
Setting<bool> rcas_enabled{true};
|
|
Setting<int> rcas_attenuation{250};
|
|
// TODO add overrides
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<GPUSettings>("null_gpu", &GPUSettings::null_gpu),
|
|
make_override<GPUSettings>("copy_gpu_buffers", &GPUSettings::copy_gpu_buffers),
|
|
make_override<GPUSettings>("full_screen", &GPUSettings::full_screen),
|
|
make_override<GPUSettings>("full_screen_mode", &GPUSettings::full_screen_mode),
|
|
make_override<GPUSettings>("present_mode", &GPUSettings::present_mode),
|
|
make_override<GPUSettings>("window_height", &GPUSettings::window_height),
|
|
make_override<GPUSettings>("window_width", &GPUSettings::window_width),
|
|
make_override<GPUSettings>("hdr_allowed", &GPUSettings::hdr_allowed),
|
|
make_override<GPUSettings>("fsr_enabled", &GPUSettings::fsr_enabled),
|
|
make_override<GPUSettings>("rcas_enabled", &GPUSettings::rcas_enabled),
|
|
make_override<GPUSettings>("rcas_attenuation", &GPUSettings::rcas_attenuation),
|
|
make_override<GPUSettings>("dump_shaders", &GPUSettings::dump_shaders),
|
|
make_override<GPUSettings>("patch_shaders", &GPUSettings::patch_shaders),
|
|
make_override<GPUSettings>("readbacks_mode", &GPUSettings::readbacks_mode),
|
|
make_override<GPUSettings>("readback_linear_images_enabled",
|
|
&GPUSettings::readback_linear_images_enabled),
|
|
make_override<GPUSettings>("direct_memory_access_enabled",
|
|
&GPUSettings::direct_memory_access_enabled),
|
|
make_override<GPUSettings>("vblank_frequency", &GPUSettings::vblank_frequency),
|
|
};
|
|
}
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GPUSettings, window_width, window_height, internal_screen_width,
|
|
internal_screen_height, null_gpu, copy_gpu_buffers,
|
|
readbacks_mode, readback_linear_images_enabled,
|
|
direct_memory_access_enabled, dump_shaders, patch_shaders,
|
|
vblank_frequency, full_screen, full_screen_mode, present_mode,
|
|
hdr_allowed, fsr_enabled, rcas_enabled, rcas_attenuation)
|
|
// -------------------------------
|
|
// Vulkan settings
|
|
// -------------------------------
|
|
struct VulkanSettings {
|
|
Setting<s32> gpu_id{-1};
|
|
Setting<bool> renderdoc_enabled{false};
|
|
Setting<bool> vkvalidation_enabled{false};
|
|
Setting<bool> vkvalidation_core_enabled{true};
|
|
Setting<bool> vkvalidation_sync_enabled{false};
|
|
Setting<bool> vkvalidation_gpu_enabled{false};
|
|
Setting<bool> vkcrash_diagnostic_enabled{false};
|
|
Setting<bool> vkhost_markers{false};
|
|
Setting<bool> vkguest_markers{false};
|
|
Setting<bool> pipeline_cache_enabled{false};
|
|
Setting<bool> pipeline_cache_archived{false};
|
|
std::vector<OverrideItem> GetOverrideableFields() const {
|
|
return std::vector<OverrideItem>{
|
|
make_override<VulkanSettings>("gpu_id", &VulkanSettings::gpu_id),
|
|
make_override<VulkanSettings>("renderdoc_enabled", &VulkanSettings::renderdoc_enabled),
|
|
make_override<VulkanSettings>("vkvalidation_enabled",
|
|
&VulkanSettings::vkvalidation_enabled),
|
|
make_override<VulkanSettings>("vkvalidation_core_enabled",
|
|
&VulkanSettings::vkvalidation_core_enabled),
|
|
make_override<VulkanSettings>("vkvalidation_sync_enabled",
|
|
&VulkanSettings::vkvalidation_sync_enabled),
|
|
make_override<VulkanSettings>("vkvalidation_gpu_enabled",
|
|
&VulkanSettings::vkvalidation_gpu_enabled),
|
|
make_override<VulkanSettings>("vkcrash_diagnostic_enabled",
|
|
&VulkanSettings::vkcrash_diagnostic_enabled),
|
|
make_override<VulkanSettings>("vkhost_markers", &VulkanSettings::vkhost_markers),
|
|
make_override<VulkanSettings>("vkguest_markers", &VulkanSettings::vkguest_markers),
|
|
make_override<VulkanSettings>("pipeline_cache_enabled",
|
|
&VulkanSettings::pipeline_cache_enabled),
|
|
make_override<VulkanSettings>("pipeline_cache_archived",
|
|
&VulkanSettings::pipeline_cache_archived),
|
|
};
|
|
}
|
|
};
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VulkanSettings, gpu_id, renderdoc_enabled, vkvalidation_enabled,
|
|
vkvalidation_core_enabled, vkvalidation_sync_enabled,
|
|
vkvalidation_gpu_enabled, vkcrash_diagnostic_enabled,
|
|
vkhost_markers, vkguest_markers, pipeline_cache_enabled,
|
|
pipeline_cache_archived)
|
|
|
|
// -------------------------------
|
|
// Main manager
|
|
// -------------------------------
|
|
class EmulatorSettingsImpl {
|
|
public:
|
|
EmulatorSettingsImpl();
|
|
~EmulatorSettingsImpl();
|
|
|
|
static std::shared_ptr<EmulatorSettingsImpl> GetInstance();
|
|
static void SetInstance(std::shared_ptr<EmulatorSettingsImpl> instance);
|
|
|
|
bool Save(const std::string& serial = "");
|
|
bool Load(const std::string& serial = "");
|
|
void SetDefaultValues();
|
|
bool TransferSettings();
|
|
|
|
// Config mode
|
|
ConfigMode GetConfigMode() const {
|
|
return m_configMode;
|
|
}
|
|
void SetConfigMode(ConfigMode mode) {
|
|
m_configMode = mode;
|
|
}
|
|
|
|
//
|
|
// Game-specific override management
|
|
/// Clears all per-game overrides. Call this when a game exits so
|
|
/// the emulator reverts to global settings.
|
|
void ClearGameSpecificOverrides();
|
|
|
|
/// Reset a single field's game-specific override by its JSON ke
|
|
void ResetGameSpecificValue(const std::string& key);
|
|
|
|
// general accessors
|
|
bool AddGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
|
|
std::vector<std::filesystem::path> GetGameInstallDirs() const;
|
|
void SetAllGameInstallDirs(const std::vector<GameInstallDir>& dirs);
|
|
void RemoveGameInstallDir(const std::filesystem::path& dir);
|
|
void SetGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
|
|
void SetGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
|
|
const std::vector<bool> GetGameInstallDirsEnabled();
|
|
const std::vector<GameInstallDir>& GetAllGameInstallDirs() const;
|
|
|
|
std::filesystem::path GetHomeDir();
|
|
void SetHomeDir(const std::filesystem::path& dir);
|
|
std::filesystem::path GetSysModulesDir();
|
|
void SetSysModulesDir(const std::filesystem::path& dir);
|
|
std::filesystem::path GetFontsDir();
|
|
void SetFontsDir(const std::filesystem::path& dir);
|
|
|
|
private:
|
|
GeneralSettings m_general{};
|
|
DebugSettings m_debug{};
|
|
InputSettings m_input{};
|
|
AudioSettings m_audio{};
|
|
GPUSettings m_gpu{};
|
|
VulkanSettings m_vulkan{};
|
|
ConfigMode m_configMode{ConfigMode::Default};
|
|
|
|
bool m_loaded{false};
|
|
|
|
static std::shared_ptr<EmulatorSettingsImpl> s_instance;
|
|
static std::mutex s_mutex;
|
|
|
|
/// Apply overrideable fields from groupJson into group.game_specific_value.
|
|
template <typename Group>
|
|
void ApplyGroupOverrides(Group& group, const nlohmann::json& groupJson,
|
|
std::vector<std::string>& changed) {
|
|
for (auto& item : group.GetOverrideableFields()) {
|
|
if (!groupJson.contains(item.key))
|
|
continue;
|
|
item.apply(&group, groupJson.at(item.key), changed);
|
|
}
|
|
}
|
|
|
|
// Write all overrideable fields from group into out (for game-specific save).
|
|
template <typename Group>
|
|
static void SaveGroupGameSpecific(const Group& group, nlohmann::json& out) {
|
|
for (auto& item : group.GetOverrideableFields())
|
|
out[item.key] = item.get_for_save(&group);
|
|
}
|
|
|
|
// Discard every game-specific override in group.
|
|
template <typename Group>
|
|
static void ClearGroupOverrides(Group& group) {
|
|
for (auto& item : group.GetOverrideableFields())
|
|
item.reset_game_specific(&group);
|
|
}
|
|
|
|
static void PrintChangedSummary(const std::vector<std::string>& changed);
|
|
|
|
public:
|
|
// Add these getters to access overrideable fields
|
|
std::vector<OverrideItem> GetGeneralOverrideableFields() const {
|
|
return m_general.GetOverrideableFields();
|
|
}
|
|
std::vector<OverrideItem> GetDebugOverrideableFields() const {
|
|
return m_debug.GetOverrideableFields();
|
|
}
|
|
std::vector<OverrideItem> GetInputOverrideableFields() const {
|
|
return m_input.GetOverrideableFields();
|
|
}
|
|
std::vector<OverrideItem> GetAudioOverrideableFields() const {
|
|
return m_audio.GetOverrideableFields();
|
|
}
|
|
std::vector<OverrideItem> GetGPUOverrideableFields() const {
|
|
return m_gpu.GetOverrideableFields();
|
|
}
|
|
std::vector<OverrideItem> GetVulkanOverrideableFields() const {
|
|
return m_vulkan.GetOverrideableFields();
|
|
}
|
|
std::vector<std::string> GetAllOverrideableKeys() const;
|
|
|
|
#define SETTING_FORWARD(group, Name, field) \
|
|
auto Get##Name() const { \
|
|
return (group).field.get(m_configMode); \
|
|
} \
|
|
void Set##Name(const decltype((group).field.value)& v) { \
|
|
(group).field.value = v; \
|
|
}
|
|
#define SETTING_FORWARD_BOOL(group, Name, field) \
|
|
bool Is##Name() const { \
|
|
return (group).field.get(m_configMode); \
|
|
} \
|
|
void Set##Name(bool v) { \
|
|
(group).field.value = v; \
|
|
}
|
|
#define SETTING_FORWARD_BOOL_READONLY(group, Name, field) \
|
|
bool Is##Name() const { \
|
|
return (group).field.get(m_configMode); \
|
|
}
|
|
|
|
// General settings
|
|
SETTING_FORWARD(m_general, VolumeSlider, volume_slider)
|
|
SETTING_FORWARD_BOOL(m_general, Neo, neo_mode)
|
|
SETTING_FORWARD_BOOL(m_general, DevKit, dev_kit_mode)
|
|
SETTING_FORWARD(m_general, ExtraDmemInMBytes, extra_dmem_in_mbytes)
|
|
SETTING_FORWARD_BOOL(m_general, PSNSignedIn, psn_signed_in)
|
|
SETTING_FORWARD_BOOL(m_general, TrophyPopupDisabled, trophy_popup_disabled)
|
|
SETTING_FORWARD(m_general, TrophyNotificationDuration, trophy_notification_duration)
|
|
SETTING_FORWARD(m_general, TrophyNotificationSide, trophy_notification_side)
|
|
SETTING_FORWARD_BOOL(m_general, ShowSplash, show_splash)
|
|
SETTING_FORWARD_BOOL(m_general, IdenticalLogGrouped, identical_log_grouped)
|
|
SETTING_FORWARD(m_general, AddonInstallDir, addon_install_dir)
|
|
SETTING_FORWARD(m_general, LogFilter, log_filter)
|
|
SETTING_FORWARD(m_general, LogType, log_type)
|
|
SETTING_FORWARD_BOOL(m_general, ConnectedToNetwork, connected_to_network)
|
|
SETTING_FORWARD_BOOL(m_general, DiscordRPCEnabled, discord_rpc_enabled)
|
|
SETTING_FORWARD_BOOL(m_general, ShowFpsCounter, show_fps_counter)
|
|
SETTING_FORWARD(m_general, ConsoleLanguage, console_language)
|
|
|
|
// Audio settings
|
|
SETTING_FORWARD(m_audio, AudioBackend, audio_backend)
|
|
SETTING_FORWARD(m_audio, SDLMicDevice, sdl_mic_device)
|
|
SETTING_FORWARD(m_audio, SDLMainOutputDevice, sdl_main_output_device)
|
|
SETTING_FORWARD(m_audio, SDLPadSpkOutputDevice, sdl_padSpk_output_device)
|
|
SETTING_FORWARD(m_audio, OpenALMicDevice, openal_mic_device)
|
|
SETTING_FORWARD(m_audio, OpenALMainOutputDevice, openal_main_output_device)
|
|
SETTING_FORWARD(m_audio, OpenALPadSpkOutputDevice, openal_padSpk_output_device)
|
|
|
|
// Debug settings
|
|
SETTING_FORWARD_BOOL(m_debug, SeparateLoggingEnabled, separate_logging_enabled)
|
|
SETTING_FORWARD_BOOL(m_debug, DebugDump, debug_dump)
|
|
SETTING_FORWARD_BOOL(m_debug, ShaderCollect, shader_collect)
|
|
SETTING_FORWARD_BOOL(m_debug, LogEnabled, log_enabled)
|
|
SETTING_FORWARD(m_debug, ConfigVersion, config_version)
|
|
|
|
// GPU Settings
|
|
SETTING_FORWARD_BOOL(m_gpu, NullGPU, null_gpu)
|
|
SETTING_FORWARD_BOOL(m_gpu, DumpShaders, dump_shaders)
|
|
SETTING_FORWARD_BOOL(m_gpu, CopyGpuBuffers, copy_gpu_buffers)
|
|
SETTING_FORWARD_BOOL(m_gpu, FullScreen, full_screen)
|
|
SETTING_FORWARD(m_gpu, FullScreenMode, full_screen_mode)
|
|
SETTING_FORWARD(m_gpu, PresentMode, present_mode)
|
|
SETTING_FORWARD(m_gpu, WindowHeight, window_height)
|
|
SETTING_FORWARD(m_gpu, WindowWidth, window_width)
|
|
SETTING_FORWARD(m_gpu, InternalScreenHeight, internal_screen_height)
|
|
SETTING_FORWARD(m_gpu, InternalScreenWidth, internal_screen_width)
|
|
SETTING_FORWARD_BOOL(m_gpu, HdrAllowed, hdr_allowed)
|
|
SETTING_FORWARD_BOOL(m_gpu, FsrEnabled, fsr_enabled)
|
|
SETTING_FORWARD_BOOL(m_gpu, RcasEnabled, rcas_enabled)
|
|
SETTING_FORWARD(m_gpu, RcasAttenuation, rcas_attenuation)
|
|
SETTING_FORWARD(m_gpu, ReadbacksMode, readbacks_mode)
|
|
SETTING_FORWARD_BOOL(m_gpu, ReadbackLinearImagesEnabled, readback_linear_images_enabled)
|
|
SETTING_FORWARD_BOOL(m_gpu, DirectMemoryAccessEnabled, direct_memory_access_enabled)
|
|
SETTING_FORWARD_BOOL_READONLY(m_gpu, PatchShaders, patch_shaders)
|
|
|
|
u32 GetVblankFrequency() {
|
|
if (m_gpu.vblank_frequency.value < 30) {
|
|
return 30;
|
|
}
|
|
return m_gpu.vblank_frequency.get();
|
|
}
|
|
void SetVblankFrequency(const u32& v, bool is_specific = false) {
|
|
u32 val = v < 30 ? 30 : v;
|
|
if (is_specific) {
|
|
m_gpu.vblank_frequency.game_specific_value = val;
|
|
} else {
|
|
m_gpu.vblank_frequency.value = val;
|
|
}
|
|
}
|
|
|
|
// Input Settings
|
|
SETTING_FORWARD(m_input, CursorState, cursor_state)
|
|
SETTING_FORWARD(m_input, CursorHideTimeout, cursor_hide_timeout)
|
|
SETTING_FORWARD(m_input, UsbDeviceBackend, usb_device_backend)
|
|
SETTING_FORWARD_BOOL(m_input, MotionControlsEnabled, motion_controls_enabled)
|
|
SETTING_FORWARD_BOOL(m_input, BackgroundControllerInput, background_controller_input)
|
|
SETTING_FORWARD(m_input, DefaultControllerId, default_controller_id)
|
|
SETTING_FORWARD_BOOL(m_input, UsingSpecialPad, use_special_pad)
|
|
SETTING_FORWARD(m_input, SpecialPadClass, special_pad_class)
|
|
SETTING_FORWARD_BOOL(m_input, UseUnifiedInputConfig, use_unified_input_config)
|
|
SETTING_FORWARD(m_input, CameraId, camera_id)
|
|
|
|
// Vulkan settings
|
|
SETTING_FORWARD(m_vulkan, GpuId, gpu_id)
|
|
SETTING_FORWARD_BOOL(m_vulkan, RenderdocEnabled, renderdoc_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkValidationEnabled, vkvalidation_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkValidationCoreEnabled, vkvalidation_core_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkValidationSyncEnabled, vkvalidation_sync_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkValidationGpuEnabled, vkvalidation_gpu_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkCrashDiagnosticEnabled, vkcrash_diagnostic_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkHostMarkersEnabled, vkhost_markers)
|
|
SETTING_FORWARD_BOOL(m_vulkan, VkGuestMarkersEnabled, vkguest_markers)
|
|
SETTING_FORWARD_BOOL(m_vulkan, PipelineCacheEnabled, pipeline_cache_enabled)
|
|
SETTING_FORWARD_BOOL(m_vulkan, PipelineCacheArchived, pipeline_cache_archived)
|
|
|
|
#undef SETTING_FORWARD
|
|
#undef SETTING_FORWARD_BOOL
|
|
#undef SETTING_FORWARD_BOOL_READONLY
|
|
};
|