Cemu/src/config/CemuConfig.h
Crementif 6d75776b28
Add GDB stub for debugging (#657)
* Implement GDB stub debugger

Can be enabled by using the "--enable-gdbstub" option (and the debugger GUI, although that's untested) which'll pause any game you launch at start-up. Will start at port 1337 although it'll eventually be user-editable. The code is a bit weirdly sorted and also just needs a general cleanup, so expect that eventually too. And uses egyptian braces but formatting was easier to do at the end, so that's also something to do.

It has been tested to work with IDA Pro, Clion and the standalone interface for now, but I plan on writing some instructions in the PR to follow for people who want to use this. Memory breakpoints aren't possible yet, only execution breakpoints.

This code was aimed to be decoupled from the existing debugger to be able to be ported to the Wii U for an equal debugging experience. That's also why it uses the Cafe OS's thread sleep and resuming functions whenever possible instead of using recompiler/interpreter controls.

* Add memory writing and floating point registers support

* Reformat code a bit

* Format code to adhere to Cemu's coding style

* Rework GDB Stub settings in GUI

* Small styling fixes

* Rework execution breakpoints

Should work better in some edge cases now. But this should also allow for adding access breakpoints since it's now more separated.

* Implement access breakpoints

* Fix some issues with breakpoints

* Fix includes for Linux

* Fix unnecessary include

* Tweaks for Linux compatibility

* Use std::thread instead of std::jthread to fix MacOS support

* Enable GDB read/write breakpoints on x86 only

* Fix compilation for GCC compilers at least

The thread type varies on some platforms, so supporting this is hell... but let's get it to compile on MacOS first.

* Disable them for MacOS due to lack of ptrace

---------

Co-authored-by: Exzap <13877693+Exzap@users.noreply.github.com>
2023-02-19 15:41:49 +01:00

509 lines
13 KiB
C++

#pragma once
#include "ConfigValue.h"
#include "XMLConfig.h"
#include "util/math/vector2.h"
#include "Cafe/Account/Account.h"
#include <wx/language.h>
struct GameEntry
{
GameEntry() = default;
std::wstring rpx_file;
std::wstring legacy_name;
std::string product_code;
std::string company_code;
std::string custom_name;
sint32 icon = -1;
sint32 icon_small = -1;
sint32 legacy_version = 0;
sint32 legacy_update_version = -1;
sint32 legacy_dlc_version = -1;
uint64 title_id = 0;
uint32 legacy_region = 0;
std::wstring save_folder;
std::wstring update_folder;
std::wstring dlc_folder;
uint64 legacy_time_played = 0;
uint64 legacy_last_played = 0;
bool favorite = false;
bool is_update = false;
};
struct GraphicPackEntry
{
GraphicPackEntry(std::wstring_view filename,std::string_view category, std::string_view preset)
: filename(filename)
{
presets[std::string{category}] = preset;
}
GraphicPackEntry(std::wstring_view filename, std::string_view preset)
: filename(filename)
{
presets[""] = preset;
}
GraphicPackEntry(std::wstring filename)
: filename(std::move(filename))
{}
struct Preset
{
std::string name;
std::string category;
};
std::unordered_map<std::string, std::string> presets; // category, active_preset
std::wstring filename;
bool enabled = true;
};
enum GraphicAPI
{
kOpenGL = 0,
kVulkan,
};
enum AudioChannels
{
kMono = 0,
kStereo,
kSurround,
};
enum UpscalingFilter
{
kLinearFilter,
kBicubicFilter,
kBicubicHermiteFilter,
kNearestNeighborFilter,
};
enum FullscreenScaling
{
kKeepAspectRatio,
kStretch,
};
enum class ScreenPosition
{
kDisabled = 0,
kTopLeft,
kTopCenter,
kTopRight,
kBottomLeft,
kBottomCenter,
kBottomRight,
};
enum class PrecompiledShaderOption
{
Auto,
Enable,
Disable,
};
ENABLE_ENUM_ITERATORS(PrecompiledShaderOption, PrecompiledShaderOption::Auto, PrecompiledShaderOption::Disable);
enum class AccurateShaderMulOption
{
False = 0, // ignore non-ieee MUL special cases
True = 1, // fully emulate non-ieee MUL special cases
Min = 2, // similar to true, but avoids conditionals (instead relies on min() and abs())
};
ENABLE_ENUM_ITERATORS(AccurateShaderMulOption, AccurateShaderMulOption::False, AccurateShaderMulOption::Min);
enum class CPUMode
{
SinglecoreInterpreter = 0,
SinglecoreRecompiler = 1,
DualcoreRecompiler = 2, // deprecated and not used anymore
MulticoreRecompiler = 3,
Auto = 4,
};
ENABLE_ENUM_ITERATORS(CPUMode, CPUMode::SinglecoreInterpreter, CPUMode::Auto);
enum class CPUModeLegacy
{
SinglecoreInterpreter = 0,
SinglecoreRecompiler = 1,
DualcoreRecompiler = 2,
TriplecoreRecompiler = 3,
Auto = 4
};
ENABLE_ENUM_ITERATORS(CPUModeLegacy, CPUModeLegacy::SinglecoreInterpreter, CPUModeLegacy::Auto);
enum class CafeConsoleRegion
{
JPN = 0x1,
USA = 0x2,
EUR = 0x4,
AUS_DEPR = 0x8,
CHN = 0x10,
KOR = 0x20,
TWN = 0x40,
Auto = 0xFF,
};
ENABLE_BITMASK_OPERATORS(CafeConsoleRegion);
enum class CafeConsoleLanguage
{
JA = 0,
EN = 1,
FR = 2,
DE = 3,
IT = 4,
ES = 5,
ZH = 6,
KO = 7,
NL = 8,
PT = 9,
RU = 10,
TW = 11,
};
ENABLE_ENUM_ITERATORS(CafeConsoleLanguage, CafeConsoleLanguage::JA, CafeConsoleLanguage::TW);
#if BOOST_OS_WINDOWS
enum class CrashDump
{
Disabled,
Lite,
Full
};
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Full);
#elif BOOST_OS_UNIX
enum class CrashDump
{
Disabled,
Enabled
};
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
#endif
template <>
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
template <typename FormatContext>
auto format(const PrecompiledShaderOption c, FormatContext &ctx) {
string_view name;
switch (c)
{
case PrecompiledShaderOption::Auto: name = "auto"; break;
case PrecompiledShaderOption::Enable: name = "true"; break;
case PrecompiledShaderOption::Disable: name = "false"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
template <>
struct fmt::formatter<AccurateShaderMulOption> : formatter<string_view> {
template <typename FormatContext>
auto format(const AccurateShaderMulOption c, FormatContext &ctx) {
string_view name;
switch (c)
{
case AccurateShaderMulOption::True: name = "true"; break;
case AccurateShaderMulOption::False: name = "false"; break;
case AccurateShaderMulOption::Min: name = "min"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
template <>
struct fmt::formatter<CPUMode> : formatter<string_view> {
template <typename FormatContext>
auto format(const CPUMode c, FormatContext &ctx) {
string_view name;
switch (c)
{
case CPUMode::SinglecoreInterpreter: name = "Single-core interpreter"; break;
case CPUMode::SinglecoreRecompiler: name = "Single-core recompiler"; break;
case CPUMode::DualcoreRecompiler: name = "Dual-core recompiler"; break;
case CPUMode::MulticoreRecompiler: name = "Multi-core recompiler"; break;
case CPUMode::Auto: name = "Auto"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
template <>
struct fmt::formatter<CPUModeLegacy> : formatter<string_view> {
template <typename FormatContext>
auto format(const CPUModeLegacy c, FormatContext &ctx) {
string_view name;
switch (c)
{
case CPUModeLegacy::SinglecoreInterpreter: name = "Singlecore-Interpreter"; break;
case CPUModeLegacy::SinglecoreRecompiler: name = "Singlecore-Recompiler"; break;
case CPUModeLegacy::DualcoreRecompiler: name = "Dualcore-Recompiler"; break;
case CPUModeLegacy::TriplecoreRecompiler: name = "Triplecore-Recompiler"; break;
case CPUModeLegacy::Auto: name = "Auto"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
template <>
struct fmt::formatter<CafeConsoleRegion> : formatter<string_view> {
template <typename FormatContext>
auto format(const CafeConsoleRegion v, FormatContext &ctx) {
string_view name;
switch (v)
{
case CafeConsoleRegion::JPN: name = "Japan"; break;
case CafeConsoleRegion::USA: name = "USA"; break;
case CafeConsoleRegion::EUR: name = "Europe"; break;
case CafeConsoleRegion::AUS_DEPR: name = "Australia"; break;
case CafeConsoleRegion::CHN: name = "China"; break;
case CafeConsoleRegion::KOR: name = "Korea"; break;
case CafeConsoleRegion::TWN: name = "Taiwan"; break;
case CafeConsoleRegion::Auto: name = "Auto"; break;
default: name = "many"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
template <>
struct fmt::formatter<CafeConsoleLanguage> : formatter<string_view> {
template <typename FormatContext>
auto format(const CafeConsoleLanguage v, FormatContext &ctx) {
string_view name;
switch (v)
{
case CafeConsoleLanguage::JA: name = "Japanese"; break;
case CafeConsoleLanguage::EN: name = "English"; break;
case CafeConsoleLanguage::FR: name = "French"; break;
case CafeConsoleLanguage::DE: name = "German"; break;
case CafeConsoleLanguage::IT: name = "Italian"; break;
case CafeConsoleLanguage::ES: name = "Spanish"; break;
case CafeConsoleLanguage::ZH: name = "Chinese"; break;
case CafeConsoleLanguage::KO: name = "Korean"; break;
case CafeConsoleLanguage::NL: name = "Dutch"; break;
case CafeConsoleLanguage::PT: name = "Portugese"; break;
case CafeConsoleLanguage::RU: name = "Russian"; break;
case CafeConsoleLanguage::TW: name = "Taiwanese"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
#if BOOST_OS_WINDOWS
template <>
struct fmt::formatter<CrashDump> : formatter<string_view> {
template <typename FormatContext>
auto format(const CrashDump v, FormatContext &ctx) {
string_view name;
switch (v)
{
case CrashDump::Disabled: name = "Disabled"; break;
case CrashDump::Lite: name = "Lite"; break;
case CrashDump::Full: name = "Full"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
#elif BOOST_OS_UNIX
template <>
struct fmt::formatter<CrashDump> : formatter<string_view> {
template <typename FormatContext>
auto format(const CrashDump v, FormatContext &ctx) {
string_view name;
switch (v)
{
case CrashDump::Disabled: name = "Disabled"; break;
case CrashDump::Enabled: name = "Enabled"; break;
default: name = "unknown"; break;
}
return formatter<string_view>::format(name, ctx);
}
};
#endif
namespace DefaultColumnSize {
enum : uint32 {
name = 500u,
version = 60u,
dlc = 50u,
game_time = 140u,
game_started = 160u,
region = 80u,
};
};
struct CemuConfig
{
CemuConfig()
{
};
CemuConfig(const CemuConfig&) = delete;
//
// sets mlc path, updates permanent config value, saves config
void SetMLCPath(fs::path path, bool save = true);
ConfigValue<uint64> log_flag{ 0 };
ConfigValue<bool> advanced_ppc_logging{ false };
ConfigValue<bool> permanent_storage{ true };
ConfigValue<sint32> language{ wxLANGUAGE_DEFAULT };
ConfigValue<bool> use_discord_presence{ true };
ConfigValue<std::string> mlc_path {};
ConfigValue<bool> fullscreen_menubar{ false };
ConfigValue<bool> fullscreen{ false };
ConfigValue<std::string> proxy_server{};
std::vector<std::wstring> game_paths;
std::mutex game_cache_entries_mutex;
std::vector<GameEntry> game_cache_entries;
// optimized access
std::set<uint64> game_cache_favorites; // per titleId
struct _path_hash {
std::size_t operator()(const fs::path& path) const {
return fs::hash_value(path);
}
};
// <filename, <category, preset>>
std::unordered_map<fs::path, std::unordered_map<std::string, std::string>, _path_hash> graphic_pack_entries;
ConfigValueBounds<CPUMode> cpu_mode{ CPUMode::Auto };
ConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };
// max 15 entries
static constexpr size_t kMaxRecentEntries = 15;
std::vector<std::wstring> recent_launch_files;
std::vector<std::wstring> recent_nfc_files;
Vector2i window_position{-1,-1};
Vector2i window_size{ -1,-1 };
ConfigValue<bool> window_maximized;
ConfigValue<bool> pad_open;
Vector2i pad_position{ -1,-1 };
Vector2i pad_size{ -1,-1 };
ConfigValue<bool> pad_maximized;
ConfigValue<bool> check_update{false};
ConfigValue<bool> save_screenshot{true};
ConfigValue<bool> did_show_vulkan_warning{false};
ConfigValue<bool> did_show_graphic_pack_download{false};
ConfigValue<bool> did_show_macos_disclaimer{false};
int game_list_style = 0;
std::string game_list_column_order;
struct
{
uint32 name = DefaultColumnSize::name;
uint32 version = DefaultColumnSize::version;
uint32 dlc = DefaultColumnSize::dlc;
uint32 game_time = DefaultColumnSize::game_time;
uint32 game_started = DefaultColumnSize::game_started;
uint32 region = DefaultColumnSize::region;
} column_width{};
// graphics
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
std::array<uint8, 16> graphic_device_uuid;
ConfigValue<int> vsync{ 0 }; // 0 = off, 1+ = on depending on render backend
ConfigValue<bool> gx2drawdone_sync {true};
ConfigValue<bool> render_upside_down{ false };
ConfigValue<bool> async_compile{ false };
ConfigValue<bool> vk_accurate_barriers{ true };
struct
{
ScreenPosition position = ScreenPosition::kDisabled;
uint32 text_color = 0xFFFFFFFF;
sint32 text_scale = 100;
bool fps = true;
bool drawcalls = false;
bool cpu_usage = false;
bool cpu_per_core_usage = false;
bool ram_usage = false;
bool vram_usage = false;
bool debug = false;
} overlay{};
struct
{
ScreenPosition position = ScreenPosition::kTopLeft;
uint32 text_color = 0xFFFFFFFF;
sint32 text_scale = 100;
bool controller_profiles = true;
bool controller_battery = false;
bool shader_compiling = true;
bool friends = true;
} notification{};
ConfigValue<sint32> upscale_filter{kBicubicFilter};
ConfigValue<sint32> downscale_filter{kLinearFilter};
ConfigValue<sint32> fullscreen_scaling{kKeepAspectRatio};
// audio
sint32 audio_api = 0;
sint32 audio_delay = 2;
AudioChannels tv_channels = kStereo, pad_channels = kStereo, input_channels = kMono;
sint32 tv_volume = 50, pad_volume = 0, input_volume = 50;
std::wstring tv_device{ L"default" }, pad_device, input_device;
// account
struct
{
ConfigValueBounds<uint32> m_persistent_id{ Account::kMinPersistendId, Account::kMinPersistendId, 0xFFFFFFFF };
ConfigValue<bool> online_enabled{false};
ConfigValue<int> active_service{0};
}account{};
// input
struct
{
ConfigValue<std::string> host{"127.0.0.1"};
ConfigValue<uint16> port{ 26760 };
}dsu_client{};
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
void AddRecentlyLaunchedFile(std::wstring_view file);
void AddRecentNfcFile(std::wstring_view file);
bool IsGameListFavorite(uint64 titleId);
void SetGameListFavorite(uint64 titleId, bool isFavorite);
bool GetGameListCustomName(uint64 titleId, std::string& customName);
void SetGameListCustomName(uint64 titleId, std::string customName);
private:
GameEntry* GetGameEntryByTitleId(uint64 titleId);
GameEntry* CreateGameEntry(uint64 titleId);
};
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
extern XMLCemuConfig_t g_config;
inline CemuConfig& GetConfig() { return g_config.data(); }