summaryrefslogtreecommitdiff
path: root/src/yuzu_cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu_cmd')
-rw-r--r--src/yuzu_cmd/CMakeLists.txt5
-rw-r--r--src/yuzu_cmd/config.cpp35
-rw-r--r--src/yuzu_cmd/config.h16
-rw-r--r--src/yuzu_cmd/default_ini.h46
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp30
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp10
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h7
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp11
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h7
-rw-r--r--src/yuzu_cmd/yuzu.cpp203
-rw-r--r--src/yuzu_cmd/yuzu.rc3
12 files changed, 292 insertions, 89 deletions
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index 74fc24972..7d8ca3d8a 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -1,3 +1,6 @@
+# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
+# SPDX-License-Identifier: GPL-2.0-or-later
+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
# Credits to Samantas5855 and others for this function.
@@ -45,7 +48,7 @@ if (YUZU_USE_EXTERNAL_SDL2)
endif()
if(UNIX AND NOT APPLE)
- install(TARGETS yuzu-cmd RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+ install(TARGETS yuzu-cmd)
endif()
if (MSVC)
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index ff616da70..66dd0dc15 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -1,8 +1,8 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <memory>
+#include <optional>
#include <sstream>
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
@@ -20,7 +20,6 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
-#include "common/param_package.h"
#include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h"
#include "input_common/main.h"
@@ -29,11 +28,12 @@
namespace FS = Common::FS;
-Config::Config() {
- // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
- sdl2_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
- sdl2_config = std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc));
+const std::filesystem::path default_config_path =
+ FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
+Config::Config(std::optional<std::filesystem::path> config_path)
+ : sdl2_config_loc{config_path.value_or(default_config_path)},
+ sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} {
Reload();
}
@@ -89,17 +89,17 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
}};
template <>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
+void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
}
template <>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<bool>& setting) {
+void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
}
-template <typename Type>
-void Config::ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting) {
+template <typename Type, bool ranged>
+void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
static_cast<long>(setting.GetDefault())));
}
@@ -266,6 +266,7 @@ void Config::ReadValues() {
// Core
ReadSetting("Core", Settings::values.use_multi_core);
+ ReadSetting("Core", Settings::values.use_extended_memory_layout);
// Cpu
ReadSetting("Cpu", Settings::values.cpu_accuracy);
@@ -279,11 +280,14 @@ void Config::ReadValues() {
ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
+ ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
+ ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
+ ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
// Renderer
ReadSetting("Renderer", Settings::values.renderer_backend);
@@ -305,13 +309,12 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.gpu_accuracy);
ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
ReadSetting("Renderer", Settings::values.use_vsync);
- ReadSetting("Renderer", Settings::values.fps_cap);
- ReadSetting("Renderer", Settings::values.disable_fps_limit);
ReadSetting("Renderer", Settings::values.shader_backend);
ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
ReadSetting("Renderer", Settings::values.nvdec_emulation);
ReadSetting("Renderer", Settings::values.accelerate_astc);
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
+ ReadSetting("Renderer", Settings::values.use_pessimistic_flushes);
ReadSetting("Renderer", Settings::values.bg_red);
ReadSetting("Renderer", Settings::values.bg_green);
@@ -319,7 +322,7 @@ void Config::ReadValues() {
// Audio
ReadSetting("Audio", Settings::values.sink_id);
- ReadSetting("Audio", Settings::values.audio_device_id);
+ ReadSetting("Audio", Settings::values.audio_output_device_id);
ReadSetting("Audio", Settings::values.volume);
// Miscellaneous
@@ -339,6 +342,8 @@ void Config::ReadValues() {
ReadSetting("Debugging", Settings::values.use_debug_asserts);
ReadSetting("Debugging", Settings::values.use_auto_stub);
ReadSetting("Debugging", Settings::values.disable_macro_jit);
+ ReadSetting("Debugging", Settings::values.use_gdbstub);
+ ReadSetting("Debugging", Settings::values.gdbstub_port);
const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
std::stringstream ss(title_list);
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index 1ee932be2..021438b17 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -1,11 +1,11 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <filesystem>
#include <memory>
+#include <optional>
#include <string>
#include "common/settings.h"
@@ -13,25 +13,25 @@
class INIReader;
class Config {
- std::unique_ptr<INIReader> sdl2_config;
std::filesystem::path sdl2_config_loc;
+ std::unique_ptr<INIReader> sdl2_config;
bool LoadINI(const std::string& default_contents = "", bool retry = true);
void ReadValues();
public:
- Config();
+ explicit Config(std::optional<std::filesystem::path> config_path);
~Config();
void Reload();
private:
/**
- * Applies a value read from the sdl2_config to a BasicSetting.
+ * Applies a value read from the sdl2_config to a Setting.
*
* @param group The name of the INI group
* @param setting The yuzu setting to modify
*/
- template <typename Type>
- void ReadSetting(const std::string& group, Settings::BasicSetting<Type>& setting);
+ template <typename Type, bool ranged>
+ void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
};
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 6d613bf7a..d214771b0 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -1,6 +1,5 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -124,7 +123,11 @@ keyboard_enabled =
[Core]
# Whether to use multi-core for CPU emulation
# 0: Disabled, 1 (default): Enabled
-use_multi_core=
+use_multi_core =
+
+# Enable extended guest system memory layout (6GB DRAM)
+# 0 (default): Disabled, 1: Enabled
+use_extended_memory_layout =
[Cpu]
# Adjusts various optimizations.
@@ -174,6 +177,14 @@ cpuopt_reduce_misalign_checks =
# 0: Disabled, 1 (default): Enabled
cpuopt_fastmem =
+# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_fastmem_exclusives =
+
+# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_recompile_exclusives =
+
# Enable unfuse FMA (improve performance on CPUs without FMA)
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
# 0: Disabled, 1 (default): Enabled
@@ -199,9 +210,14 @@ cpuopt_unsafe_inaccurate_nan =
# 0: Disabled, 1 (default): Enabled
cpuopt_unsafe_fastmem_check =
+# Enable faster exclusive instructions
+# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
+# 0: Disabled, 1 (default): Enabled
+cpuopt_unsafe_ignore_global_monitor =
+
[Renderer]
# Which backend API to use.
-# 0 (default): OpenGL, 1: Vulkan
+# 0: OpenGL, 1 (default): Vulkan
backend =
# Enable graphics API debugging mode.
@@ -303,6 +319,10 @@ use_asynchronous_gpu_emulation =
# 0: Off, 1 (default): On
use_fast_gpu_time =
+# Force unmodified buffers to be flushed, which can cost performance.
+# 0: Off (default), 1: On
+use_pessimistic_flushes =
+
# Whether to use garbage collection or not for GPU caches.
# 0 (default): Off, 1: On
use_caches_gc =
@@ -313,10 +333,6 @@ bg_red =
bg_blue =
bg_green =
-# Caps the unlocked framerate to a multiple of the title's target FPS.
-# 1 - 1000: Target FPS multiple cap. 1000 (default)
-fps_cap =
-
[Audio]
# Which audio output engine to use.
# auto (default): Auto-select
@@ -325,12 +341,6 @@ fps_cap =
# null: No audio output
output_engine =
-# Whether or not to enable the audio-stretching post-processing effect.
-# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
-# at the cost of increasing audio latency.
-# 0: No, 1 (default): Yes
-enable_audio_stretching =
-
# Which audio device to use.
# auto (default): Auto-select
output_device =
@@ -423,9 +433,11 @@ use_debug_asserts =
use_auto_stub =
# Enables/Disables the macro JIT compiler
disable_macro_jit=false
-# Presents guest frames as they become available. Experimental.
+# Determines whether to enable the GDB stub and wait for the debugger to attach before running.
# false: Disabled (default), true: Enabled
-disable_fps_limit=false
+use_gdbstub=false
+# The port to use for the GDB server, if it is enabled.
+gdbstub_port=6543
[WebService]
# Whether or not to enable telemetry
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 57f807826..4ac72c2f6 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -1,6 +1,5 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <SDL.h>
@@ -93,7 +92,7 @@ void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
}
void EmuWindow_SDL2::OnFingerUp() {
- input_subsystem->GetTouchScreen()->TouchReleased(0);
+ input_subsystem->GetTouchScreen()->ReleaseAllTouch();
}
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
@@ -123,14 +122,15 @@ void EmuWindow_SDL2::ShowCursor(bool show_cursor) {
}
void EmuWindow_SDL2::Fullscreen() {
+ SDL_DisplayMode display_mode;
switch (Settings::values.fullscreen_mode.GetValue()) {
case Settings::FullscreenMode::Exclusive:
- // Set window size to render size before entering fullscreen -- SDL does not resize to
- // display dimensions in this mode.
- // TODO: Multiply the window size by resolution_factor (for both docked modes)
- if (Settings::values.use_docked_mode) {
- SDL_SetWindowSize(render_window, Layout::ScreenDocked::Width,
- Layout::ScreenDocked::Height);
+ // Set window size to render size before entering fullscreen -- SDL2 does not resize window
+ // to display dimensions automatically in this mode.
+ if (SDL_GetDesktopDisplayMode(0, &display_mode) == 0) {
+ SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
+ } else {
+ LOG_ERROR(Frontend, "SDL_GetDesktopDisplayMode failed: {}", SDL_GetError());
}
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
@@ -161,7 +161,15 @@ void EmuWindow_SDL2::WaitEvent() {
SDL_Event event;
if (!SDL_WaitEvent(&event)) {
- LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", SDL_GetError());
+ const char* error = SDL_GetError();
+ if (!error || strcmp(error, "") == 0) {
+ // https://github.com/libsdl-org/SDL/issues/5780
+ // Sometimes SDL will return without actually having hit an error condition;
+ // just ignore it in this case.
+ return;
+ }
+
+ LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error);
exit(1);
}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 0af002693..90bb0b415 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -1,10 +1,8 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
-#include <memory>
#include <utility>
#include "core/frontend/emu_window.h"
@@ -21,7 +19,7 @@ enum class MouseButton;
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public:
- explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem, Core::System& system_);
+ explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_);
~EmuWindow_SDL2();
/// Whether the window is still open, and a close request hasn't yet been sent
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 70db865ec..9b660c13c 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -1,6 +1,5 @@
-// Copyright 2019 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <cstdlib>
@@ -11,7 +10,6 @@
#include <fmt/format.h>
#include <glad/glad.h>
-#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "common/settings.h"
@@ -75,9 +73,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
return unsupported_ext.empty();
}
-EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem,
+EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_,
Core::System& system_, bool fullscreen)
- : EmuWindow_SDL2{input_subsystem, system_} {
+ : EmuWindow_SDL2{input_subsystem_, system_} {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
index d7f2c83d8..39346e704 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
@@ -1,6 +1,5 @@
-// Copyright 2019 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -18,7 +17,7 @@ class InputSubsystem;
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
public:
- explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, Core::System& system_,
+ explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_,
bool fullscreen);
~EmuWindow_SDL2_GL();
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index de40b76bf..65455c86e 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -1,6 +1,5 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib>
#include <memory>
@@ -8,10 +7,8 @@
#include <fmt/format.h>
-#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
-#include "common/settings.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
@@ -24,9 +21,9 @@
#include <SDL.h>
#include <SDL_syswm.h>
-EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem,
+EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_,
Core::System& system_, bool fullscreen)
- : EmuWindow_SDL2{input_subsystem, system_} {
+ : EmuWindow_SDL2{input_subsystem_, system_} {
const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc);
render_window =
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
index 3ea521b2a..e39ad754d 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
@@ -1,6 +1,5 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -19,7 +18,7 @@ class InputSubsystem;
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
public:
- explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, Core::System& system,
+ explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system,
bool fullscreen);
~EmuWindow_SDL2_VK() override;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index b44ea0cc4..3a0f33cba 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -1,21 +1,17 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <iostream>
#include <memory>
+#include <regex>
#include <string>
#include <thread>
#include <fmt/ostream.h>
#include "common/detached_tasks.h"
-#include "common/fs/fs.h"
-#include "common/fs/fs_paths.h"
-#include "common/fs/path_util.h"
#include "common/logging/backend.h"
-#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/nvidia_flags.h"
@@ -25,6 +21,7 @@
#include "common/string_util.h"
#include "common/telemetry.h"
#include "core/core.h"
+#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
@@ -32,6 +29,7 @@
#include "core/loader/loader.h"
#include "core/telemetry_session.h"
#include "input_common/main.h"
+#include "network/network.h"
#include "video_core/renderer_base.h"
#include "yuzu_cmd/config.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
@@ -63,22 +61,122 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
static void PrintHelp(const char* argv0) {
std::cout << "Usage: " << argv0
<< " [options] <filename>\n"
+ "-m, --multiplayer=nick:password@address:port"
+ " Nickname, password, address and port for multiplayer\n"
"-f, --fullscreen Start in fullscreen mode\n"
"-h, --help Display this help and exit\n"
"-v, --version Output version information and exit\n"
- "-p, --program Pass following string as arguments to executable\n";
+ "-p, --program Pass following string as arguments to executable\n"
+ "-c, --config Load the specified configuration file\n";
}
static void PrintVersion() {
std::cout << "yuzu " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl;
}
+static void OnStateChanged(const Network::RoomMember::State& state) {
+ switch (state) {
+ case Network::RoomMember::State::Idle:
+ LOG_DEBUG(Network, "Network is idle");
+ break;
+ case Network::RoomMember::State::Joining:
+ LOG_DEBUG(Network, "Connection sequence to room started");
+ break;
+ case Network::RoomMember::State::Joined:
+ LOG_DEBUG(Network, "Successfully joined to the room");
+ break;
+ case Network::RoomMember::State::Moderator:
+ LOG_DEBUG(Network, "Successfully joined the room as a moderator");
+ break;
+ default:
+ break;
+ }
+}
+
+static void OnNetworkError(const Network::RoomMember::Error& error) {
+ switch (error) {
+ case Network::RoomMember::Error::LostConnection:
+ LOG_DEBUG(Network, "Lost connection to the room");
+ break;
+ case Network::RoomMember::Error::CouldNotConnect:
+ LOG_ERROR(Network, "Error: Could not connect");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::NameCollision:
+ LOG_ERROR(
+ Network,
+ "You tried to use the same nickname as another user that is connected to the Room");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::IpCollision:
+ LOG_ERROR(Network, "You tried to use the same fake IP-Address as another user that is "
+ "connected to the Room");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::WrongPassword:
+ LOG_ERROR(Network, "Room replied with: Wrong password");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::WrongVersion:
+ LOG_ERROR(Network,
+ "You are using a different version than the room you are trying to connect to");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::RoomIsFull:
+ LOG_ERROR(Network, "The room is full");
+ exit(1);
+ break;
+ case Network::RoomMember::Error::HostKicked:
+ LOG_ERROR(Network, "You have been kicked by the host");
+ break;
+ case Network::RoomMember::Error::HostBanned:
+ LOG_ERROR(Network, "You have been banned by the host");
+ break;
+ case Network::RoomMember::Error::UnknownError:
+ LOG_ERROR(Network, "UnknownError");
+ break;
+ case Network::RoomMember::Error::PermissionDenied:
+ LOG_ERROR(Network, "PermissionDenied");
+ break;
+ case Network::RoomMember::Error::NoSuchUser:
+ LOG_ERROR(Network, "NoSuchUser");
+ break;
+ }
+}
+
+static void OnMessageReceived(const Network::ChatEntry& msg) {
+ std::cout << std::endl << msg.nickname << ": " << msg.message << std::endl << std::endl;
+}
+
+static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) {
+ std::string message;
+ switch (msg.type) {
+ case Network::IdMemberJoin:
+ message = fmt::format("{} has joined", msg.nickname);
+ break;
+ case Network::IdMemberLeave:
+ message = fmt::format("{} has left", msg.nickname);
+ break;
+ case Network::IdMemberKicked:
+ message = fmt::format("{} has been kicked", msg.nickname);
+ break;
+ case Network::IdMemberBanned:
+ message = fmt::format("{} has been banned", msg.nickname);
+ break;
+ case Network::IdAddressUnbanned:
+ message = fmt::format("{} has been unbanned", msg.nickname);
+ break;
+ }
+ if (!message.empty())
+ std::cout << std::endl << "* " << message << std::endl << std::endl;
+}
+
/// Application entry point
int main(int argc, char** argv) {
Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true);
+ Common::Log::Start();
Common::DetachedTasks detached_tasks;
- Config config;
int option_index = 0;
#ifdef _WIN32
@@ -91,21 +189,64 @@ int main(int argc, char** argv) {
}
#endif
std::string filepath;
+ std::optional<std::string> config_path;
+ std::string program_args;
+ bool use_multiplayer = false;
bool fullscreen = false;
+ std::string nickname{};
+ std::string password{};
+ std::string address{};
+ u16 port = Network::DefaultRoomPort;
static struct option long_options[] = {
+ // clang-format off
+ {"multiplayer", required_argument, 0, 'm'},
{"fullscreen", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{"program", optional_argument, 0, 'p'},
+ {"config", required_argument, 0, 'c'},
{0, 0, 0, 0},
+ // clang-format on
};
while (optind < argc) {
- int arg = getopt_long(argc, argv, "g:fhvp::", long_options, &option_index);
+ int arg = getopt_long(argc, argv, "g:fhvp::c:", long_options, &option_index);
if (arg != -1) {
switch (static_cast<char>(arg)) {
+ case 'm': {
+ use_multiplayer = true;
+ const std::string str_arg(optarg);
+ // regex to check if the format is nickname:password@ip:port
+ // with optional :password
+ const std::regex re("^([^:]+)(?::(.+))?@([^:]+)(?::([0-9]+))?$");
+ if (!std::regex_match(str_arg, re)) {
+ std::cout << "Wrong format for option --multiplayer\n";
+ PrintHelp(argv[0]);
+ return 0;
+ }
+
+ std::smatch match;
+ std::regex_search(str_arg, match, re);
+ ASSERT(match.size() == 5);
+ nickname = match[1];
+ password = match[2];
+ address = match[3];
+ if (!match[4].str().empty())
+ port = std::stoi(match[4]);
+ std::regex nickname_re("^[a-zA-Z0-9._\\- ]+$");
+ if (!std::regex_match(nickname, nickname_re)) {
+ std::cout
+ << "Nickname is not valid. Must be 4 to 20 alphanumeric characters.\n";
+ return 0;
+ }
+ if (address.empty()) {
+ std::cout << "Address to room must not be empty.\n";
+ return 0;
+ }
+ break;
+ }
case 'f':
fullscreen = true;
LOG_INFO(Frontend, "Starting in fullscreen mode...");
@@ -117,9 +258,12 @@ int main(int argc, char** argv) {
PrintVersion();
return 0;
case 'p':
- Settings::values.program_args = argv[optind];
+ program_args = argv[optind];
++optind;
break;
+ case 'c':
+ config_path = optarg;
+ break;
}
} else {
#ifdef _WIN32
@@ -131,6 +275,18 @@ int main(int argc, char** argv) {
}
}
+ Config config{config_path};
+
+ // apply the log_filter setting
+ // the logger was initialized before and doesn't pick up the filter on its own
+ Common::Log::Filter filter;
+ filter.ParseFilterString(Settings::values.log_filter.GetValue());
+ Common::Log::SetGlobalFilter(filter);
+
+ if (!program_args.empty()) {
+ Settings::values.program_args = program_args;
+ }
+
#ifdef _WIN32
LocalFree(argv_w);
#endif
@@ -197,8 +353,24 @@ int main(int argc, char** argv) {
system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");
+ if (use_multiplayer) {
+ if (auto member = system.GetRoomNetwork().GetRoomMember().lock()) {
+ member->BindOnChatMessageRecieved(OnMessageReceived);
+ member->BindOnStatusMessageReceived(OnStatusMessageReceived);
+ member->BindOnStateChanged(OnStateChanged);
+ member->BindOnError(OnNetworkError);
+ LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port,
+ nickname);
+ member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredIP, password);
+ } else {
+ LOG_ERROR(Network, "Could not access RoomMember");
+ return 0;
+ }
+ }
+
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
system.GPU().Start();
+ system.GetCpuManager().OnGpuReady();
if (Settings::values.use_disk_shader_cache.GetValue()) {
system.Renderer().ReadRasterizer()->LoadDiskResources(
@@ -206,10 +378,19 @@ int main(int argc, char** argv) {
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
}
+ system.RegisterExitCallback([&] {
+ // Just exit right away.
+ exit(0);
+ });
+
void(system.Run());
+ if (system.DebuggerEnabled()) {
+ system.InitializeDebugger();
+ }
while (emu_window->IsOpen()) {
emu_window->WaitEvent();
}
+ system.DetachDebugger();
void(system.Pause());
system.Shutdown();
diff --git a/src/yuzu_cmd/yuzu.rc b/src/yuzu_cmd/yuzu.rc
index 0cde75e2f..e230cf680 100644
--- a/src/yuzu_cmd/yuzu.rc
+++ b/src/yuzu_cmd/yuzu.rc
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
#include "winresrc.h"
/////////////////////////////////////////////////////////////////////////////
//