diff options
| author | 2019-03-25 20:30:36 -0400 | |
|---|---|---|
| committer | 2019-06-10 00:03:11 -0400 | |
| commit | 819006d0d3232d66d303daabe701ca031e4caeae (patch) | |
| tree | 536d1a37cc7bd0f578bfdf5f8d32d81e9d6625c4 /src | |
| parent | yuzu_tester: Add project subdirectory (diff) | |
| download | yuzu-819006d0d3232d66d303daabe701ca031e4caeae.tar.gz yuzu-819006d0d3232d66d303daabe701ca031e4caeae.tar.xz yuzu-819006d0d3232d66d303daabe701ca031e4caeae.zip | |
yuzu_tester: Use config, icon, and main from yuzu-cmd
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuzu_tester/config.cpp | 185 | ||||
| -rw-r--r-- | src/yuzu_tester/config.h | 24 | ||||
| -rw-r--r-- | src/yuzu_tester/default_ini.h | 150 | ||||
| -rw-r--r-- | src/yuzu_tester/resource.h | 16 | ||||
| -rw-r--r-- | src/yuzu_tester/yuzu.cpp | 232 | ||||
| -rw-r--r-- | src/yuzu_tester/yuzu.rc | 17 |
6 files changed, 624 insertions, 0 deletions
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp new file mode 100644 index 000000000..62407efac --- /dev/null +++ b/src/yuzu_tester/config.cpp | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <sstream> | ||
| 7 | #include <SDL.h> | ||
| 8 | #include <inih/cpp/INIReader.h> | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "common/param_package.h" | ||
| 12 | #include "core/hle/service/acc/profile_manager.h" | ||
| 13 | #include "core/settings.h" | ||
| 14 | #include "input_common/main.h" | ||
| 15 | #include "yuzu_tester/config.h" | ||
| 16 | #include "yuzu_tester/default_ini.h" | ||
| 17 | |||
| 18 | Config::Config() { | ||
| 19 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | ||
| 20 | sdl2_config_loc = | ||
| 21 | FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-tester-config.ini"; | ||
| 22 | sdl2_config = std::make_unique<INIReader>(sdl2_config_loc); | ||
| 23 | |||
| 24 | Reload(); | ||
| 25 | } | ||
| 26 | |||
| 27 | Config::~Config() = default; | ||
| 28 | |||
| 29 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | ||
| 30 | const char* location = this->sdl2_config_loc.c_str(); | ||
| 31 | if (sdl2_config->ParseError() < 0) { | ||
| 32 | if (retry) { | ||
| 33 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); | ||
| 34 | FileUtil::CreateFullPath(location); | ||
| 35 | FileUtil::WriteStringToFile(true, default_contents, location); | ||
| 36 | sdl2_config = std::make_unique<INIReader>(location); // Reopen file | ||
| 37 | |||
| 38 | return LoadINI(default_contents, false); | ||
| 39 | } | ||
| 40 | LOG_ERROR(Config, "Failed."); | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | LOG_INFO(Config, "Successfully loaded {}", location); | ||
| 44 | return true; | ||
| 45 | } | ||
| 46 | |||
| 47 | void Config::ReadValues() { | ||
| 48 | // Controls | ||
| 49 | for (std::size_t p = 0; p < Settings::values.players.size(); ++p) { | ||
| 50 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 51 | Settings::values.players[p].buttons[i] = ""; | ||
| 52 | } | ||
| 53 | |||
| 54 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 55 | Settings::values.players[p].analogs[i] = ""; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | Settings::values.mouse_enabled = false; | ||
| 60 | for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { | ||
| 61 | Settings::values.mouse_buttons[i] = ""; | ||
| 62 | } | ||
| 63 | |||
| 64 | Settings::values.motion_device = ""; | ||
| 65 | |||
| 66 | Settings::values.keyboard_enabled = false; | ||
| 67 | |||
| 68 | Settings::values.debug_pad_enabled = false; | ||
| 69 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 70 | Settings::values.debug_pad_buttons[i] = ""; | ||
| 71 | } | ||
| 72 | |||
| 73 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 74 | Settings::values.debug_pad_analogs[i] = ""; | ||
| 75 | } | ||
| 76 | |||
| 77 | Settings::values.touchscreen.enabled = ""; | ||
| 78 | Settings::values.touchscreen.device = ""; | ||
| 79 | Settings::values.touchscreen.finger = 0; | ||
| 80 | Settings::values.touchscreen.rotation_angle = 0; | ||
| 81 | Settings::values.touchscreen.diameter_x = 15; | ||
| 82 | Settings::values.touchscreen.diameter_y = 15; | ||
| 83 | |||
| 84 | // Data Storage | ||
| 85 | Settings::values.use_virtual_sd = | ||
| 86 | sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); | ||
| 87 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir, | ||
| 88 | sdl2_config->Get("Data Storage", "nand_directory", | ||
| 89 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir))); | ||
| 90 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir, | ||
| 91 | sdl2_config->Get("Data Storage", "sdmc_directory", | ||
| 92 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); | ||
| 93 | |||
| 94 | // System | ||
| 95 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); | ||
| 96 | Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true); | ||
| 97 | const auto size = sdl2_config->GetInteger("System", "users_size", 0); | ||
| 98 | |||
| 99 | Settings::values.current_user = std::clamp<int>( | ||
| 100 | sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); | ||
| 101 | |||
| 102 | const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); | ||
| 103 | if (rng_seed_enabled) { | ||
| 104 | Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); | ||
| 105 | } else { | ||
| 106 | Settings::values.rng_seed = std::nullopt; | ||
| 107 | } | ||
| 108 | |||
| 109 | const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); | ||
| 110 | if (custom_rtc_enabled) { | ||
| 111 | Settings::values.custom_rtc = | ||
| 112 | std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); | ||
| 113 | } else { | ||
| 114 | Settings::values.custom_rtc = std::nullopt; | ||
| 115 | } | ||
| 116 | |||
| 117 | // Core | ||
| 118 | Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true); | ||
| 119 | Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); | ||
| 120 | |||
| 121 | // Renderer | ||
| 122 | Settings::values.resolution_factor = | ||
| 123 | static_cast<float>(sdl2_config->GetReal("Renderer", "resolution_factor", 1.0)); | ||
| 124 | Settings::values.use_frame_limit = false; | ||
| 125 | Settings::values.frame_limit = 100; | ||
| 126 | Settings::values.use_disk_shader_cache = | ||
| 127 | sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); | ||
| 128 | Settings::values.use_accurate_gpu_emulation = | ||
| 129 | sdl2_config->GetBoolean("Renderer", "use_accurate_gpu_emulation", false); | ||
| 130 | Settings::values.use_asynchronous_gpu_emulation = | ||
| 131 | sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false); | ||
| 132 | |||
| 133 | Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)); | ||
| 134 | Settings::values.bg_green = | ||
| 135 | static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)); | ||
| 136 | Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)); | ||
| 137 | |||
| 138 | // Audio | ||
| 139 | Settings::values.sink_id = "null"; | ||
| 140 | Settings::values.enable_audio_stretching = false; | ||
| 141 | Settings::values.audio_device_id = "auto"; | ||
| 142 | Settings::values.volume = 0; | ||
| 143 | |||
| 144 | Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1); | ||
| 145 | |||
| 146 | // Miscellaneous | ||
| 147 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); | ||
| 148 | Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); | ||
| 149 | |||
| 150 | // Debugging | ||
| 151 | Settings::values.use_gdbstub = false; | ||
| 152 | Settings::values.program_args = ""; | ||
| 153 | Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false); | ||
| 154 | Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); | ||
| 155 | |||
| 156 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); | ||
| 157 | std::stringstream ss(title_list); | ||
| 158 | std::string line; | ||
| 159 | while (std::getline(ss, line, '|')) { | ||
| 160 | const auto title_id = std::stoul(line, nullptr, 16); | ||
| 161 | const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, ""); | ||
| 162 | |||
| 163 | std::stringstream inner_ss(disabled_list); | ||
| 164 | std::string inner_line; | ||
| 165 | std::vector<std::string> out; | ||
| 166 | while (std::getline(inner_ss, inner_line, '|')) { | ||
| 167 | out.push_back(inner_line); | ||
| 168 | } | ||
| 169 | |||
| 170 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 171 | } | ||
| 172 | |||
| 173 | // Web Service | ||
| 174 | Settings::values.enable_telemetry = | ||
| 175 | sdl2_config->GetBoolean("WebService", "enable_telemetry", true); | ||
| 176 | Settings::values.web_api_url = | ||
| 177 | sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); | ||
| 178 | Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", ""); | ||
| 179 | Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); | ||
| 180 | } | ||
| 181 | |||
| 182 | void Config::Reload() { | ||
| 183 | LoadINI(DefaultINI::sdl2_config_file); | ||
| 184 | ReadValues(); | ||
| 185 | } | ||
diff --git a/src/yuzu_tester/config.h b/src/yuzu_tester/config.h new file mode 100644 index 000000000..3b68e5bc9 --- /dev/null +++ b/src/yuzu_tester/config.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 10 | class INIReader; | ||
| 11 | |||
| 12 | class Config { | ||
| 13 | std::unique_ptr<INIReader> sdl2_config; | ||
| 14 | std::string sdl2_config_loc; | ||
| 15 | |||
| 16 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | ||
| 17 | void ReadValues(); | ||
| 18 | |||
| 19 | public: | ||
| 20 | Config(); | ||
| 21 | ~Config(); | ||
| 22 | |||
| 23 | void Reload(); | ||
| 24 | }; | ||
diff --git a/src/yuzu_tester/default_ini.h b/src/yuzu_tester/default_ini.h new file mode 100644 index 000000000..46a9960cd --- /dev/null +++ b/src/yuzu_tester/default_ini.h | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace DefaultINI { | ||
| 8 | |||
| 9 | const char* sdl2_config_file = R"( | ||
| 10 | [Core] | ||
| 11 | # Whether to use the Just-In-Time (JIT) compiler for CPU emulation | ||
| 12 | # 0: Interpreter (slow), 1 (default): JIT (fast) | ||
| 13 | use_cpu_jit = | ||
| 14 | |||
| 15 | # Whether to use multi-core for CPU emulation | ||
| 16 | # 0 (default): Disabled, 1: Enabled | ||
| 17 | use_multi_core= | ||
| 18 | |||
| 19 | [Renderer] | ||
| 20 | # Whether to use software or hardware rendering. | ||
| 21 | # 0: Software, 1 (default): Hardware | ||
| 22 | use_hw_renderer = | ||
| 23 | |||
| 24 | # Whether to use the Just-In-Time (JIT) compiler for shader emulation | ||
| 25 | # 0: Interpreter (slow), 1 (default): JIT (fast) | ||
| 26 | use_shader_jit = | ||
| 27 | |||
| 28 | # Resolution scale factor | ||
| 29 | # 0: Auto (scales resolution to window size), 1: Native Switch screen resolution, Otherwise a scale | ||
| 30 | # factor for the Switch resolution | ||
| 31 | resolution_factor = | ||
| 32 | |||
| 33 | # Whether to enable V-Sync (caps the framerate at 60FPS) or not. | ||
| 34 | # 0 (default): Off, 1: On | ||
| 35 | use_vsync = | ||
| 36 | |||
| 37 | # Whether to use disk based shader cache | ||
| 38 | # 0 (default): Off, 1 : On | ||
| 39 | use_disk_shader_cache = | ||
| 40 | |||
| 41 | # Whether to use accurate GPU emulation | ||
| 42 | # 0 (default): Off (fast), 1 : On (slow) | ||
| 43 | use_accurate_gpu_emulation = | ||
| 44 | |||
| 45 | # Whether to use asynchronous GPU emulation | ||
| 46 | # 0 : Off (slow), 1 (default): On (fast) | ||
| 47 | use_asynchronous_gpu_emulation = | ||
| 48 | |||
| 49 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | ||
| 50 | # Must be in range of 0.0-1.0. Defaults to 1.0 for all. | ||
| 51 | bg_red = | ||
| 52 | bg_blue = | ||
| 53 | bg_green = | ||
| 54 | |||
| 55 | [Layout] | ||
| 56 | # Layout for the screen inside the render window. | ||
| 57 | # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen | ||
| 58 | layout_option = | ||
| 59 | |||
| 60 | # Toggle custom layout (using the settings below) on or off. | ||
| 61 | # 0 (default): Off, 1: On | ||
| 62 | custom_layout = | ||
| 63 | |||
| 64 | # Screen placement when using Custom layout option | ||
| 65 | # 0x, 0y is the top left corner of the render window. | ||
| 66 | custom_top_left = | ||
| 67 | custom_top_top = | ||
| 68 | custom_top_right = | ||
| 69 | custom_top_bottom = | ||
| 70 | custom_bottom_left = | ||
| 71 | custom_bottom_top = | ||
| 72 | custom_bottom_right = | ||
| 73 | custom_bottom_bottom = | ||
| 74 | |||
| 75 | # Swaps the prominent screen with the other screen. | ||
| 76 | # For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. | ||
| 77 | # 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent | ||
| 78 | swap_screen = | ||
| 79 | |||
| 80 | [Data Storage] | ||
| 81 | # Whether to create a virtual SD card. | ||
| 82 | # 1 (default): Yes, 0: No | ||
| 83 | use_virtual_sd = | ||
| 84 | |||
| 85 | [System] | ||
| 86 | # Whether the system is docked | ||
| 87 | # 1: Yes, 0 (default): No | ||
| 88 | use_docked_mode = | ||
| 89 | |||
| 90 | # Allow the use of NFC in games | ||
| 91 | # 1 (default): Yes, 0 : No | ||
| 92 | enable_nfc = | ||
| 93 | |||
| 94 | # Sets the seed for the RNG generator built into the switch | ||
| 95 | # rng_seed will be ignored and randomly generated if rng_seed_enabled is false | ||
| 96 | rng_seed_enabled = | ||
| 97 | rng_seed = | ||
| 98 | |||
| 99 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 100 | # This will auto-increment, with the time set being the time the game is started | ||
| 101 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 102 | custom_rtc_enabled = | ||
| 103 | custom_rtc = | ||
| 104 | |||
| 105 | # Sets the account username, max length is 32 characters | ||
| 106 | # yuzu (default) | ||
| 107 | username = yuzu | ||
| 108 | |||
| 109 | # Sets the systems language index | ||
| 110 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | ||
| 111 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | ||
| 112 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese | ||
| 113 | language_index = | ||
| 114 | |||
| 115 | # The system region that yuzu will use during emulation | ||
| 116 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | ||
| 117 | region_value = | ||
| 118 | |||
| 119 | [Miscellaneous] | ||
| 120 | # A filter which removes logs below a certain logging level. | ||
| 121 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | ||
| 122 | log_filter = *:Trace | ||
| 123 | |||
| 124 | [Debugging] | ||
| 125 | # Arguments to be passed to argv/argc in the emulated program. It is preferable to use the testing service datastring | ||
| 126 | program_args= | ||
| 127 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 128 | dump_exefs=false | ||
| 129 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | ||
| 130 | dump_nso=false | ||
| 131 | |||
| 132 | [WebService] | ||
| 133 | # Whether or not to enable telemetry | ||
| 134 | # 0: No, 1 (default): Yes | ||
| 135 | enable_telemetry = | ||
| 136 | # URL for Web API | ||
| 137 | web_api_url = https://api.yuzu-emu.org | ||
| 138 | # Username and token for yuzu Web Service | ||
| 139 | # See https://profile.yuzu-emu.org/ for more info | ||
| 140 | yuzu_username = | ||
| 141 | yuzu_token = | ||
| 142 | |||
| 143 | [AddOns] | ||
| 144 | # Used to disable add-ons | ||
| 145 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | ||
| 146 | title_ids = | ||
| 147 | # For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') | ||
| 148 | # e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey | ||
| 149 | )"; | ||
| 150 | } | ||
diff --git a/src/yuzu_tester/resource.h b/src/yuzu_tester/resource.h new file mode 100644 index 000000000..df8e459e4 --- /dev/null +++ b/src/yuzu_tester/resource.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | //{{NO_DEPENDENCIES}} | ||
| 2 | // Microsoft Visual C++ generated include file. | ||
| 3 | // Used by pcafe.rc | ||
| 4 | // | ||
| 5 | #define IDI_ICON3 103 | ||
| 6 | |||
| 7 | // Next default values for new objects | ||
| 8 | // | ||
| 9 | #ifdef APSTUDIO_INVOKED | ||
| 10 | #ifndef APSTUDIO_READONLY_SYMBOLS | ||
| 11 | #define _APS_NEXT_RESOURCE_VALUE 105 | ||
| 12 | #define _APS_NEXT_COMMAND_VALUE 40001 | ||
| 13 | #define _APS_NEXT_CONTROL_VALUE 1001 | ||
| 14 | #define _APS_NEXT_SYMED_VALUE 101 | ||
| 15 | #endif | ||
| 16 | #endif | ||
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp new file mode 100644 index 000000000..84d277fcf --- /dev/null +++ b/src/yuzu_tester/yuzu.cpp | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <iostream> | ||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | #include <thread> | ||
| 9 | |||
| 10 | #include <fmt/ostream.h> | ||
| 11 | |||
| 12 | #include "common/common_paths.h" | ||
| 13 | #include "common/detached_tasks.h" | ||
| 14 | #include "common/file_util.h" | ||
| 15 | #include "common/logging/backend.h" | ||
| 16 | #include "common/logging/filter.h" | ||
| 17 | #include "common/logging/log.h" | ||
| 18 | #include "common/microprofile.h" | ||
| 19 | #include "common/scm_rev.h" | ||
| 20 | #include "common/scope_exit.h" | ||
| 21 | #include "common/string_util.h" | ||
| 22 | #include "common/telemetry.h" | ||
| 23 | #include "core/core.h" | ||
| 24 | #include "core/crypto/key_manager.h" | ||
| 25 | #include "core/file_sys/vfs_real.h" | ||
| 26 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 27 | #include "core/loader/loader.h" | ||
| 28 | #include "core/settings.h" | ||
| 29 | #include "core/telemetry_session.h" | ||
| 30 | #include "video_core/renderer_base.h" | ||
| 31 | #include "yuzu_tester/config.h" | ||
| 32 | #include "yuzu_tester/emu_window/emu_window_sdl2_hide.h" | ||
| 33 | #include "yuzu_tester/service/yuzutest.h" | ||
| 34 | |||
| 35 | #include <getopt.h> | ||
| 36 | #ifndef _MSC_VER | ||
| 37 | #include <unistd.h> | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #ifdef _WIN32 | ||
| 41 | // windows.h needs to be included before shellapi.h | ||
| 42 | #include <windows.h> | ||
| 43 | |||
| 44 | #include <shellapi.h> | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #ifdef _WIN32 | ||
| 48 | extern "C" { | ||
| 49 | // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable | ||
| 50 | // graphics | ||
| 51 | __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | ||
| 52 | __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | ||
| 53 | } | ||
| 54 | #endif | ||
| 55 | |||
| 56 | static void PrintHelp(const char* argv0) { | ||
| 57 | std::cout << "Usage: " << argv0 | ||
| 58 | << " [options] <filename>\n" | ||
| 59 | "-h, --help Display this help and exit\n" | ||
| 60 | "-v, --version Output version information and exit\n" | ||
| 61 | "-d, --datastring Pass following string as data to test service command #2\n" | ||
| 62 | "-l, --log Log to console in addition to file (will log to file only " | ||
| 63 | "by default)\n"; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void PrintVersion() { | ||
| 67 | std::cout << "yuzu [Test Utility] " << Common::g_scm_branch << " " << Common::g_scm_desc | ||
| 68 | << std::endl; | ||
| 69 | } | ||
| 70 | |||
| 71 | static void InitializeLogging(bool console) { | ||
| 72 | Log::Filter log_filter(Log::Level::Debug); | ||
| 73 | log_filter.ParseFilterString(Settings::values.log_filter); | ||
| 74 | Log::SetGlobalFilter(log_filter); | ||
| 75 | |||
| 76 | if (console) | ||
| 77 | Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); | ||
| 78 | |||
| 79 | const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir); | ||
| 80 | FileUtil::CreateFullPath(log_dir); | ||
| 81 | Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); | ||
| 82 | #ifdef _WIN32 | ||
| 83 | Log::AddBackend(std::make_unique<Log::DebuggerBackend>()); | ||
| 84 | #endif | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Application entry point | ||
| 88 | int main(int argc, char** argv) { | ||
| 89 | Common::DetachedTasks detached_tasks; | ||
| 90 | Config config; | ||
| 91 | |||
| 92 | int option_index = 0; | ||
| 93 | |||
| 94 | char* endarg; | ||
| 95 | #ifdef _WIN32 | ||
| 96 | int argc_w; | ||
| 97 | auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); | ||
| 98 | |||
| 99 | if (argv_w == nullptr) { | ||
| 100 | std::cout << "Failed to get command line arguments" << std::endl; | ||
| 101 | return -1; | ||
| 102 | } | ||
| 103 | #endif | ||
| 104 | std::string filepath; | ||
| 105 | |||
| 106 | static struct option long_options[] = { | ||
| 107 | {"help", no_argument, 0, 'h'}, | ||
| 108 | {"version", no_argument, 0, 'v'}, | ||
| 109 | {"datastring", optional_argument, 0, 'd'}, | ||
| 110 | {"log", no_argument, 0, 'l'}, | ||
| 111 | {0, 0, 0, 0}, | ||
| 112 | }; | ||
| 113 | |||
| 114 | bool console_log = false; | ||
| 115 | std::string datastring; | ||
| 116 | |||
| 117 | while (optind < argc) { | ||
| 118 | int arg = getopt_long(argc, argv, "hvdl::", long_options, &option_index); | ||
| 119 | if (arg != -1) { | ||
| 120 | switch (static_cast<char>(arg)) { | ||
| 121 | case 'h': | ||
| 122 | PrintHelp(argv[0]); | ||
| 123 | return 0; | ||
| 124 | case 'v': | ||
| 125 | PrintVersion(); | ||
| 126 | return 0; | ||
| 127 | case 'd': | ||
| 128 | datastring = argv[optind]; | ||
| 129 | ++optind; | ||
| 130 | break; | ||
| 131 | case 'l': | ||
| 132 | console_log = true; | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | } else { | ||
| 136 | #ifdef _WIN32 | ||
| 137 | filepath = Common::UTF16ToUTF8(argv_w[optind]); | ||
| 138 | #else | ||
| 139 | filepath = argv[optind]; | ||
| 140 | #endif | ||
| 141 | optind++; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | InitializeLogging(console_log); | ||
| 146 | |||
| 147 | #ifdef _WIN32 | ||
| 148 | LocalFree(argv_w); | ||
| 149 | #endif | ||
| 150 | |||
| 151 | MicroProfileOnThreadCreate("EmuThread"); | ||
| 152 | SCOPE_EXIT({ MicroProfileShutdown(); }); | ||
| 153 | |||
| 154 | if (filepath.empty()) { | ||
| 155 | LOG_CRITICAL(Frontend, "Failed to load application: No application specified"); | ||
| 156 | std::cout << "Failed to load application: No application specified" << std::endl; | ||
| 157 | PrintHelp(argv[0]); | ||
| 158 | return -1; | ||
| 159 | } | ||
| 160 | |||
| 161 | Settings::values.use_gdbstub = false; | ||
| 162 | Settings::Apply(); | ||
| 163 | |||
| 164 | std::unique_ptr<EmuWindow_SDL2_Hide> emu_window{std::make_unique<EmuWindow_SDL2_Hide>()}; | ||
| 165 | |||
| 166 | if (!Settings::values.use_multi_core) { | ||
| 167 | // Single core mode must acquire OpenGL context for entire emulation session | ||
| 168 | emu_window->MakeCurrent(); | ||
| 169 | } | ||
| 170 | |||
| 171 | bool finished = false; | ||
| 172 | int return_value = 0; | ||
| 173 | const auto callback = [&finished, &return_value](u32 code, std::string string) { | ||
| 174 | finished = true; | ||
| 175 | return_value = code & 0xFF; | ||
| 176 | const auto text = fmt::format("Test Finished [Result Code: {:08X}]\n{}", code, string); | ||
| 177 | LOG_INFO(Frontend, text.c_str()); | ||
| 178 | std::cout << text << std::endl; | ||
| 179 | }; | ||
| 180 | |||
| 181 | Core::System& system{Core::System::GetInstance()}; | ||
| 182 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | ||
| 183 | Service::FileSystem::CreateFactories(*system.GetFilesystem()); | ||
| 184 | |||
| 185 | SCOPE_EXIT({ system.Shutdown(); }); | ||
| 186 | |||
| 187 | const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)}; | ||
| 188 | |||
| 189 | switch (load_result) { | ||
| 190 | case Core::System::ResultStatus::ErrorGetLoader: | ||
| 191 | LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); | ||
| 192 | return -1; | ||
| 193 | case Core::System::ResultStatus::ErrorLoader: | ||
| 194 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||
| 195 | return -1; | ||
| 196 | case Core::System::ResultStatus::ErrorNotInitialized: | ||
| 197 | LOG_CRITICAL(Frontend, "CPUCore not initialized"); | ||
| 198 | return -1; | ||
| 199 | case Core::System::ResultStatus::ErrorSystemMode: | ||
| 200 | LOG_CRITICAL(Frontend, "Failed to determine system mode!"); | ||
| 201 | return -1; | ||
| 202 | case Core::System::ResultStatus::ErrorVideoCore: | ||
| 203 | LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); | ||
| 204 | return -1; | ||
| 205 | case Core::System::ResultStatus::Success: | ||
| 206 | break; // Expected case | ||
| 207 | default: | ||
| 208 | if (static_cast<u32>(load_result) > | ||
| 209 | static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) { | ||
| 210 | const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader); | ||
| 211 | const u16 error_id = static_cast<u16>(load_result) - loader_id; | ||
| 212 | LOG_CRITICAL(Frontend, | ||
| 213 | "While attempting to load the ROM requested, an error occured. Please " | ||
| 214 | "refer to the yuzu wiki for more information or the yuzu discord for " | ||
| 215 | "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", | ||
| 216 | loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | Service::Yuzu::InstallInterfaces(system.ServiceManager(), datastring, callback); | ||
| 221 | |||
| 222 | system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDLHideTester"); | ||
| 223 | |||
| 224 | system.Renderer().Rasterizer().LoadDiskResources(); | ||
| 225 | |||
| 226 | while (!finished) { | ||
| 227 | system.RunLoop(); | ||
| 228 | } | ||
| 229 | |||
| 230 | detached_tasks.WaitForAllTasks(); | ||
| 231 | return return_value; | ||
| 232 | } | ||
diff --git a/src/yuzu_tester/yuzu.rc b/src/yuzu_tester/yuzu.rc new file mode 100644 index 000000000..7de8ef3d9 --- /dev/null +++ b/src/yuzu_tester/yuzu.rc | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #include "winresrc.h" | ||
| 2 | ///////////////////////////////////////////////////////////////////////////// | ||
| 3 | // | ||
| 4 | // Icon | ||
| 5 | // | ||
| 6 | |||
| 7 | // Icon with lowest ID value placed first to ensure application icon | ||
| 8 | // remains consistent on all systems. | ||
| 9 | YUZU_ICON ICON "../../dist/yuzu.ico" | ||
| 10 | |||
| 11 | |||
| 12 | ///////////////////////////////////////////////////////////////////////////// | ||
| 13 | // | ||
| 14 | // RT_MANIFEST | ||
| 15 | // | ||
| 16 | |||
| 17 | 1 RT_MANIFEST "../../dist/yuzu.manifest" | ||