From 07858a015ead4d0717a851847ddd5407a3073c3d Mon Sep 17 00:00:00 2001 From: OpenSauce04 Date: Tue, 3 Sep 2024 19:34:11 +0100 Subject: [PATCH] Dropped `lime3ds-cli` executable and SDL2 frontend --- .ci/macos-universal.sh | 4 +- .gitmodules | 3 - CMakeLists.txt | 18 - dist/lime3ds-cli.desktop | 15 - externals/CMakeLists.txt | 8 - externals/sdl2/CMakeLists.txt | 25 - externals/sdl2/SDL | 1 - src/CMakeLists.txt | 4 - .../app/src/main/jni/input_manager.cpp | 1 - src/audio_core/CMakeLists.txt | 6 - src/audio_core/sdl2_sink.cpp | 108 -- src/audio_core/sdl2_sink.h | 29 - src/audio_core/sink_details.cpp | 10 - src/input_common/CMakeLists.txt | 11 - src/input_common/main.cpp | 17 - src/input_common/sdl/sdl.cpp | 19 - src/input_common/sdl/sdl.h | 44 - src/input_common/sdl/sdl_impl.cpp | 1092 ----------------- src/input_common/sdl/sdl_impl.h | 74 -- src/lime/CMakeLists.txt | 61 - src/lime/config.cpp | 383 ------ src/lime/config.h | 35 - src/lime/default_ini.h | 398 ------ src/lime/emu_window/emu_window_sdl2.cpp | 252 ---- src/lime/emu_window/emu_window_sdl2.h | 91 -- src/lime/emu_window/emu_window_sdl2_gl.cpp | 167 --- src/lime/emu_window/emu_window_sdl2_gl.h | 39 - src/lime/emu_window/emu_window_sdl2_sw.cpp | 108 -- src/lime/emu_window/emu_window_sdl2_sw.h | 43 - src/lime/emu_window/emu_window_sdl2_vk.cpp | 90 -- src/lime/emu_window/emu_window_sdl2_vk.h | 24 - src/lime/lime.cpp | 536 -------- src/lime/lime.rc | 17 - src/lime/precompiled_headers.h | 7 - src/lime/resource.h | 16 - src/lime_qt/CMakeLists.txt | 5 - src/lime_qt/main.cpp | 53 - 37 files changed, 2 insertions(+), 3812 deletions(-) delete mode 100644 dist/lime3ds-cli.desktop delete mode 100644 externals/sdl2/CMakeLists.txt delete mode 160000 externals/sdl2/SDL delete mode 100644 src/audio_core/sdl2_sink.cpp delete mode 100644 src/audio_core/sdl2_sink.h delete mode 100644 src/input_common/sdl/sdl.cpp delete mode 100644 src/input_common/sdl/sdl.h delete mode 100644 src/input_common/sdl/sdl_impl.cpp delete mode 100644 src/input_common/sdl/sdl_impl.h delete mode 100644 src/lime/CMakeLists.txt delete mode 100644 src/lime/config.cpp delete mode 100644 src/lime/config.h delete mode 100644 src/lime/default_ini.h delete mode 100644 src/lime/emu_window/emu_window_sdl2.cpp delete mode 100644 src/lime/emu_window/emu_window_sdl2.h delete mode 100644 src/lime/emu_window/emu_window_sdl2_gl.cpp delete mode 100644 src/lime/emu_window/emu_window_sdl2_gl.h delete mode 100644 src/lime/emu_window/emu_window_sdl2_sw.cpp delete mode 100644 src/lime/emu_window/emu_window_sdl2_sw.h delete mode 100644 src/lime/emu_window/emu_window_sdl2_vk.cpp delete mode 100644 src/lime/emu_window/emu_window_sdl2_vk.h delete mode 100644 src/lime/lime.cpp delete mode 100644 src/lime/lime.rc delete mode 100644 src/lime/precompiled_headers.h delete mode 100644 src/lime/resource.h diff --git a/.ci/macos-universal.sh b/.ci/macos-universal.sh index 65ed3435e..df831ea30 100755 --- a/.ci/macos-universal.sh +++ b/.ci/macos-universal.sh @@ -11,7 +11,7 @@ BASE_ARTIFACT_ARCH="${BASE_ARTIFACT##*-}" mv $BASE_ARTIFACT $BUNDLE_DIR # Executable binary paths that need to be combined. -BIN_PATHS=(lime3ds-cli lime3ds-room lime3ds-gui.app/Contents/MacOS/lime3ds-gui) +BIN_PATHS=(lime3ds-room lime3ds-gui.app/Contents/MacOS/lime3ds-gui) # Dylib paths that need to be combined. IFS=$'\n' @@ -37,7 +37,7 @@ for OTHER_ARTIFACT in "${ARTIFACTS_LIST[@]:1}"; do done # Re-sign executables and bundles after combining. -APP_PATHS=(lime3ds-cli lime3ds-room lime3ds-gui.app) +APP_PATHS=(lime3ds-room lime3ds-gui.app) for APP_PATH in "${APP_PATHS[@]}"; do codesign --deep -fs - $BUNDLE_DIR/$APP_PATH done diff --git a/.gitmodules b/.gitmodules index 507ae7a99..9b7dd46b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,9 +52,6 @@ [submodule "libyuv"] path = externals/libyuv url = https://github.com/lemenkov/libyuv.git -[submodule "sdl2"] - path = externals/sdl2/SDL - url = https://github.com/libsdl-org/SDL [submodule "cryptopp-cmake"] path = externals/cryptopp-cmake url = https://github.com/abdes/cryptopp-cmake.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3203f1304..ccd147793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,10 +56,6 @@ else() set(DEFAULT_ENABLE_LTO OFF) endif() -option(ENABLE_SDL2 "Enable using SDL2" ON) -CMAKE_DEPENDENT_OPTION(ENABLE_SDL2_FRONTEND "Enable the SDL2 frontend" ON "ENABLE_SDL2;NOT ANDROID" OFF) -option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OFF) - # Set bundled qt as dependent options. option(ENABLE_QT "Enable the Qt frontend" ON) option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) @@ -397,15 +393,6 @@ if (NOT USE_SYSTEM_BOOST) add_library(Boost::iostreams ALIAS boost_iostreams) endif() -# SDL2 -if (ENABLE_SDL2 AND USE_SYSTEM_SDL2) - find_package(SDL2 REQUIRED) - add_library(SDL2 INTERFACE) - target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") - target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") - add_library(SDL2::SDL2 ALIAS SDL2) -endif() - if (ENABLE_LIBUSB AND USE_SYSTEM_LIBUSB) include(FindPkgConfig) find_package(LibUSB) @@ -426,17 +413,12 @@ add_subdirectory(dist/installer) # Set lime-qt project or lime project as default StartUp Project in Visual Studio depending on whether QT is enabled or not if(ENABLE_QT) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT lime-qt) -else() - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT lime) endif() # Create target for outputting distributable bundles. # Not supported for mobile platforms as distributables are built differently. if (NOT ANDROID) include(BundleTarget) - if (ENABLE_SDL2_FRONTEND) - bundle_target(lime) - endif() if (ENABLE_QT) bundle_target(lime-qt) endif() diff --git a/dist/lime3ds-cli.desktop b/dist/lime3ds-cli.desktop deleted file mode 100644 index dd8b5b1d2..000000000 --- a/dist/lime3ds-cli.desktop +++ /dev/null @@ -1,15 +0,0 @@ -[Desktop Entry] -Version=1.0 -Type=Application -Name=Lime3DS -GenericName=3DS Emulator -GenericName[fr]=Émulateur 3DS -Comment=Nintendo 3DS video game console emulator -Comment[fr]=Émulateur de console de jeu Nintendo 3DS -Icon=lime -TryExec=lime3ds-cli -Exec=lime3ds-cli %f -Categories=Game;Emulator; -MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi; -Keywords=3DS;Nintendo; -PrefersNonDefaultGPU=true diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index eb7279724..80201b960 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -183,14 +183,6 @@ endif() # Teakra add_subdirectory(teakra EXCLUDE_FROM_ALL) -# SDL2 -if (ENABLE_SDL2 AND NOT USE_SYSTEM_SDL2) - if (MSVC) - set (SDL_LIBC ON) - endif() - add_subdirectory(sdl2) -endif() - # libusb if (ENABLE_LIBUSB AND NOT USE_SYSTEM_LIBUSB) add_subdirectory(libusb) diff --git a/externals/sdl2/CMakeLists.txt b/externals/sdl2/CMakeLists.txt deleted file mode 100644 index f6e332623..000000000 --- a/externals/sdl2/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Configure static library build -set(SDL_SHARED OFF CACHE BOOL "") -set(SDL_STATIC ON CACHE BOOL "") - -# Subsystems -set(SDL_ATOMIC ON CACHE BOOL "") -set(SDL_AUDIO ON CACHE BOOL "") -set(SDL_VIDEO ON CACHE BOOL "") -set(SDL_RENDER OFF CACHE BOOL "") -set(SDL_EVENTS ON CACHE BOOL "") -set(SDL_JOYSTICK ON CACHE BOOL "") -set(SDL_HAPTIC OFF CACHE BOOL "") -set(SDL_HIDAPI ON CACHE BOOL "") -set(SDL_POWER OFF CACHE BOOL "") -set(SDL_THREADS ON CACHE BOOL "") -set(SDL_TIMERS ON CACHE BOOL "") -set(SDL_FILE ON CACHE BOOL "") -set(SDL_LOADSO ON CACHE BOOL "") -set(SDL_CPUINFO ON CACHE BOOL "") -set(SDL_FILESYSTEM OFF CACHE BOOL "") -set(SDL_DLOPEN ON CACHE BOOL "") -set(SDL_SENSOR OFF CACHE BOOL "") -set(SDL_LOCALE OFF CACHE BOOL "") - -add_subdirectory(SDL) diff --git a/externals/sdl2/SDL b/externals/sdl2/SDL deleted file mode 160000 index ba2f78a00..000000000 --- a/externals/sdl2/SDL +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ba2f78a0069118a6c583f1fbf1420144ffa35bad diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 793ada6dc..5d7e50847 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -180,10 +180,6 @@ if (ENABLE_TESTS) add_subdirectory(tests) endif() -if (ENABLE_SDL2 AND ENABLE_SDL2_FRONTEND) - add_subdirectory(lime) -endif() - if (ENABLE_QT) add_subdirectory(lime_qt) endif() diff --git a/src/android/app/src/main/jni/input_manager.cpp b/src/android/app/src/main/jni/input_manager.cpp index 6585ff626..4c2656b85 100644 --- a/src/android/app/src/main/jni/input_manager.cpp +++ b/src/android/app/src/main/jni/input_manager.cpp @@ -13,7 +13,6 @@ #include "common/math_util.h" #include "common/param_package.h" #include "input_common/main.h" -#include "input_common/sdl/sdl.h" #include "jni/input_manager.h" #include "jni/ndk_motion.h" diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 14a63c076..071c58b8c 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -36,7 +36,6 @@ add_library(audio_core STATIC time_stretch.cpp time_stretch.h - $<$:sdl2_sink.cpp sdl2_sink.h> $<$:cubeb_sink.cpp cubeb_sink.h cubeb_input.cpp cubeb_input.h> $<$:openal_input.cpp openal_input.h openal_sink.cpp openal_sink.h> ) @@ -46,11 +45,6 @@ create_target_directory_groups(audio_core) target_link_libraries(audio_core PUBLIC lime_common lime_core) target_link_libraries(audio_core PRIVATE faad2 SoundTouch teakra) -if(ENABLE_SDL2) - target_link_libraries(audio_core PRIVATE SDL2::SDL2) - target_compile_definitions(audio_core PRIVATE HAVE_SDL2) -endif() - if(ENABLE_CUBEB) target_link_libraries(audio_core PRIVATE cubeb) target_compile_definitions(audio_core PUBLIC HAVE_CUBEB) diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp deleted file mode 100644 index 2aa90c48a..000000000 --- a/src/audio_core/sdl2_sink.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "audio_core/audio_types.h" -#include "audio_core/sdl2_sink.h" -#include "common/assert.h" -#include "common/logging/log.h" - -namespace AudioCore { - -struct SDL2Sink::Impl { - unsigned int sample_rate = 0; - - SDL_AudioDeviceID audio_device_id = 0; - - std::function cb; - - static void Callback(void* impl_, u8* buffer, int buffer_size_in_bytes); -}; - -SDL2Sink::SDL2Sink(std::string device_name) : impl(std::make_unique()) { - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - LOG_CRITICAL(Audio_Sink, "SDL_Init(SDL_INIT_AUDIO) failed with: {}", SDL_GetError()); - impl->audio_device_id = 0; - return; - } - - SDL_AudioSpec desired_audiospec; - SDL_zero(desired_audiospec); - desired_audiospec.format = AUDIO_S16; - desired_audiospec.channels = 2; - desired_audiospec.freq = native_sample_rate; - desired_audiospec.samples = 512; - desired_audiospec.userdata = impl.get(); - desired_audiospec.callback = &Impl::Callback; - - SDL_AudioSpec obtained_audiospec; - SDL_zero(obtained_audiospec); - - const char* device = nullptr; - if (device_name != auto_device_name && !device_name.empty()) { - device = device_name.c_str(); - } - - impl->audio_device_id = - SDL_OpenAudioDevice(device, false, &desired_audiospec, &obtained_audiospec, 0); - if (impl->audio_device_id <= 0) { - LOG_CRITICAL(Audio_Sink, "SDL_OpenAudioDevice failed with code {} for device \"{}\"", - impl->audio_device_id, device_name); - return; - } - - impl->sample_rate = obtained_audiospec.freq; - - // SDL2 audio devices start out paused, unpause it: - SDL_PauseAudioDevice(impl->audio_device_id, 0); -} - -SDL2Sink::~SDL2Sink() { - if (impl->audio_device_id <= 0) - return; - - SDL_CloseAudioDevice(impl->audio_device_id); -} - -unsigned int SDL2Sink::GetNativeSampleRate() const { - if (impl->audio_device_id <= 0) - return native_sample_rate; - - return impl->sample_rate; -} - -void SDL2Sink::SetCallback(std::function cb) { - impl->cb = cb; -} - -void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) { - Impl* impl = reinterpret_cast(impl_); - if (!impl || !impl->cb) - return; - - const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16)); - - impl->cb(reinterpret_cast(buffer), num_frames); -} - -std::vector ListSDL2SinkDevices() { - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { - LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem failed with: {}", SDL_GetError()); - return {}; - } - - std::vector device_list; - const int device_count = SDL_GetNumAudioDevices(0); - for (int i = 0; i < device_count; ++i) { - device_list.push_back(SDL_GetAudioDeviceName(i, 0)); - } - - SDL_QuitSubSystem(SDL_INIT_AUDIO); - - return device_list; -} - -} // namespace AudioCore diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h deleted file mode 100644 index 6e262a0b6..000000000 --- a/src/audio_core/sdl2_sink.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "audio_core/sink.h" - -namespace AudioCore { - -class SDL2Sink final : public Sink { -public: - explicit SDL2Sink(std::string device_id); - ~SDL2Sink() override; - - unsigned int GetNativeSampleRate() const override; - - void SetCallback(std::function cb) override; - -private: - struct Impl; - std::unique_ptr impl; -}; - -std::vector ListSDL2SinkDevices(); - -} // namespace AudioCore diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp index 961e040b3..0eaa8398b 100644 --- a/src/audio_core/sink_details.cpp +++ b/src/audio_core/sink_details.cpp @@ -8,9 +8,6 @@ #include #include "audio_core/null_sink.h" #include "audio_core/sink_details.h" -#ifdef HAVE_SDL2 -#include "audio_core/sdl2_sink.h" -#endif #ifdef HAVE_CUBEB #include "audio_core/cubeb_sink.h" #endif @@ -36,13 +33,6 @@ constexpr std::array sink_details = { return std::make_unique(std::string(device_id)); }, &ListOpenALSinkDevices}, -#endif -#ifdef HAVE_SDL2 - SinkDetails{SinkType::SDL2, "SDL2", - [](std::string_view device_id) -> std::unique_ptr { - return std::make_unique(std::string(device_id)); - }, - &ListSDL2SinkDevices}, #endif SinkDetails{SinkType::Null, "None", [](std::string_view device_id) -> std::unique_ptr { diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index e0aa3b1c3..d470e1746 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(input_common STATIC precompiled_headers.h touch_from_button.cpp touch_from_button.h - sdl/sdl.cpp - sdl/sdl.h udp/client.cpp udp/client.h udp/protocol.cpp @@ -20,15 +18,6 @@ add_library(input_common STATIC udp/udp.h ) -if(ENABLE_SDL2) - target_sources(input_common PRIVATE - sdl/sdl_impl.cpp - sdl/sdl_impl.h - ) - target_link_libraries(input_common PRIVATE SDL2::SDL2) - target_compile_definitions(input_common PRIVATE HAVE_SDL2) -endif() - if(ENABLE_LIBUSB) target_sources(input_common PRIVATE gcadapter/gc_adapter.cpp diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index bcff11d20..f6c64c208 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -13,8 +13,6 @@ #include "input_common/keyboard.h" #include "input_common/main.h" #include "input_common/motion_emu.h" -#include "input_common/sdl/sdl.h" -#include "input_common/sdl/sdl_impl.h" #include "input_common/touch_from_button.h" #include "input_common/udp/udp.h" @@ -28,7 +26,6 @@ std::shared_ptr gcadapter; static std::shared_ptr keyboard; static std::shared_ptr motion_emu; static std::unique_ptr udp; -static std::unique_ptr sdl; void Init() { #ifdef ENABLE_GCADAPTER @@ -47,8 +44,6 @@ void Init() { Input::RegisterFactory("touch_from_button", std::make_shared()); - sdl = SDL::Init(); - udp = CemuhookUDP::Init(); } @@ -66,7 +61,6 @@ void Shutdown() { motion_emu.reset(); Input::UnregisterFactory("emu_window"); Input::UnregisterFactory("touch_from_button"); - sdl.reset(); udp.reset(); } @@ -103,10 +97,6 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, Common::ParamPackage GetControllerButtonBinds(const Common::ParamPackage& params, int button) { const auto native_button{static_cast(button)}; const auto engine{params.Get("engine", "")}; - if (engine == "sdl") { - return dynamic_cast(sdl.get())->GetSDLControllerButtonBindByGUID( - params.Get("guid", "0"), params.Get("port", 0), native_button); - } #ifdef ENABLE_GCADAPTER if (engine == "gcpad") { return gcbuttons->GetGcTo3DSMappedButton(params.Get("port", 0), native_button); @@ -118,10 +108,6 @@ Common::ParamPackage GetControllerButtonBinds(const Common::ParamPackage& params Common::ParamPackage GetControllerAnalogBinds(const Common::ParamPackage& params, int analog) { const auto native_analog{static_cast(analog)}; const auto engine{params.Get("engine", "")}; - if (engine == "sdl") { - return dynamic_cast(sdl.get())->GetSDLControllerAnalogBindByGUID( - params.Get("guid", "0"), params.Get("port", 0), native_analog); - } #ifdef ENABLE_GCADAPTER if (engine == "gcpad") { return gcanalog->GetGcTo3DSMappedAnalog(params.Get("port", 0), native_analog); @@ -142,9 +128,6 @@ namespace Polling { std::vector> GetPollers(DeviceType type) { std::vector> pollers; -#ifdef HAVE_SDL2 - pollers = sdl->GetPollers(type); -#endif #ifdef ENABLE_GCADAPTER switch (type) { case DeviceType::Analog: diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp deleted file mode 100644 index 644db3448..000000000 --- a/src/input_common/sdl/sdl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "input_common/sdl/sdl.h" -#ifdef HAVE_SDL2 -#include "input_common/sdl/sdl_impl.h" -#endif - -namespace InputCommon::SDL { - -std::unique_ptr Init() { -#ifdef HAVE_SDL2 - return std::make_unique(); -#else - return std::make_unique(); -#endif -} -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h deleted file mode 100644 index d7f24c68a..000000000 --- a/src/input_common/sdl/sdl.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "core/frontend/input.h" -#include "input_common/main.h" - -union SDL_Event; - -namespace Common { -class ParamPackage; -} // namespace Common - -namespace InputCommon::Polling { -class DevicePoller; -enum class DeviceType; -} // namespace InputCommon::Polling - -namespace InputCommon::SDL { - -class State { -public: - using Pollers = std::vector>; - - /// Unregisters SDL device factories and shut them down. - virtual ~State() = default; - - virtual Pollers GetPollers(Polling::DeviceType type) = 0; -}; - -class NullState : public State { -public: - Pollers GetPollers(Polling::DeviceType type) override { - return {}; - } -}; - -std::unique_ptr Init(); - -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp deleted file mode 100644 index 1833e49cb..000000000 --- a/src/input_common/sdl/sdl_impl.cpp +++ /dev/null @@ -1,1092 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/math_util.h" -#include "common/param_package.h" -#include "common/threadsafe_queue.h" -#include "core/frontend/input.h" -#include "input_common/sdl/sdl_impl.h" - -// These structures are not actually defined in the headers, so we need to define them here to use -// them. -typedef struct { - SDL_GameControllerBindType inputType; - union { - int button; - - struct { - int axis; - int axis_min; - int axis_max; - } axis; - - struct { - int hat; - int hat_mask; - } hat; - - } input; - - SDL_GameControllerBindType outputType; - union { - SDL_GameControllerButton button; - - struct { - SDL_GameControllerAxis axis; - int axis_min; - int axis_max; - } axis; - - } output; - -} SDL_ExtendedGameControllerBind; - -#if SDL_VERSION_ATLEAST(2, 26, 0) -/* our hard coded list of mapping support */ -typedef enum { - SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT, - SDL_CONTROLLER_MAPPING_PRIORITY_API, - SDL_CONTROLLER_MAPPING_PRIORITY_USER, -} SDL_ControllerMappingPriority; - -typedef struct _ControllerMapping_t { - SDL_JoystickGUID guid; - char* name; - char* mapping; - SDL_ControllerMappingPriority priority; - struct _ControllerMapping_t* next; -} ControllerMapping_t; -#endif - -struct _SDL_GameController { -#if SDL_VERSION_ATLEAST(2, 26, 0) - const void* magic; -#endif - - SDL_Joystick* joystick; /* underlying joystick device */ - int ref_count; - - const char* name; -#if SDL_VERSION_ATLEAST(2, 26, 0) - ControllerMapping_t* mapping; -#endif - int num_bindings; - SDL_ExtendedGameControllerBind* bindings; - SDL_ExtendedGameControllerBind** last_match_axis; - Uint8* last_hat_mask; - Uint32 guide_button_down; - - struct _SDL_GameController* next; /* pointer to next game controller we have allocated */ -}; - -namespace InputCommon { - -namespace SDL { - -static std::string GetGUID(SDL_Joystick* joystick) { - SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - char guid_str[33]; - SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); - return guid_str; -} - -/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice -static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); - -static int SDLEventWatcher(void* userdata, SDL_Event* event) { - SDLState* sdl_state = reinterpret_cast(userdata); - // Don't handle the event if we are configuring - if (sdl_state->polling) { - sdl_state->event_queue.Push(*event); - } else { - sdl_state->HandleGameControllerEvent(*event); - } - return 0; -} - -constexpr std::array - xinput_to_3ds_mapping = {{ - SDL_CONTROLLER_BUTTON_B, - SDL_CONTROLLER_BUTTON_A, - SDL_CONTROLLER_BUTTON_Y, - SDL_CONTROLLER_BUTTON_X, - SDL_CONTROLLER_BUTTON_DPAD_UP, - SDL_CONTROLLER_BUTTON_DPAD_DOWN, - SDL_CONTROLLER_BUTTON_DPAD_LEFT, - SDL_CONTROLLER_BUTTON_DPAD_RIGHT, - SDL_CONTROLLER_BUTTON_LEFTSHOULDER, - SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, - SDL_CONTROLLER_BUTTON_START, - SDL_CONTROLLER_BUTTON_BACK, - SDL_CONTROLLER_BUTTON_INVALID, - SDL_CONTROLLER_BUTTON_INVALID, - SDL_CONTROLLER_BUTTON_INVALID, - SDL_CONTROLLER_BUTTON_INVALID, - SDL_CONTROLLER_BUTTON_GUIDE, - SDL_CONTROLLER_BUTTON_INVALID, - }}; - -struct SDLJoystickDeleter { - void operator()(SDL_Joystick* object) { - SDL_JoystickClose(object); - } -}; -class SDLJoystick { -public: - SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, - SDL_GameController* game_controller) - : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, - sdl_controller{game_controller, &SDL_GameControllerClose} { - EnableMotion(); - } - - void EnableMotion() { - if (!sdl_controller) { - return; - } -#if SDL_VERSION_ATLEAST(2, 0, 14) - SDL_GameController* controller = sdl_controller.get(); - - if (HasMotion()) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE); - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE); - } - has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE; - has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE; - if (has_accel) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); - } - if (has_gyro) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); - } -#endif - } - - bool HasMotion() const { - return has_gyro || has_accel; - } - - void SetButton(int button, bool value) { - std::lock_guard lock{mutex}; - state.buttons[button] = value; - } - - bool GetButton(int button) const { - std::lock_guard lock{mutex}; - return state.buttons.at(button); - } - - void SetAxis(int axis, Sint16 value) { - std::lock_guard lock{mutex}; - state.axes[axis] = value; - } - - float GetAxis(int axis) const { - std::lock_guard lock{mutex}; - return state.axes.at(axis) / 32767.0f; - } - - std::tuple GetAnalog(int axis_x, int axis_y) const { - float x = GetAxis(axis_x); - float y = GetAxis(axis_y); - y = -y; // 3DS uses an y-axis inverse from SDL - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return std::make_tuple(x, y); - } - - void SetHat(int hat, Uint8 direction) { - std::lock_guard lock{mutex}; - state.hats[hat] = direction; - } - - bool GetHatDirection(int hat, Uint8 direction) const { - std::lock_guard lock{mutex}; - return (state.hats.at(hat) & direction) != 0; - } - - void SetAccel(const float x, const float y, const float z) { - std::lock_guard lock{mutex}; - state.accel.x = x; - state.accel.y = y; - state.accel.z = z; - } - void SetGyro(const float pitch, const float yaw, const float roll) { - std::lock_guard lock{mutex}; - state.gyro.x = pitch; - state.gyro.y = yaw; - state.gyro.z = roll; - } - std::tuple, Common::Vec3> GetMotion() const { - std::lock_guard lock{mutex}; - return std::make_tuple(state.accel, state.gyro); - } - - /** - * The guid of the joystick - */ - const std::string& GetGUID() const { - return guid; - } - - /** - * The number of joystick from the same type that were connected before this joystick - */ - int GetPort() const { - return port; - } - - SDL_Joystick* GetSDLJoystick() const { - return sdl_joystick.get(); - } - - SDL_GameController* GetSDLGameController() const { - return sdl_controller.get(); - } - - void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) { - sdl_joystick.reset(joystick); - sdl_controller.reset(controller); - } - -private: - struct State { - std::unordered_map buttons; - std::unordered_map axes; - std::unordered_map hats; - Common::Vec3 accel; - Common::Vec3 gyro; - } state; - std::string guid; - int port; - bool has_gyro{false}; - bool has_accel{false}; - std::unique_ptr sdl_joystick; - std::unique_ptr sdl_controller; - mutable std::mutex mutex; -}; - -struct SDLGameControllerDeleter { - void operator()(SDL_GameController* object) { - SDL_GameControllerClose(object); - } -}; -class SDLGameController { -public: - SDLGameController(std::string guid_, int port_, SDL_GameController* controller) - : guid{std::move(guid_)}, port{port_}, sdl_controller{controller} {} - - /** - * The guid of the joystick/controller - */ - const std::string& GetGUID() const { - return guid; - } - - /** - * The number of joystick from the same type that were connected before this joystick - */ - int GetPort() const { - return port; - } - - SDL_GameController* GetSDLGameController() const { - return sdl_controller.get(); - } - - void SetSDLGameController(SDL_GameController* controller) { - sdl_controller = std::unique_ptr(controller); - } - -private: - std::string guid; - int port; - std::unique_ptr sdl_controller; -}; - -/** - * Get the nth joystick with the corresponding GUID - */ -std::shared_ptr SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { - std::lock_guard lock{joystick_map_mutex}; - const auto it = joystick_map.find(guid); - if (it != joystick_map.end()) { - while (it->second.size() <= static_cast(port)) { - auto joystick = std::make_shared(guid, static_cast(it->second.size()), - nullptr, nullptr); - it->second.emplace_back(std::move(joystick)); - } - return it->second[static_cast(port)]; - } - auto joystick = std::make_shared(guid, 0, nullptr, nullptr); - return joystick_map[guid].emplace_back(std::move(joystick)); -} - -/** - * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie - * it to a SDLJoystick with the same guid and that port - */ -std::shared_ptr SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { - auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - auto map_it = joystick_map.find(guid); - - if (map_it == joystick_map.end()) { - return nullptr; - } - - const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (vec_it == map_it->second.end()) { - return nullptr; - } - - return *vec_it; -} - -Common::ParamPackage SDLState::GetSDLControllerButtonBindByGUID( - const std::string& guid, int port, Settings::NativeButton::Values button) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("guid", guid); - params.Set("port", port); - SDL_GameController* controller = GetSDLJoystickByGUID(guid, port)->GetSDLGameController(); - SDL_GameControllerButtonBind button_bind; - - if (!controller) { - LOG_WARNING(Input, "failed to open controller {}", guid); - return {{}}; - } - - auto mapped_button = xinput_to_3ds_mapping[static_cast(button)]; - if (mapped_button == SDL_CONTROLLER_BUTTON_INVALID) { - if (button == Settings::NativeButton::Values::ZL) { - button_bind = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); - } else if (button == Settings::NativeButton::Values::ZR) { - button_bind = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); - } else { - return {{}}; - } - } else { - button_bind = SDL_GameControllerGetBindForButton(controller, mapped_button); - } - - switch (button_bind.bindType) { - case SDL_CONTROLLER_BINDTYPE_BUTTON: - params.Set("button", button_bind.value.button); - break; - case SDL_CONTROLLER_BINDTYPE_HAT: - params.Set("hat", button_bind.value.hat.hat); - switch (button_bind.value.hat.hat_mask) { - case SDL_HAT_UP: - params.Set("direction", "up"); - break; - case SDL_HAT_DOWN: - params.Set("direction", "down"); - break; - case SDL_HAT_LEFT: - params.Set("direction", "left"); - break; - case SDL_HAT_RIGHT: - params.Set("direction", "right"); - break; - default: - return {{}}; - } - break; - case SDL_CONTROLLER_BINDTYPE_AXIS: - params.Set("axis", button_bind.value.axis); - -#if SDL_VERSION_ATLEAST(2, 0, 6) - { - if (mapped_button != SDL_CONTROLLER_BUTTON_INVALID) { - const SDL_ExtendedGameControllerBind extended_bind = - controller->bindings[mapped_button]; - if (extended_bind.input.axis.axis_max < extended_bind.input.axis.axis_min) { - params.Set("direction", "-"); - } else { - params.Set("direction", "+"); - } - params.Set("threshold", (extended_bind.input.axis.axis_min + - (extended_bind.input.axis.axis_max - - extended_bind.input.axis.axis_min) / - 2.0f) / - SDL_JOYSTICK_AXIS_MAX); - } - } -#else - params.Set("direction", "+"); // lacks extended_bind, so just a guess -#endif - break; - case SDL_CONTROLLER_BINDTYPE_NONE: - LOG_WARNING(Input, "Button not bound: {}", Settings::NativeButton::mapping[button]); - return {{}}; - default: - LOG_WARNING(Input, "unknown SDL bind type {}", button_bind.bindType); - return {{}}; - } - - return params; -} - -Common::ParamPackage SDLState::GetSDLControllerAnalogBindByGUID( - const std::string& guid, int port, Settings::NativeAnalog::Values analog) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("guid", guid); - params.Set("port", port); - SDL_GameController* controller = GetSDLJoystickByGUID(guid, port)->GetSDLGameController(); - SDL_GameControllerButtonBind button_bind_x; - SDL_GameControllerButtonBind button_bind_y; - - if (!controller) { - LOG_WARNING(Input, "failed to open controller {}", guid); - return {{}}; - } - - if (analog == Settings::NativeAnalog::Values::CirclePad) { - button_bind_x = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); - button_bind_y = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); - } else if (analog == Settings::NativeAnalog::Values::CStick) { - button_bind_x = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); - button_bind_y = SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); - } else { - LOG_WARNING(Input, "analog value out of range {}", analog); - return {{}}; - } - - if (button_bind_x.bindType != SDL_CONTROLLER_BINDTYPE_AXIS || - button_bind_y.bindType != SDL_CONTROLLER_BINDTYPE_AXIS) { - return {{}}; - } - params.Set("axis_x", button_bind_x.value.axis); - params.Set("axis_y", button_bind_y.value.axis); - return params; -} - -void SDLState::InitJoystick(int joystick_index) { - SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); - SDL_GameController* sdl_gamecontroller = nullptr; - - if (SDL_IsGameController(joystick_index)) { - sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); - } - - if (!sdl_joystick) { - LOG_ERROR(Input, "failed to open joystick {}, with error: {}", joystick_index, - SDL_GetError()); - return; - } - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - if (joystick_map.find(guid) == joystick_map.end()) { - auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); - joystick->EnableMotion(); - joystick_map[guid].emplace_back(std::move(joystick)); - return; - } - - auto& joystick_guid_list = joystick_map[guid]; - const auto it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); - if (it != joystick_guid_list.end()) { - (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); - (*it)->EnableMotion(); - return; - } - const int port = static_cast(joystick_guid_list.size()); - auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); - joystick->EnableMotion(); - joystick_guid_list.emplace_back(std::move(joystick)); -} - -void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { - const auto guid = GetGUID(sdl_joystick); - - std::scoped_lock lock{joystick_map_mutex}; - // This call to guid is safe since the joystick is guaranteed to be in the map - const auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (joystick_it != joystick_guid_list.end()) { - (*joystick_it)->SetSDLJoystick(nullptr, nullptr); - } -} - -void SDLState::HandleGameControllerEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_JOYBUTTONUP: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, false); - } - break; - } - case SDL_JOYBUTTONDOWN: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, true); - } - break; - } - case SDL_JOYHATMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { - joystick->SetHat(event.jhat.hat, event.jhat.value); - } - break; - } - case SDL_JOYAXISMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { - joystick->SetAxis(event.jaxis.axis, event.jaxis.value); - } - break; - } -#if SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_CONTROLLERSENSORUPDATE: { - if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { - switch (event.csensor.sensor) { - case SDL_SENSOR_ACCEL: - joystick->SetAccel(event.csensor.data[0] / SDL_STANDARD_GRAVITY, - -event.csensor.data[1] / SDL_STANDARD_GRAVITY, - event.csensor.data[2] / SDL_STANDARD_GRAVITY); - break; - case SDL_SENSOR_GYRO: - joystick->SetGyro(-event.csensor.data[0] * (180.0f / Common::PI), - event.csensor.data[1] * (180.0f / Common::PI), - -event.csensor.data[2] * (180.0f / Common::PI)); - break; - } - } - break; - } -#endif - case SDL_JOYDEVICEREMOVED: - LOG_DEBUG(Input, "Joystick removed with Instance_ID {}", event.jdevice.which); - CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); - break; - case SDL_JOYDEVICEADDED: - LOG_DEBUG(Input, "Joystick connected with device index {}", event.jdevice.which); - InitJoystick(event.jdevice.which); - break; - } -} - -void SDLState::CloseJoysticks() { - std::lock_guard lock{joystick_map_mutex}; - joystick_map.clear(); -} - -class SDLButton final : public Input::ButtonDevice { -public: - explicit SDLButton(std::shared_ptr joystick_, int button_) - : joystick(std::move(joystick_)), button(button_) {} - - bool GetStatus() const override { - return joystick->GetButton(button); - } - -private: - std::shared_ptr joystick; - int button; -}; - -class SDLDirectionButton final : public Input::ButtonDevice { -public: - explicit SDLDirectionButton(std::shared_ptr joystick_, int hat_, Uint8 direction_) - : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} - - bool GetStatus() const override { - return joystick->GetHatDirection(hat, direction); - } - -private: - std::shared_ptr joystick; - int hat; - Uint8 direction; -}; - -class SDLAxisButton final : public Input::ButtonDevice { -public: - explicit SDLAxisButton(std::shared_ptr joystick_, int axis_, float threshold_, - bool trigger_if_greater_) - : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), - trigger_if_greater(trigger_if_greater_) {} - - bool GetStatus() const override { - float axis_value = joystick->GetAxis(axis); - if (trigger_if_greater) - return axis_value > threshold; - return axis_value < threshold; - } - -private: - std::shared_ptr joystick; - int axis; - float threshold; - bool trigger_if_greater; -}; - -class SDLAnalog final : public Input::AnalogDevice { -public: - SDLAnalog(std::shared_ptr joystick_, int axis_x_, int axis_y_, float deadzone_) - : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} - - std::tuple GetStatus() const override { - const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); - const float r = std::sqrt((x * x) + (y * y)); - if (r > deadzone) { - return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)); - } - return std::make_tuple(0.0f, 0.0f); - } - -private: - std::shared_ptr joystick; - const int axis_x; - const int axis_y; - const float deadzone; -}; - -class SDLMotion final : public Input::MotionDevice { -public: - explicit SDLMotion(std::shared_ptr joystick_) : joystick(std::move(joystick_)) {} - - std::tuple, Common::Vec3> GetStatus() const override { - return joystick->GetMotion(); - } - -private: - std::shared_ptr joystick; -}; - -/// A button device factory that creates button devices from SDL joystick -class SDLButtonFactory final : public Input::Factory { -public: - explicit SDLButtonFactory(SDLState& state_) : state(state_) {} - - /** - * Creates a button device from a joystick button - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type to bind - * - "button"(optional): the index of the button to bind - * - "hat"(optional): the index of the hat to bind as direction buttons - * - "axis"(optional): the index of the axis to bind - * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", - * "down", "left" or "right" - * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is - * triggered if the axis value crosses - * - "direction"(only used for axis): "+" means the button is triggered when the axis - * value is greater than the threshold; "-" means the button is triggered when the axis - * value is smaller than the threshold - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - if (params.Has("hat")) { - const int hat = params.Get("hat", 0); - const std::string direction_name = params.Get("direction", ""); - Uint8 direction; - if (direction_name == "up") { - direction = SDL_HAT_UP; - } else if (direction_name == "down") { - direction = SDL_HAT_DOWN; - } else if (direction_name == "left") { - direction = SDL_HAT_LEFT; - } else if (direction_name == "right") { - direction = SDL_HAT_RIGHT; - } else { - direction = 0; - } - // This is necessary so accessing GetHat with hat won't crash - joystick->SetHat(hat, SDL_HAT_CENTERED); - return std::make_unique(joystick, hat, direction); - } - - if (params.Has("axis")) { - const int axis = params.Get("axis", 0); - const float threshold = params.Get("threshold", 0.5f); - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - // This is necessary so accessing GetAxis with axis won't crash - joystick->SetAxis(axis, 0); - return std::make_unique(joystick, axis, threshold, trigger_if_greater); - } - - const int button = params.Get("button", 0); - // This is necessary so accessing GetButton with button won't crash - joystick->SetButton(button, false); - return std::make_unique(joystick, button); - } - -private: - SDLState& state; -}; - -/// An analog device factory that creates analog devices from SDL joystick -class SDLAnalogFactory final : public Input::Factory { -public: - explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} - /** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - const int axis_x = params.Get("axis_x", 0); - const int axis_y = params.Get("axis_y", 1); - float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - // This is necessary so accessing GetAxis with axis_x and axis_y won't crash - joystick->SetAxis(axis_x, 0); - joystick->SetAxis(axis_y, 0); - return std::make_unique(joystick, axis_x, axis_y, deadzone); - } - -private: - SDLState& state; -}; - -class SDLMotionFactory final : public Input::Factory { -public: - explicit SDLMotionFactory(SDLState& state_) : state(state_) {} - - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - return std::make_unique(joystick); - } - -private: - SDLState& state; -}; - -SDLState::SDLState() { - using namespace Input; - RegisterFactory("sdl", std::make_shared(*this)); - RegisterFactory("sdl", std::make_shared(*this)); - RegisterFactory("sdl", std::make_shared(*this)); - - // If the frontend is going to manage the event loop, then we dont start one here - start_thread = !SDL_WasInit(SDL_INIT_GAMECONTROLLER); - if (start_thread && SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { - LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_GAMECONTROLLER) failed with: {}", SDL_GetError()); - return; - } - if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { - LOG_ERROR(Input, "Failed to set Hint for background events: {}", SDL_GetError()); - } -// these hints are only defined on sdl2.0.9 or higher -#if SDL_VERSION_ATLEAST(2, 0, 9) -#if !SDL_VERSION_ATLEAST(2, 0, 12) - // There are also hints to toggle the individual drivers if needed. - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "0"); -#endif -#endif - - // Prevent SDL from adding undesired axis -#ifdef SDL_HINT_ACCELEROMETER_AS_JOYSTICK - SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); -#endif - - // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers -#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); -#endif -#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); -#endif - - SDL_AddEventWatch(&SDLEventWatcher, this); - - initialized = true; - if (start_thread) { - poll_thread = std::thread([this] { - using namespace std::chrono_literals; - while (initialized) { - SDL_PumpEvents(); - std::this_thread::sleep_for(10ms); - } - }); - } - // Because the events for joystick connection happens before we have our event watcher added, we - // can just open all the joysticks right here - for (int i = 0; i < SDL_NumJoysticks(); ++i) { - InitJoystick(i); - } -} - -SDLState::~SDLState() { - using namespace Input; - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - - CloseJoysticks(); - SDL_DelEventWatch(&SDLEventWatcher, this); - - initialized = false; - if (start_thread) { - poll_thread.join(); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); - } -} - -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { - Common::ParamPackage params({{"engine", "sdl"}}); - - switch (event.type) { - case SDL_JOYAXISMOTION: { - auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); - params.Set("port", joystick->GetPort()); - params.Set("guid", joystick->GetGUID()); - params.Set("axis", event.jaxis.axis); - if (event.jaxis.value > 0) { - params.Set("direction", "+"); - params.Set("threshold", "0.5"); - } else { - params.Set("direction", "-"); - params.Set("threshold", "-0.5"); - } - break; - } - case SDL_JOYBUTTONUP: { - auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); - params.Set("port", joystick->GetPort()); - params.Set("guid", joystick->GetGUID()); - params.Set("button", event.jbutton.button); - break; - } - case SDL_JOYHATMOTION: { - auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); - params.Set("port", joystick->GetPort()); - params.Set("guid", joystick->GetGUID()); - params.Set("hat", event.jhat.hat); - switch (event.jhat.value) { - case SDL_HAT_UP: - params.Set("direction", "up"); - break; - case SDL_HAT_DOWN: - params.Set("direction", "down"); - break; - case SDL_HAT_LEFT: - params.Set("direction", "left"); - break; - case SDL_HAT_RIGHT: - params.Set("direction", "right"); - break; - default: - return {}; - } - break; - } - } - return params; -} - -namespace Polling { - -class SDLPoller : public InputCommon::Polling::DevicePoller { -public: - explicit SDLPoller(SDLState& state_) : state(state_) {} - - void Start() override { - state.event_queue.Clear(); - state.polling = true; - } - - void Stop() override { - state.polling = false; - } - -protected: - SDLState& state; -}; - -class SDLButtonPoller final : public SDLPoller { -public: - explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - switch (event.type) { - case SDL_JOYAXISMOTION: - if (!axis_memory.count(event.jaxis.which) || - !axis_memory[event.jaxis.which].count(event.jaxis.axis)) { - axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value; - axis_event_count[event.jaxis.which][event.jaxis.axis] = 1; - break; - } else { - axis_event_count[event.jaxis.which][event.jaxis.axis]++; - // The joystick and axis exist in our map if we take this branch, so no checks - // needed - if (std::abs( - (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) / - 32767.0) < 0.5) { - break; - } else { - if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 && - IsAxisAtPole(event.jaxis.value) && - IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) { - // If we have exactly two events and both are near a pole, this is - // likely a digital input masquerading as an analog axis; Instead of - // trying to look at the direction the axis travelled, assume the first - // event was press and the second was release; This should handle most - // digital axes while deferring to the direction of travel for analog - // axes - event.jaxis.value = static_cast(std::copysign( - 32767, axis_memory[event.jaxis.which][event.jaxis.axis])); - } else { - // There are more than two events, so this is likely a true analog axis, - // check the direction it travelled - event.jaxis.value = static_cast(std::copysign( - 32767, event.jaxis.value - - axis_memory[event.jaxis.which][event.jaxis.axis])); - } - axis_memory.clear(); - axis_event_count.clear(); - } - } - case SDL_JOYBUTTONUP: - case SDL_JOYHATMOTION: - return SDLEventToButtonParamPackage(state, event); - } - } - return {}; - } - -private: - // Determine whether an axis value is close to an extreme or center - // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per - // axis, which is why the center must be considered a pole - bool IsAxisAtPole(int16_t value) { - return std::abs(value) >= 32767 || std::abs(value) < 327; - } - std::unordered_map> axis_memory; - std::unordered_map> axis_event_count; -}; - -class SDLAnalogPoller final : public SDLPoller { -public: - explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} - - void Start() override { - SDLPoller::Start(); - - // Reset stored axes - analog_xaxis = -1; - analog_yaxis = -1; - analog_axes_joystick = -1; - } - - Common::ParamPackage GetNextInput() override { - SDL_Event event{}; - while (state.event_queue.Pop(event)) { - if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { - continue; - } - // An analog device needs two axes, so we need to store the axis for later and wait for - // a second SDL event. The axes also must be from the same joystick. - int axis = event.jaxis.axis; - if (analog_xaxis == -1) { - analog_xaxis = axis; - analog_axes_joystick = event.jaxis.which; - } else if (analog_yaxis == -1 && analog_xaxis != axis && - analog_axes_joystick == event.jaxis.which) { - analog_yaxis = axis; - } - } - Common::ParamPackage params; - if (analog_xaxis != -1 && analog_yaxis != -1) { - auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); - params.Set("engine", "sdl"); - params.Set("port", joystick->GetPort()); - params.Set("guid", joystick->GetGUID()); - params.Set("axis_x", analog_xaxis); - params.Set("axis_y", analog_yaxis); - analog_xaxis = -1; - analog_yaxis = -1; - analog_axes_joystick = -1; - return params; - } - return params; - } - -private: - int analog_xaxis = -1; - int analog_yaxis = -1; - SDL_JoystickID analog_axes_joystick = -1; -}; -} // namespace Polling - -SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) { - Pollers pollers; - - switch (type) { - case InputCommon::Polling::DeviceType::Analog: - pollers.emplace_back(std::make_unique(*this)); - break; - case InputCommon::Polling::DeviceType::Button: - pollers.emplace_back(std::make_unique(*this)); - break; - } - - return pollers; -} - -} // namespace SDL -} // namespace InputCommon diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h deleted file mode 100644 index 56f53121b..000000000 --- a/src/input_common/sdl/sdl_impl.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "input_common/sdl/sdl.h" - -union SDL_Event; -using SDL_Joystick = struct _SDL_Joystick; -using SDL_JoystickID = s32; -using SDL_GameController = struct _SDL_GameController; - -namespace InputCommon::SDL { - -class SDLJoystick; -class SDLGameController; -class SDLButtonFactory; -class SDLAnalogFactory; -class SDLMotionFactory; - -class SDLState : public State { -public: - /// Initializes and registers SDL device factories - SDLState(); - - /// Unregisters SDL device factories and shut them down. - ~SDLState() override; - - /// Handle SDL_Events for joysticks from SDL_PollEvent - void HandleGameControllerEvent(const SDL_Event& event); - - std::shared_ptr GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); - std::shared_ptr GetSDLJoystickByGUID(const std::string& guid, int port); - - Common::ParamPackage GetSDLControllerButtonBindByGUID(const std::string& guid, int port, - Settings::NativeButton::Values button); - Common::ParamPackage GetSDLControllerAnalogBindByGUID(const std::string& guid, int port, - Settings::NativeAnalog::Values analog); - - /// Get all DevicePoller that use the SDL backend for a specific device type - Pollers GetPollers(Polling::DeviceType type) override; - - /// Used by the Pollers during config - std::atomic polling = false; - Common::SPSCQueue event_queue; - -private: - void InitJoystick(int joystick_index); - void CloseJoystick(SDL_Joystick* sdl_joystick); - - /// Needs to be called before SDL_QuitSubSystem. - void CloseJoysticks(); - - /// Map of GUID of a list of corresponding virtual Joysticks - std::unordered_map>> joystick_map; - std::mutex joystick_map_mutex; - - std::shared_ptr button_factory; - std::shared_ptr analog_factory; - std::shared_ptr motion_factory; - - bool start_thread = false; - std::atomic initialized = false; - - std::thread poll_thread; -}; -} // namespace InputCommon::SDL diff --git a/src/lime/CMakeLists.txt b/src/lime/CMakeLists.txt deleted file mode 100644 index 2efc46a1b..000000000 --- a/src/lime/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) - -add_executable(lime - lime.cpp - lime.rc - config.cpp - config.h - default_ini.h - emu_window/emu_window_sdl2.cpp - emu_window/emu_window_sdl2.h - precompiled_headers.h - resource.h -) - -set_target_properties(lime PROPERTIES OUTPUT_NAME "lime3ds-cli") - -if (ENABLE_SOFTWARE_RENDERER) - target_sources(lime PRIVATE - emu_window/emu_window_sdl2_sw.cpp - emu_window/emu_window_sdl2_sw.h - ) -endif() -if (ENABLE_OPENGL) - target_sources(lime PRIVATE - emu_window/emu_window_sdl2_gl.cpp - emu_window/emu_window_sdl2_gl.h - ) -endif() -if (ENABLE_VULKAN) - target_sources(lime PRIVATE - emu_window/emu_window_sdl2_vk.cpp - emu_window/emu_window_sdl2_vk.h - ) -endif() - -create_target_directory_groups(lime) - -target_link_libraries(lime PRIVATE lime_common lime_core input_common network) -target_link_libraries(lime PRIVATE inih) -if (MSVC) - target_link_libraries(lime PRIVATE getopt) -endif() -target_link_libraries(lime PRIVATE ${PLATFORM_LIBRARIES} SDL2::SDL2 Threads::Threads) - -if (ENABLE_OPENGL) - target_link_libraries(lime PRIVATE glad) -endif() - -if(UNIX AND NOT APPLE) - install(TARGETS lime RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") -endif() - -if (LIME3DS_USE_PRECOMPILED_HEADERS) - target_precompile_headers(lime PRIVATE precompiled_headers.h) -endif() - -# Bundle in-place on MSVC so dependencies can be resolved by builds. -if (MSVC) - include(BundleTarget) - bundle_target_in_place(lime) -endif() diff --git a/src/lime/config.cpp b/src/lime/config.cpp deleted file mode 100644 index 0e6240a6e..000000000 --- a/src/lime/config.cpp +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include "common/file_util.h" -#include "common/logging/backend.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/hle/service/service.h" -#include "input_common/main.h" -#include "input_common/udp/client.h" -#include "lime/config.h" -#include "lime/default_ini.h" -#include "network/network_settings.h" - -Config::Config() { - // TODO: Don't hardcode the path; let the frontend decide where to put the config files. - sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-config.ini"; - sdl2_config = std::make_unique(sdl2_config_loc); - - Reload(); -} - -Config::~Config() = default; - -bool Config::LoadINI(const std::string& default_contents, bool retry) { - const std::string& location = this->sdl2_config_loc; - if (sdl2_config->ParseError() < 0) { - if (retry) { - LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); - FileUtil::CreateFullPath(location); - FileUtil::WriteStringToFile(true, location, default_contents); - sdl2_config = std::make_unique(location); // Reopen file - - return LoadINI(default_contents, false); - } - LOG_ERROR(Config, "Failed."); - return false; - } - LOG_INFO(Config, "Successfully loaded {}", location); - return true; -} - -static const std::array default_buttons = { - SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, SDL_SCANCODE_G, - SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_M, SDL_SCANCODE_N, - SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, -}; - -static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs{{ - { - SDL_SCANCODE_UP, - SDL_SCANCODE_DOWN, - SDL_SCANCODE_LEFT, - SDL_SCANCODE_RIGHT, - SDL_SCANCODE_D, - }, - { - SDL_SCANCODE_I, - SDL_SCANCODE_K, - SDL_SCANCODE_J, - SDL_SCANCODE_L, - SDL_SCANCODE_D, - }, -}}; - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { - std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); - if (setting_value.empty()) { - setting_value = setting.GetDefault(); - } - setting = std::move(setting_value); -} - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { - setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); -} - -template -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { - if constexpr (std::is_floating_point_v) { - setting = static_cast( - sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault())); - } else { - setting = static_cast(sdl2_config->GetInteger( - group, setting.GetLabel(), static_cast(setting.GetDefault()))); - } -} - -void Config::ReadValues() { - // Controls - // TODO: add multiple input profile support - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - Settings::values.current_input_profile.buttons[i] = - sdl2_config->GetString("Controls", Settings::NativeButton::mapping[i], default_param); - if (Settings::values.current_input_profile.buttons[i].empty()) - Settings::values.current_input_profile.buttons[i] = default_param; - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_analogs[i][4], 0.5f); - Settings::values.current_input_profile.analogs[i] = - sdl2_config->GetString("Controls", Settings::NativeAnalog::mapping[i], default_param); - if (Settings::values.current_input_profile.analogs[i].empty()) - Settings::values.current_input_profile.analogs[i] = default_param; - } - - Settings::values.current_input_profile.motion_device = sdl2_config->GetString( - "Controls", "motion_device", - "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0"); - Settings::values.current_input_profile.touch_device = - sdl2_config->GetString("Controls", "touch_device", "engine:emu_window"); - Settings::values.current_input_profile.udp_input_address = sdl2_config->GetString( - "Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); - Settings::values.current_input_profile.udp_input_port = - static_cast(sdl2_config->GetInteger("Controls", "udp_input_port", - InputCommon::CemuhookUDP::DEFAULT_PORT)); - - // Core - ReadSetting("Core", Settings::values.use_cpu_jit); - ReadSetting("Core", Settings::values.cpu_clock_percentage); - - // Renderer - ReadSetting("Renderer", Settings::values.graphics_api); - ReadSetting("Renderer", Settings::values.physical_device); - ReadSetting("Renderer", Settings::values.spirv_shader_gen); - ReadSetting("Renderer", Settings::values.async_shader_compilation); - ReadSetting("Renderer", Settings::values.async_presentation); - ReadSetting("Renderer", Settings::values.use_gles); - ReadSetting("Renderer", Settings::values.use_hw_shader); - ReadSetting("Renderer", Settings::values.shaders_accurate_mul); - ReadSetting("Renderer", Settings::values.use_shader_jit); - ReadSetting("Renderer", Settings::values.resolution_factor); - ReadSetting("Renderer", Settings::values.use_disk_shader_cache); - ReadSetting("Renderer", Settings::values.frame_limit); - ReadSetting("Renderer", Settings::values.use_vsync_new); - ReadSetting("Renderer", Settings::values.texture_filter); - ReadSetting("Renderer", Settings::values.texture_sampling); - - ReadSetting("Renderer", Settings::values.mono_render_option); - ReadSetting("Renderer", Settings::values.render_3d); - ReadSetting("Renderer", Settings::values.factor_3d); - ReadSetting("Renderer", Settings::values.pp_shader_name); - ReadSetting("Renderer", Settings::values.anaglyph_shader_name); - ReadSetting("Renderer", Settings::values.filter_mode); - - ReadSetting("Renderer", Settings::values.bg_red); - ReadSetting("Renderer", Settings::values.bg_green); - ReadSetting("Renderer", Settings::values.bg_blue); - - // Layout - ReadSetting("Layout", Settings::values.layout_option); - ReadSetting("Layout", Settings::values.swap_screen); - ReadSetting("Layout", Settings::values.upright_screen); - ReadSetting("Layout", Settings::values.large_screen_proportion); - ReadSetting("Layout", Settings::values.custom_top_x); - ReadSetting("Layout", Settings::values.custom_top_y); - ReadSetting("Layout", Settings::values.custom_top_width); - ReadSetting("Layout", Settings::values.custom_top_height); - ReadSetting("Layout", Settings::values.custom_bottom_x); - ReadSetting("Layout", Settings::values.custom_bottom_y); - ReadSetting("Layout", Settings::values.custom_bottom_width); - ReadSetting("Layout", Settings::values.custom_bottom_height); - ReadSetting("Layout", Settings::values.custom_second_layer_opacity); - - ReadSetting("Layout", Settings::values.screen_top_stretch); - ReadSetting("Layout", Settings::values.screen_top_leftright_padding); - ReadSetting("Layout", Settings::values.screen_top_topbottom_padding); - ReadSetting("Layout", Settings::values.screen_bottom_stretch); - ReadSetting("Layout", Settings::values.screen_bottom_leftright_padding); - ReadSetting("Layout", Settings::values.screen_bottom_topbottom_padding); - - ReadSetting("Layout", Settings::values.portrait_layout_option); - ReadSetting("Layout", Settings::values.custom_portrait_top_x); - ReadSetting("Layout", Settings::values.custom_portrait_top_y); - ReadSetting("Layout", Settings::values.custom_portrait_top_width); - ReadSetting("Layout", Settings::values.custom_portrait_top_height); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_x); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_y); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_width); - ReadSetting("Layout", Settings::values.custom_portrait_bottom_height); - - // Utility - ReadSetting("Utility", Settings::values.dump_textures); - ReadSetting("Utility", Settings::values.custom_textures); - ReadSetting("Utility", Settings::values.preload_textures); - ReadSetting("Utility", Settings::values.async_custom_loading); - - // Audio - ReadSetting("Audio", Settings::values.audio_emulation); - ReadSetting("Audio", Settings::values.enable_audio_stretching); - ReadSetting("Audio", Settings::values.enable_realtime_audio); - ReadSetting("Audio", Settings::values.volume); - ReadSetting("Audio", Settings::values.output_type); - ReadSetting("Audio", Settings::values.output_device); - ReadSetting("Audio", Settings::values.input_type); - ReadSetting("Audio", Settings::values.input_device); - - // Data Storage - ReadSetting("Data Storage", Settings::values.use_virtual_sd); - ReadSetting("Data Storage", Settings::values.use_custom_storage); - - if (Settings::values.use_custom_storage) { - FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir, - sdl2_config->GetString("Data Storage", "nand_directory", "")); - FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir, - sdl2_config->GetString("Data Storage", "sdmc_directory", "")); - } - - // System - ReadSetting("System", Settings::values.is_new_3ds); - ReadSetting("System", Settings::values.lle_applets); - ReadSetting("System", Settings::values.region_value); - ReadSetting("System", Settings::values.init_clock); - { - std::tm t; - t.tm_sec = 1; - t.tm_min = 0; - t.tm_hour = 0; - t.tm_mday = 1; - t.tm_mon = 0; - t.tm_year = 100; - t.tm_isdst = 0; - std::istringstream string_stream( - sdl2_config->GetString("System", "init_time", "2000-01-01 00:00:01")); - string_stream >> std::get_time(&t, "%Y-%m-%d %H:%M:%S"); - if (string_stream.fail()) { - LOG_ERROR(Config, "Failed To parse init_time. Using 2000-01-01 00:00:01"); - } - Settings::values.init_time = - std::chrono::duration_cast( - std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch()) - .count(); - } - ReadSetting("System", Settings::values.init_ticks_type); - ReadSetting("System", Settings::values.init_ticks_override); - ReadSetting("System", Settings::values.plugin_loader_enabled); - ReadSetting("System", Settings::values.allow_plugin_loader); - - { - constexpr const char* default_init_time_offset = "0 00:00:00"; - - std::string offset_string = - sdl2_config->GetString("System", "init_time_offset", default_init_time_offset); - - std::size_t sep_index = offset_string.find(' '); - - if (sep_index == std::string::npos) { - LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00"); - offset_string = default_init_time_offset; - - sep_index = offset_string.find(' '); - } - - std::string day_string = offset_string.substr(0, sep_index); - long long days = 0; - - try { - days = std::stoll(day_string); - } catch (std::logic_error&) { - LOG_ERROR(Config, "Failed to parse days in init_time_offset. Using 0"); - days = 0; - } - - long long days_in_seconds = days * 86400; - - std::tm t; - t.tm_sec = 0; - t.tm_min = 0; - t.tm_hour = 0; - t.tm_mday = 1; - t.tm_mon = 0; - t.tm_year = 100; - t.tm_isdst = 0; - - std::istringstream string_stream(offset_string.substr(sep_index + 1)); - string_stream >> std::get_time(&t, "%H:%M:%S"); - - if (string_stream.fail()) { - LOG_ERROR(Config, - "Failed to parse hours, minutes and seconds in init_time_offset. 00:00:00"); - } - - auto time_offset = - std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch(); - - auto secs = std::chrono::duration_cast(time_offset).count(); - - Settings::values.init_time_offset = static_cast(secs) + days_in_seconds; - } - - // Camera - using namespace Service::CAM; - Settings::values.camera_name[OuterRightCamera] = - sdl2_config->GetString("Camera", "camera_outer_right_name", "blank"); - Settings::values.camera_config[OuterRightCamera] = - sdl2_config->GetString("Camera", "camera_outer_right_config", ""); - Settings::values.camera_flip[OuterRightCamera] = - sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0); - Settings::values.camera_name[InnerCamera] = - sdl2_config->GetString("Camera", "camera_inner_name", "blank"); - Settings::values.camera_config[InnerCamera] = - sdl2_config->GetString("Camera", "camera_inner_config", ""); - Settings::values.camera_flip[InnerCamera] = - sdl2_config->GetInteger("Camera", "camera_inner_flip", 0); - Settings::values.camera_name[OuterLeftCamera] = - sdl2_config->GetString("Camera", "camera_outer_left_name", "blank"); - Settings::values.camera_config[OuterLeftCamera] = - sdl2_config->GetString("Camera", "camera_outer_left_config", ""); - Settings::values.camera_flip[OuterLeftCamera] = - sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0); - - // Miscellaneous - ReadSetting("Miscellaneous", Settings::values.log_filter); - - // Apply the log_filter setting as the logger has already been initialized - // 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); - - // Debugging - Settings::values.record_frame_times = - sdl2_config->GetBoolean("Debugging", "record_frame_times", false); - ReadSetting("Debugging", Settings::values.renderer_debug); - ReadSetting("Debugging", Settings::values.use_gdbstub); - ReadSetting("Debugging", Settings::values.gdbstub_port); - - for (const auto& service_module : Service::service_module_map) { - bool use_lle = sdl2_config->GetBoolean("Debugging", "LLE\\" + service_module.name, false); - Settings::values.lle_modules.emplace(service_module.name, use_lle); - } - - // Web Service - NetSettings::values.web_api_url = - sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org"); - NetSettings::values.lime3ds_username = - sdl2_config->GetString("WebService", "lime3ds_username", ""); - NetSettings::values.lime3ds_token = sdl2_config->GetString("WebService", "lime3ds_token", ""); - - // Video Dumping - Settings::values.output_format = - sdl2_config->GetString("Video Dumping", "output_format", "webm"); - Settings::values.format_options = sdl2_config->GetString("Video Dumping", "format_options", ""); - - Settings::values.video_encoder = - sdl2_config->GetString("Video Dumping", "video_encoder", "libvpx-vp9"); - - // Options for variable bit rate live streaming taken from here: - // https://developers.google.com/media/vp9/live-encoding - std::string default_video_options; - if (Settings::values.video_encoder == "libvpx-vp9") { - default_video_options = - "quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"; - } - Settings::values.video_encoder_options = - sdl2_config->GetString("Video Dumping", "video_encoder_options", default_video_options); - Settings::values.video_bitrate = - sdl2_config->GetInteger("Video Dumping", "video_bitrate", 2500000); - - Settings::values.audio_encoder = - sdl2_config->GetString("Video Dumping", "audio_encoder", "libvorbis"); - Settings::values.audio_encoder_options = - sdl2_config->GetString("Video Dumping", "audio_encoder_options", ""); - Settings::values.audio_bitrate = - sdl2_config->GetInteger("Video Dumping", "audio_bitrate", 64000); -} - -void Config::Reload() { - LoadINI(DefaultINI::sdl2_config_file); - ReadValues(); -} diff --git a/src/lime/config.h b/src/lime/config.h deleted file mode 100644 index 22a71891b..000000000 --- a/src/lime/config.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/settings.h" - -class INIReader; - -class Config { - std::unique_ptr sdl2_config; - std::string sdl2_config_loc; - - bool LoadINI(const std::string& default_contents = "", bool retry = true); - void ReadValues(); - -public: - Config(); - ~Config(); - - void Reload(); - -private: - /** - * 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 - void ReadSetting(const std::string& group, Settings::Setting& setting); -}; diff --git a/src/lime/default_ini.h b/src/lime/default_ini.h deleted file mode 100644 index 2a1b74ab5..000000000 --- a/src/lime/default_ini.h +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -namespace DefaultINI { - -const char* sdl2_config_file = R"( -[Controls] -# The input devices and parameters for each 3DS native input -# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." -# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values - -# for button input, the following devices are available: -# - "keyboard" (default) for keyboard input. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for joystick input using SDL. Required parameters: -# - "joystick": the index of the joystick to bind -# - "button"(optional): the index of the button to bind -# - "hat"(optional): the index of the hat to bind as direction buttons -# - "axis"(optional): the index of the axis to bind -# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" -# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is -# triggered if the axis value crosses -# - "direction"(only used for axis): "+" means the button is triggered when the axis value -# is greater than the threshold; "-" means the button is triggered when the axis value -# is smaller than the threshold -button_a= -button_b= -button_x= -button_y= -button_up= -button_down= -button_left= -button_right= -button_l= -button_r= -button_start= -button_select= -button_debug= -button_gpio14= -button_zl= -button_zr= -button_home= - -# for analog input, the following devices are available: -# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: -# - "up", "down", "left", "right": sub-devices for each direction. -# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" -# - "modifier": sub-devices as a modifier. -# - "modifier_scale": a float number representing the applied modifier scale to the analog input. -# Must be in range of 0.0-1.0. Defaults to 0.5 -# - "sdl" for joystick input using SDL. Required parameters: -# - "joystick": the index of the joystick to bind -# - "axis_x": the index of the axis to bind as x-axis (default to 0) -# - "axis_y": the index of the axis to bind as y-axis (default to 1) -circle_pad= -c_stick= - -# for motion input, the following devices are available: -# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: -# - "update_period": update period in milliseconds (default to 100) -# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01) -# - "tilt_clamp": the max value of the tilt angle in degrees (default to 90) -# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol -motion_device= - -# for touch input, the following devices are available: -# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required -# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol -# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system -touch_device= - -# Most desktop operating systems do not expose a way to poll the motion state of the controllers -# so as a way around it, cemuhook created a udp client/server protocol to broadcast the data directly -# from a controller device to the client program. Lime3DS has a client that can connect and read -# from any cemuhook compatible motion program. - -# IPv4 address of the udp input server (Default "127.0.0.1") -udp_input_address= - -# Port of the udp input server. (Default 26760) -udp_input_port= - -# The pad to request data on. Should be between 0 (Pad 1) and 3 (Pad 4). (Default 0) -udp_pad_index= - -[Core] -# Whether to use the Just-In-Time (JIT) compiler for CPU emulation -# 0: Interpreter (slow), 1 (default): JIT (fast) -use_cpu_jit = - -# Change the Clock Frequency of the emulated 3DS CPU. -# Underclocking can increase the performance of the game at the risk of freezing. -# Overclocking may fix lag that happens on console, but also comes with the risk of freezing. -# Range is any positive integer (but we suspect 25 - 400 is a good idea) Default is 100 -cpu_clock_percentage = - -[Renderer] -# Whether to render using OpenGL or Software -# 0: Software, 1: OpenGL (default), 2: Vulkan -graphics_api = - -# Whether to render using GLES or OpenGL -# 0 (default): OpenGL, 1: GLES -use_gles = - -# Whether to use hardware shaders to emulate 3DS shaders -# 0: Software, 1 (default): Hardware -use_hw_shader = - -# Whether to use accurate multiplication in hardware shaders -# 0: Off (Faster, but causes issues in some games) 1: On (Default. Slower, but correct) -shaders_accurate_mul = - -# Whether to use the Just-In-Time (JIT) compiler for shader emulation -# 0: Interpreter (slow), 1 (default): JIT (fast) -use_shader_jit = - -# Forces VSync on the display thread. Usually doesn't impact performance, but on some drivers it can -# so only turn this off if you notice a speed difference. -# 0: Off, 1 (default): On -use_vsync_new = - -# Reduce stuttering by storing and loading generated shaders to disk -# 0: Off, 1 (default. On) -use_disk_shader_cache = - -# Resolution scale factor -# 0: Auto (scales resolution to window size), 1: Native 3DS screen resolution, Otherwise a scale -# factor for the 3DS resolution -resolution_factor = - -# Texture filter -# 0: None, 1: Anime4K, 2: Bicubic, 3: Nearest Neighbor, 4: ScaleForce, 5: xBRZ -texture_filter = - -# Limits the speed of the game to run no faster than this value as a percentage of target speed. -# Will not have an effect if unthrottled is enabled. -# 5 - 995: Speed limit as a percentage of target game speed. 0 for unthrottled. 100 (default) -frame_limit = - -# Overrides the frame limiter to use frame_limit_alternate instead of frame_limit. -# 0: Off (default), 1: On -use_frame_limit_alternate = - -# Alternate speed limit to be used instead of frame_limit if use_frame_limit_alternate is enabled -# 5 - 995: Speed limit as a percentage of target game speed. 0 for unthrottled. 200 (default) -frame_limit_alternate = - -# The clear color for the renderer. What shows up on the sides of the bottom screen. -# Must be in range of 0.0-1.0. Defaults to 0.0 for all. -bg_red = -bg_blue = -bg_green = - -# Whether and how Stereoscopic 3D should be rendered -# 0 (default): Off, 1: Side by Side, 2: Reverse Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced -render_3d = - -# Change 3D Intensity -# 0 - 100: Intensity. 0 (default) -factor_3d = - -# Change Default Eye to Render When in Monoscopic Mode -# 0 (default): Left, 1: Right -mono_render_option = - -# The name of the post processing shader to apply. -# Loaded from shaders if render_3d is off or side by side. -pp_shader_name = - -# The name of the shader to apply when render_3d is anaglyph. -# Loaded from shaders/anaglyph -anaglyph_shader_name = - -# Whether to enable linear filtering or not -# This is required for some shaders to work correctly -# 0: Nearest, 1 (default): Linear -filter_mode = - -[Layout] -# Layout for the screen inside the render window. -# 0 (default): Default Above/Below Screen -# 1: Single Screen Only -# 2: Large Screen Small Screen -# 3: Side by Side -# 4: Separate Windows -# 5: Hybrid Screen -# 6: Custom Layout -layout_option = - -# Screen placement when using Custom layout option -# 0x, 0y is the top left corner of the render window. -custom_top_x = -custom_top_y = -custom_top_width = -custom_top_height = -custom_bottom_x = -custom_bottom_y = -custom_bottom_width = -custom_bottom_height = - -# Opacity of second layer when using custom layout option (bottom screen unless swapped) -custom_second_layer_opacity = - -# Swaps the prominent screen with the other screen. -# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. -# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent -swap_screen = - -# Toggle upright orientation, for book style games. -# 0 (default): Off, 1: On -upright_screen = - -# The proportion between the large and small screens when playing in Large Screen Small Screen layout. -# Must be a real value between 1.0 and 16.0. Default is 4 -large_screen_proportion = - -# Dumps textures as PNG to dump/textures/[Title ID]/. -# 0 (default): Off, 1: On -dump_textures = - -# Reads PNG files from load/textures/[Title ID]/ and replaces textures. -# 0 (default): Off, 1: On -custom_textures = - -# Loads all custom textures into memory before booting. -# 0 (default): Off, 1: On -preload_textures = - -# Loads custom textures asynchronously with background threads. -# 0: Off, 1 (default): On -async_custom_loading = - -[Audio] -# Whether or not to enable DSP LLE -# 0 (default): No, 1: Yes -enable_dsp_lle = - -# Whether or not to run DSP LLE on a different thread -# 0 (default): No, 1: Yes -enable_dsp_lle_thread = - -# 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 = - -# Scales audio playback speed to account for drops in emulation framerate -# 0 (default): No, 1: Yes -enable_realtime_audio = - -# Output volume. -# 1.0 (default): 100%, 0.0; mute -volume = - -# Which audio output type to use. -# 0 (default): Auto-select, 1: No audio output, 2: Cubeb (if available), 3: OpenAL (if available), 4: SDL2 (if available) -output_type = - -# Which audio output device to use. -# auto (default): Auto-select -output_device = - -# Which audio input type to use. -# 0 (default): Auto-select, 1: No audio input, 2: Static noise, 3: Cubeb (if available), 4: OpenAL (if available) -input_type = - -# Which audio input device to use. -# auto (default): Auto-select -input_device = - -[Data Storage] -# Whether to create a virtual SD card. -# 1 (default): Yes, 0: No -use_virtual_sd = - -# Whether to use custom storage locations -# 1: Yes, 0 (default): No -use_custom_storage = - -# The path of the virtual SD card directory. -# empty (default) will use the user_path -sdmc_directory = - -# The path of NAND directory. -# empty (default) will use the user_path -nand_directory = - -[System] -# The system model that Lime3DS will try to emulate -# 0: Old 3DS, 1: New 3DS (default) -is_new_3ds = - -# Whether to use LLE system applets, if installed -# 0 (default): No, 1: Yes -lle_applets = - -# The system region that Lime3DS will use during emulation -# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan -region_value = - -# The clock to use when lime3ds starts -# 0: System clock (default), 1: fixed time -init_clock = - -# Time used when init_clock is set to fixed_time in the format %Y-%m-%d %H:%M:%S -# set to fixed time. Default 2000-01-01 00:00:01 -# Note: 3DS can only handle times later then Jan 1 2000 -init_time = - -# The system ticks count to use when lime3ds starts -# 0: Random (default), 1: Fixed -init_ticks_type = - -# Tick count to use when init_ticks_type is set to Fixed. -# Defaults to 0. -init_ticks_override = - -[Camera] -# Which camera engine to use for the right outer camera -# blank (default): a dummy camera that always returns black image -camera_outer_right_name = - -# A config string for the right outer camera. Its meaning is defined by the camera engine -camera_outer_right_config = - -# The image flip to apply -# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse -camera_outer_right_flip = - -# ... for the left outer camera -camera_outer_left_name = -camera_outer_left_config = -camera_outer_left_flip = - -# ... for the inner camera -camera_inner_name = -camera_inner_config = -camera_inner_flip = - -[Miscellaneous] -# A filter which removes logs below a certain logging level. -# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical -log_filter = *:Info - -[Debugging] -# Record frame time data, can be found in the log directory. Boolean value -record_frame_times = - -# Port for listening to GDB connections. -use_gdbstub=false -gdbstub_port=24689 - -# Whether to enable additional debugging information during emulation -# 0 (default): Off, 1: On -renderer_debug = - -# To LLE a service module add "LLE\=true" - -[WebService] -# URL for Web API -web_api_url = https://api.citra-emu.org -# Username and token for Lime3DS Web Service -# See https://profile.citra-emu.org/ for more info -lime3ds_username = -lime3ds_token = - -[Video Dumping] -# Format of the video to output, default: webm -output_format = - -# Options passed to the muxer (optional) -# This is a param package, format: [key1]:[value1],[key2]:[value2],... -format_options = - -# Video encoder used, default: libvpx-vp9 -video_encoder = - -# Options passed to the video codec (optional) -video_encoder_options = - -# Video bitrate, default: 2500000 -video_bitrate = - -# Audio encoder used, default: libvorbis -audio_encoder = - -# Options passed to the audio codec (optional) -audio_encoder_options = - -# Audio bitrate, default: 64000 -audio_bitrate = -)"; -} diff --git a/src/lime/emu_window/emu_window_sdl2.cpp b/src/lime/emu_window/emu_window_sdl2.cpp deleted file mode 100644 index 83113d7d4..000000000 --- a/src/lime/emu_window/emu_window_sdl2.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#define SDL_MAIN_HANDLED -#include -#include "common/logging/log.h" -#include "common/scm_rev.h" -#include "core/core.h" -#include "input_common/keyboard.h" -#include "input_common/main.h" -#include "input_common/motion_emu.h" -#include "lime/emu_window/emu_window_sdl2.h" -#include "network/network.h" - -void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { - TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); - InputCommon::GetMotionEmu()->Tilt(x, y); -} - -void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { - if (button == SDL_BUTTON_LEFT) { - if (state == SDL_PRESSED) { - TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); - } else { - TouchReleased(); - } - } else if (button == SDL_BUTTON_RIGHT) { - if (state == SDL_PRESSED) { - InputCommon::GetMotionEmu()->BeginTilt(x, y); - } else { - InputCommon::GetMotionEmu()->EndTilt(); - } - } -} - -std::pair EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const { - int w, h; - SDL_GetWindowSize(render_window, &w, &h); - - touch_x *= w; - touch_y *= h; - - return {static_cast(std::max(std::round(touch_x), 0.0f)), - static_cast(std::max(std::round(touch_y), 0.0f))}; -} - -void EmuWindow_SDL2::OnFingerDown(float x, float y) { - // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind - // This isn't critical because the best we can do when we have that is to average them, like the - // 3DS does - - const auto [px, py] = TouchToPixelPos(x, y); - TouchPressed(px, py); -} - -void EmuWindow_SDL2::OnFingerMotion(float x, float y) { - const auto [px, py] = TouchToPixelPos(x, y); - TouchMoved(px, py); -} - -void EmuWindow_SDL2::OnFingerUp() { - TouchReleased(); -} - -void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { - if (state == SDL_PRESSED) { - InputCommon::GetKeyboard()->PressKey(key); - } else if (state == SDL_RELEASED) { - InputCommon::GetKeyboard()->ReleaseKey(key); - } -} - -bool EmuWindow_SDL2::IsOpen() const { - return is_open; -} - -void EmuWindow_SDL2::RequestClose() { - is_open = false; -} - -void EmuWindow_SDL2::OnResize() { - int width, height; - SDL_GL_GetDrawableSize(render_window, &width, &height); - UpdateCurrentFramebufferLayout(width, height); -} - -void EmuWindow_SDL2::Fullscreen() { - if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) { - return; - } - - LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); - - // Try a different fullscreening method - LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); - if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { - return; - } - - LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError()); - - // Fallback algorithm: Maximise window. - // Works on all systems (unless something is seriously wrong), so no fallback for this one. - LOG_INFO(Frontend, "Falling back on a maximised window..."); - SDL_MaximizeWindow(render_window); -} - -EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system_, bool is_secondary) - : EmuWindow(is_secondary), system(system_) {} - -EmuWindow_SDL2::~EmuWindow_SDL2() { - SDL_Quit(); -} - -void EmuWindow_SDL2::InitializeSDL2() { - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) { - LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}! Exiting...", SDL_GetError()); - exit(1); - } - - InputCommon::Init(); - Network::Init(); - - SDL_SetMainReady(); -} - -u32 EmuWindow_SDL2::GetEventWindowId(const SDL_Event& event) const { - switch (event.type) { - case SDL_WINDOWEVENT: - return event.window.windowID; - case SDL_KEYDOWN: - case SDL_KEYUP: - return event.key.windowID; - case SDL_MOUSEMOTION: - return event.motion.windowID; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - return event.button.windowID; - case SDL_MOUSEWHEEL: - return event.wheel.windowID; - case SDL_FINGERDOWN: - case SDL_FINGERMOTION: - case SDL_FINGERUP: - return event.tfinger.windowID; - case SDL_TEXTEDITING: - return event.edit.windowID; - case SDL_TEXTEDITING_EXT: - return event.editExt.windowID; - case SDL_TEXTINPUT: - return event.text.windowID; - case SDL_DROPBEGIN: - case SDL_DROPFILE: - case SDL_DROPTEXT: - case SDL_DROPCOMPLETE: - return event.drop.windowID; - case SDL_USEREVENT: - return event.user.windowID; - default: - // Event is not for any particular window, so we can just pretend it's for this one. - return render_window_id; - } -} - -void EmuWindow_SDL2::PollEvents() { - SDL_Event event; - std::vector other_window_events; - - // SDL_PollEvent returns 0 when there are no more events in the event queue - while (SDL_PollEvent(&event)) { - if (GetEventWindowId(event) != render_window_id) { - other_window_events.push_back(event); - continue; - } - - switch (event.type) { - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_SIZE_CHANGED: - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_MAXIMIZED: - case SDL_WINDOWEVENT_RESTORED: - case SDL_WINDOWEVENT_MINIMIZED: - OnResize(); - break; - case SDL_WINDOWEVENT_CLOSE: - RequestClose(); - break; - } - break; - case SDL_KEYDOWN: - case SDL_KEYUP: - OnKeyEvent(static_cast(event.key.keysym.scancode), event.key.state); - break; - case SDL_MOUSEMOTION: - // ignore if it came from touch - if (event.button.which != SDL_TOUCH_MOUSEID) - OnMouseMotion(event.motion.x, event.motion.y); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - // ignore if it came from touch - if (event.button.which != SDL_TOUCH_MOUSEID) { - OnMouseButton(event.button.button, event.button.state, event.button.x, - event.button.y); - } - break; - case SDL_FINGERDOWN: - OnFingerDown(event.tfinger.x, event.tfinger.y); - break; - case SDL_FINGERMOTION: - OnFingerMotion(event.tfinger.x, event.tfinger.y); - break; - case SDL_FINGERUP: - OnFingerUp(); - break; - case SDL_QUIT: - RequestClose(); - break; - default: - break; - } - } - for (auto& e : other_window_events) { - // This is a somewhat hacky workaround to re-emit window events meant for another window - // since SDL_PollEvent() is global but we poll events per window. - SDL_PushEvent(&e); - } - if (!is_secondary) { - UpdateFramerateCounter(); - } -} - -void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair minimal_size) { - SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second); -} - -void EmuWindow_SDL2::UpdateFramerateCounter() { - const u32 current_time = SDL_GetTicks(); - if (current_time > last_time + 2000) { - const auto results = system.GetAndResetPerfStats(); - const auto title = - fmt::format("Lime3DS {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc, results.game_fps, - results.emulation_speed * 100.0f); - SDL_SetWindowTitle(render_window, title.c_str()); - last_time = current_time; - } -} diff --git a/src/lime/emu_window/emu_window_sdl2.h b/src/lime/emu_window/emu_window_sdl2.h deleted file mode 100644 index 28f86f81a..000000000 --- a/src/lime/emu_window/emu_window_sdl2.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "common/common_types.h" -#include "core/frontend/emu_window.h" - -union SDL_Event; -struct SDL_Window; - -namespace Core { -class System; -} - -class EmuWindow_SDL2 : public Frontend::EmuWindow { -public: - explicit EmuWindow_SDL2(Core::System& system_, bool is_secondary); - ~EmuWindow_SDL2(); - - /// Initializes SDL2 - static void InitializeSDL2(); - - /// Presents the most recent frame from the video backend - virtual void Present() {} - - /// Polls window events - void PollEvents() override; - - /// Whether the window is still open, and a close request hasn't yet been sent - bool IsOpen() const; - - /// Close the window. - void RequestClose(); - -protected: - /// Gets the ID of the window an event originated from. - u32 GetEventWindowId(const SDL_Event& event) const; - - /// Called by PollEvents when a key is pressed or released. - void OnKeyEvent(int key, u8 state); - - /// Called by PollEvents when the mouse moves. - void OnMouseMotion(s32 x, s32 y); - - /// Called by PollEvents when a mouse button is pressed or released - void OnMouseButton(u32 button, u8 state, s32 x, s32 y); - - /// Translates pixel position (0..1) to pixel positions - std::pair TouchToPixelPos(float touch_x, float touch_y) const; - - /// Called by PollEvents when a finger starts touching the touchscreen - void OnFingerDown(float x, float y); - - /// Called by PollEvents when a finger moves while touching the touchscreen - void OnFingerMotion(float x, float y); - - /// Called by PollEvents when a finger stops touching the touchscreen - void OnFingerUp(); - - /// Called by PollEvents when any event that may cause the window to be resized occurs - void OnResize(); - - /// Called when user passes the fullscreen parameter flag - void Fullscreen(); - - /// Called when a configuration change affects the minimal size of the window - void OnMinimalClientAreaChangeRequest(std::pair minimal_size) override; - - /// Called when polling to update framerate - void UpdateFramerateCounter(); - - /// Is the window still open? - bool is_open = true; - - /// Internal SDL2 render window - SDL_Window* render_window; - - /// Internal SDL2 window ID - u32 render_window_id{}; - - /// Fake hidden window for the core context - SDL_Window* dummy_window; - - /// Keeps track of how often to update the title bar during gameplay - u32 last_time = 0; - - Core::System& system; -}; diff --git a/src/lime/emu_window/emu_window_sdl2_gl.cpp b/src/lime/emu_window/emu_window_sdl2_gl.cpp deleted file mode 100644 index 345c7a4f4..000000000 --- a/src/lime/emu_window/emu_window_sdl2_gl.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#define SDL_MAIN_HANDLED -#include -#include -#include "common/scm_rev.h" -#include "common/settings.h" -#include "core/core.h" -#include "lime/emu_window/emu_window_sdl2_gl.h" -#include "video_core/gpu.h" -#include "video_core/renderer_base.h" - -class SDLGLContext : public Frontend::GraphicsContext { -public: - using SDL_GLContext = void*; - - SDLGLContext() { - window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, - SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); - context = SDL_GL_CreateContext(window); - } - - ~SDLGLContext() override { - SDL_GL_DeleteContext(context); - SDL_DestroyWindow(window); - } - - void MakeCurrent() override { - SDL_GL_MakeCurrent(window, context); - } - - void DoneCurrent() override { - SDL_GL_MakeCurrent(window, nullptr); - } - -private: - SDL_Window* window; - SDL_GLContext context; -}; - -static SDL_Window* CreateGLWindow(const std::string& window_title, bool gles) { - if (gles) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - } else { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - } - return SDL_CreateWindow(window_title.c_str(), - SDL_WINDOWPOS_UNDEFINED, // x position - SDL_WINDOWPOS_UNDEFINED, // y position - Core::kScreenTopWidth, - Core::kScreenTopHeight + Core::kScreenBottomHeight, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); -} - -EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, bool is_secondary) - : EmuWindow_SDL2{system_, is_secondary} { - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); - // Enable context sharing for the shared context - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - // Enable vsync - SDL_GL_SetSwapInterval(1); - // Enable debug context - if (Settings::values.renderer_debug) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); - } - - std::string window_title = fmt::format("Lime3DS {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - - // First, try to create a context with the requested type. - render_window = CreateGLWindow(window_title, Settings::values.use_gles.GetValue()); - if (render_window == nullptr) { - // On failure, fall back to context with flipped type. - render_window = CreateGLWindow(window_title, !Settings::values.use_gles.GetValue()); - if (render_window == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError()); - exit(1); - } - } - - strict_context_required = std::strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0; - - dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, - SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); - - if (fullscreen) { - Fullscreen(); - } - - window_context = SDL_GL_CreateContext(render_window); - core_context = CreateSharedContext(); - last_saved_context = nullptr; - - if (window_context == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError()); - exit(1); - } - if (core_context == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError()); - exit(1); - } - - render_window_id = SDL_GetWindowID(render_window); - - int profile_mask = 0; - SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask); - auto gl_load_func = - profile_mask == SDL_GL_CONTEXT_PROFILE_ES ? gladLoadGLES2Loader : gladLoadGLLoader; - - if (!gl_load_func(static_cast(SDL_GL_GetProcAddress))) { - LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError()); - exit(1); - } - - OnResize(); - OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); - SDL_PumpEvents(); -} - -EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() { - core_context.reset(); - SDL_DestroyWindow(render_window); - SDL_GL_DeleteContext(window_context); -} - -std::unique_ptr EmuWindow_SDL2_GL::CreateSharedContext() const { - return std::make_unique(); -} - -void EmuWindow_SDL2_GL::MakeCurrent() { - core_context->MakeCurrent(); -} - -void EmuWindow_SDL2_GL::DoneCurrent() { - core_context->DoneCurrent(); -} - -void EmuWindow_SDL2_GL::SaveContext() { - last_saved_context = SDL_GL_GetCurrentContext(); -} - -void EmuWindow_SDL2_GL::RestoreContext() { - SDL_GL_MakeCurrent(render_window, last_saved_context); -} - -void EmuWindow_SDL2_GL::Present() { - SDL_GL_MakeCurrent(render_window, window_context); - SDL_GL_SetSwapInterval(1); - while (IsOpen()) { - system.GPU().Renderer().TryPresent(100, is_secondary); - SDL_GL_SwapWindow(render_window); - } - SDL_GL_MakeCurrent(render_window, nullptr); -} diff --git a/src/lime/emu_window/emu_window_sdl2_gl.h b/src/lime/emu_window/emu_window_sdl2_gl.h deleted file mode 100644 index c1339a049..000000000 --- a/src/lime/emu_window/emu_window_sdl2_gl.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "lime/emu_window/emu_window_sdl2.h" - -struct SDL_Window; - -namespace Core { -class System; -} - -class EmuWindow_SDL2_GL : public EmuWindow_SDL2 { -public: - explicit EmuWindow_SDL2_GL(Core::System& system_, bool fullscreen, bool is_secondary); - ~EmuWindow_SDL2_GL(); - - void Present() override; - std::unique_ptr CreateSharedContext() const override; - void MakeCurrent() override; - void DoneCurrent() override; - void SaveContext() override; - void RestoreContext() override; - -private: - using SDL_GLContext = void*; - - /// The OpenGL context associated with the window - SDL_GLContext window_context; - - /// Used by SaveContext and RestoreContext - SDL_GLContext last_saved_context; - - /// The OpenGL context associated with the core - std::unique_ptr core_context; -}; diff --git a/src/lime/emu_window/emu_window_sdl2_sw.cpp b/src/lime/emu_window/emu_window_sdl2_sw.cpp deleted file mode 100644 index f537dd381..000000000 --- a/src/lime/emu_window/emu_window_sdl2_sw.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#define SDL_MAIN_HANDLED -#include -#include -#include "common/scm_rev.h" -#include "common/settings.h" -#include "core/core.h" -#include "core/frontend/emu_window.h" -#include "lime/emu_window/emu_window_sdl2_sw.h" -#include "video_core/gpu.h" -#include "video_core/renderer_software/renderer_software.h" - -class DummyContext : public Frontend::GraphicsContext {}; - -EmuWindow_SDL2_SW::EmuWindow_SDL2_SW(Core::System& system_, bool fullscreen, bool is_secondary) - : EmuWindow_SDL2{system_, is_secondary}, system{system_} { - std::string window_title = fmt::format("Lime3DS {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - render_window = - SDL_CreateWindow(window_title.c_str(), - SDL_WINDOWPOS_UNDEFINED, // x position - SDL_WINDOWPOS_UNDEFINED, // y position - Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight, - SDL_WINDOW_SHOWN); - - if (render_window == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 window: {}", SDL_GetError()); - exit(1); - } - - window_surface = SDL_GetWindowSurface(render_window); - renderer = SDL_CreateSoftwareRenderer(window_surface); - - if (renderer == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 software renderer: {}", SDL_GetError()); - exit(1); - } - - if (fullscreen) { - Fullscreen(); - } - - render_window_id = SDL_GetWindowID(render_window); - - OnResize(); - OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); - SDL_PumpEvents(); -} - -EmuWindow_SDL2_SW::~EmuWindow_SDL2_SW() { - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(render_window); -} - -std::unique_ptr EmuWindow_SDL2_SW::CreateSharedContext() const { - return std::make_unique(); -} - -void EmuWindow_SDL2_SW::Present() { - const auto layout{Layout::DefaultFrameLayout( - Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight, false, false)}; - - using VideoCore::ScreenId; - - while (IsOpen()) { - SDL_SetRenderDrawColor(renderer, - static_cast(Settings::values.bg_red.GetValue() * 255), - static_cast(Settings::values.bg_green.GetValue() * 255), - static_cast(Settings::values.bg_blue.GetValue() * 255), 0xFF); - SDL_RenderClear(renderer); - - const auto draw_screen = [&](ScreenId screen_id) { - const auto dst_rect = - screen_id == ScreenId::TopLeft ? layout.top_screen : layout.bottom_screen; - SDL_Rect sdl_rect{static_cast(dst_rect.left), static_cast(dst_rect.top), - static_cast(dst_rect.GetWidth()), - static_cast(dst_rect.GetHeight())}; - SDL_Surface* screen = LoadFramebuffer(screen_id); - SDL_BlitSurface(screen, nullptr, window_surface, &sdl_rect); - SDL_FreeSurface(screen); - }; - - draw_screen(ScreenId::TopLeft); - draw_screen(ScreenId::Bottom); - - SDL_RenderPresent(renderer); - SDL_UpdateWindowSurface(render_window); - } -} - -SDL_Surface* EmuWindow_SDL2_SW::LoadFramebuffer(VideoCore::ScreenId screen_id) { - const auto& renderer = static_cast(system.GPU().Renderer()); - const auto& info = renderer.Screen(screen_id); - const int width = static_cast(info.width); - const int height = static_cast(info.height); - SDL_Surface* surface = - SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_ABGR8888); - SDL_LockSurface(surface); - std::memcpy(surface->pixels, info.pixels.data(), info.pixels.size()); - SDL_UnlockSurface(surface); - return surface; -} diff --git a/src/lime/emu_window/emu_window_sdl2_sw.h b/src/lime/emu_window/emu_window_sdl2_sw.h deleted file mode 100644 index 0bb4e5bc6..000000000 --- a/src/lime/emu_window/emu_window_sdl2_sw.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "lime/emu_window/emu_window_sdl2.h" - -struct SDL_Renderer; -struct SDL_Surface; - -namespace VideoCore { -enum class ScreenId : u32; -} - -namespace Core { -class System; -} - -class EmuWindow_SDL2_SW : public EmuWindow_SDL2 { -public: - explicit EmuWindow_SDL2_SW(Core::System& system, bool fullscreen, bool is_secondary); - ~EmuWindow_SDL2_SW(); - - void Present() override; - std::unique_ptr CreateSharedContext() const override; - void MakeCurrent() override {} - void DoneCurrent() override {} - -private: - /// Loads a framebuffer to an SDL surface - SDL_Surface* LoadFramebuffer(VideoCore::ScreenId screen_id); - - /// The system class. - Core::System& system; - - /// The SDL software renderer - SDL_Renderer* renderer; - - /// The window surface - SDL_Surface* window_surface; -}; diff --git a/src/lime/emu_window/emu_window_sdl2_vk.cpp b/src/lime/emu_window/emu_window_sdl2_vk.cpp deleted file mode 100644 index 09aba417a..000000000 --- a/src/lime/emu_window/emu_window_sdl2_vk.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include "common/logging/log.h" -#include "common/scm_rev.h" -#include "core/frontend/emu_window.h" -#include "lime/emu_window/emu_window_sdl2_vk.h" - -class DummyContext : public Frontend::GraphicsContext {}; - -EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, bool is_secondary) - : EmuWindow_SDL2{system, is_secondary} { - const std::string window_title = fmt::format("Lime3DS {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - render_window = - SDL_CreateWindow(window_title.c_str(), - SDL_WINDOWPOS_UNDEFINED, // x position - SDL_WINDOWPOS_UNDEFINED, // y position - Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_SysWMinfo wm; - SDL_VERSION(&wm.version); - if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) { - LOG_CRITICAL(Frontend, "Failed to get information from the window manager"); - std::exit(EXIT_FAILURE); - } - - if (fullscreen) { - Fullscreen(); - SDL_ShowCursor(false); - } - - switch (wm.subsystem) { -#ifdef SDL_VIDEO_DRIVER_WINDOWS - case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS: - window_info.type = Frontend::WindowSystemType::Windows; - window_info.render_surface = reinterpret_cast(wm.info.win.window); - break; -#endif -#ifdef SDL_VIDEO_DRIVER_X11 - case SDL_SYSWM_TYPE::SDL_SYSWM_X11: - window_info.type = Frontend::WindowSystemType::X11; - window_info.display_connection = wm.info.x11.display; - window_info.render_surface = reinterpret_cast(wm.info.x11.window); - break; -#endif -#ifdef SDL_VIDEO_DRIVER_WAYLAND - case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: - window_info.type = Frontend::WindowSystemType::Wayland; - window_info.display_connection = wm.info.wl.display; - window_info.render_surface = wm.info.wl.surface; - break; -#endif -#ifdef SDL_VIDEO_DRIVER_COCOA - case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA: - window_info.type = Frontend::WindowSystemType::MacOS; - window_info.render_surface = SDL_Metal_GetLayer(SDL_Metal_CreateView(render_window)); - break; -#endif -#ifdef SDL_VIDEO_DRIVER_ANDROID - case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID: - window_info.type = Frontend::WindowSystemType::Android; - window_info.render_surface = reinterpret_cast(wm.info.android.window); - break; -#endif - default: - LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem); - std::exit(EXIT_FAILURE); - break; - } - - render_window_id = SDL_GetWindowID(render_window); - - OnResize(); - OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); - SDL_PumpEvents(); -} - -EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default; - -std::unique_ptr EmuWindow_SDL2_VK::CreateSharedContext() const { - return std::make_unique(); -} diff --git a/src/lime/emu_window/emu_window_sdl2_vk.h b/src/lime/emu_window/emu_window_sdl2_vk.h deleted file mode 100644 index 586ae7534..000000000 --- a/src/lime/emu_window/emu_window_sdl2_vk.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "lime/emu_window/emu_window_sdl2.h" - -namespace Frontend { -class GraphicsContext; -} - -namespace Core { -class System; -} - -class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { -public: - explicit EmuWindow_SDL2_VK(Core::System& system_, bool fullscreen, bool is_secondary); - ~EmuWindow_SDL2_VK() override; - - std::unique_ptr CreateSharedContext() const override; -}; diff --git a/src/lime/lime.cpp b/src/lime/lime.cpp deleted file mode 100644 index f7a41cdd5..000000000 --- a/src/lime/lime.cpp +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include - -// This needs to be included before getopt.h because the latter #defines symbols used by it -#include "common/microprofile.h" - -#include "lime/config.h" -#include "lime/emu_window/emu_window_sdl2.h" -#ifdef ENABLE_OPENGL -#include "lime/emu_window/emu_window_sdl2_gl.h" -#endif -#ifdef ENABLE_SOFTWARE_RENDERER -#include "lime/emu_window/emu_window_sdl2_sw.h" -#endif -#ifdef ENABLE_VULKAN -#include "lime/emu_window/emu_window_sdl2_vk.h" -#endif -#include "common/common_paths.h" -#include "common/detached_tasks.h" -#include "common/file_util.h" -#include "common/logging/backend.h" -#include "common/logging/log.h" -#include "common/scm_rev.h" -#include "common/scope_exit.h" -#include "common/settings.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/dumping/backend.h" -#include "core/dumping/ffmpeg_backend.h" -#include "core/frontend/applets/default_applets.h" -#include "core/frontend/framebuffer_layout.h" -#include "core/hle/service/am/am.h" -#include "core/hle/service/cfg/cfg.h" -#include "core/movie.h" -#include "input_common/main.h" -#include "network/network.h" -#include "video_core/gpu.h" -#include "video_core/renderer_base.h" - -#ifdef __unix__ -#include "common/linux/gamemode.h" -#endif - -#undef _UNICODE -#include -#ifndef _MSC_VER -#include -#endif - -#ifdef _WIN32 -// windows.h needs to be included before shellapi.h -#include - -#include - -extern "C" { -// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -} -#endif - -static void PrintHelp(const char* argv0) { - std::cout << "Usage: " << argv0 - << " [options] \n" - "-g, --gdbport=NUMBER Enable gdb stub on port NUMBER\n" - "-i, --install=FILE Installs a specified CIA file\n" - "-m, --multiplayer=nick:password@address:port" - " Nickname, password, address and port for multiplayer\n" - "-r, --movie-record=[file] Record a movie (game inputs) to the given file\n" - "-a, --movie-record-author=AUTHOR Sets the author of the movie to be recorded\n" - "-p, --movie-play=[file] Playback the movie (game inputs) from the given file\n" - "-d, --dump-video=[file] Dumps audio and video to the given video file\n" - "-f, --fullscreen Start in fullscreen mode\n" - "-h, --help Display this help and exit\n" - "-v, --version Output version information and exit\n"; -} - -static void PrintVersion() { - std::cout << "Lime3DS " << 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"); - std::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"); - std::exit(1); - break; - case Network::RoomMember::Error::MacCollision: - LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is " - "connected to the Room"); - std::exit(1); - break; - case Network::RoomMember::Error::ConsoleIdCollision: - LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room"); - std::exit(1); - break; - case Network::RoomMember::Error::WrongPassword: - LOG_ERROR(Network, "Room replied with: Wrong password"); - std::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"); - std::exit(1); - break; - case Network::RoomMember::Error::RoomIsFull: - LOG_ERROR(Network, "The room is full"); - std::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; - default: - LOG_ERROR(Network, "Unknown network error: {}", error); - 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; - bool use_gdbstub = Settings::values.use_gdbstub.GetValue(); - u32 gdb_port = static_cast(Settings::values.gdbstub_port.GetValue()); - std::string movie_record; - std::string movie_record_author; - std::string movie_play; - std::string dump_video; - - char* endarg; -#ifdef _WIN32 - int argc_w; - auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); - - if (argv_w == nullptr) { - LOG_CRITICAL(Frontend, "Failed to get command line arguments"); - return -1; - } -#endif - std::string filepath; - - 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[] = { - {"gdbport", required_argument, 0, 'g'}, - {"install", required_argument, 0, 'i'}, - {"multiplayer", required_argument, 0, 'm'}, - {"movie-record", required_argument, 0, 'r'}, - {"movie-record-author", required_argument, 0, 'a'}, - {"movie-play", required_argument, 0, 'p'}, - {"dump-video", required_argument, 0, 'd'}, - {"fullscreen", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'v'}, - {0, 0, 0, 0}, - }; - - while (optind < argc) { - int arg = getopt_long(argc, argv, "g:i:m:r:p:fhv", long_options, &option_index); - if (arg != -1) { - switch (static_cast(arg)) { - case 'g': - errno = 0; - gdb_port = strtoul(optarg, &endarg, 0); - use_gdbstub = true; - if (endarg == optarg) - errno = EINVAL; - if (errno != 0) { - perror("--gdbport"); - exit(1); - } - break; - case 'i': { - const auto cia_progress = [](std::size_t written, std::size_t total) { - LOG_INFO(Frontend, "{:02d}%", (written * 100 / total)); - }; - if (Service::AM::InstallCIA(std::string(optarg), cia_progress) != - Service::AM::InstallStatus::Success) - errno = EINVAL; - if (errno != 0) - exit(1); - break; - } - 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 'r': - movie_record = optarg; - break; - case 'a': - movie_record_author = optarg; - break; - case 'p': - movie_play = optarg; - break; - case 'd': - dump_video = optarg; - break; - case 'f': - fullscreen = true; - LOG_INFO(Frontend, "Starting in fullscreen mode..."); - break; - case 'h': - PrintHelp(argv[0]); - return 0; - case 'v': - PrintVersion(); - return 0; - } - } else { -#ifdef _WIN32 - filepath = Common::UTF16ToUTF8(argv_w[optind]); -#else - filepath = argv[optind]; -#endif - optind++; - } - } - -#ifdef _WIN32 - LocalFree(argv_w); -#endif - - MicroProfileOnThreadCreate("EmuThread"); - SCOPE_EXIT({ MicroProfileShutdown(); }); - - if (filepath.empty()) { - LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); - return -1; - } - - if (!movie_record.empty() && !movie_play.empty()) { - LOG_CRITICAL(Frontend, "Cannot both play and record a movie"); - return -1; - } - - auto& system = Core::System::GetInstance(); - auto& movie = system.Movie(); - - if (!movie_record.empty()) { - movie.PrepareForRecording(); - } - if (!movie_play.empty()) { - movie.PrepareForPlayback(movie_play); - } - - // Apply the command line arguments - Settings::values.gdbstub_port = gdb_port; - Settings::values.use_gdbstub = use_gdbstub; - system.ApplySettings(); - - // Register frontend applets - Frontend::RegisterDefaultApplets(system); - - EmuWindow_SDL2::InitializeSDL2(); - - const auto create_emu_window = [&](bool fullscreen, - bool is_secondary) -> std::unique_ptr { - const auto graphics_api = Settings::values.graphics_api.GetValue(); - switch (graphics_api) { -#ifdef ENABLE_OPENGL - case Settings::GraphicsAPI::OpenGL: - return std::make_unique(system, fullscreen, is_secondary); -#endif -#ifdef ENABLE_VULKAN - case Settings::GraphicsAPI::Vulkan: - return std::make_unique(system, fullscreen, is_secondary); -#endif -#ifdef ENABLE_SOFTWARE_RENDERER - case Settings::GraphicsAPI::Software: - return std::make_unique(system, fullscreen, is_secondary); -#endif - default: - LOG_CRITICAL( - Frontend, - "Unknown or unsupported graphics API {}, falling back to available default", - graphics_api); -#ifdef ENABLE_OPENGL - return std::make_unique(system, fullscreen, is_secondary); -#elif ENABLE_VULKAN - return std::make_unique(system, fullscreen, is_secondary); -#elif ENABLE_SOFTWARE_RENDERER - return std::make_unique(system, fullscreen, is_secondary); -#else - // TODO: Add a null renderer backend for this, perhaps. -#error "At least one renderer must be enabled." -#endif - } - }; - - const auto emu_window{create_emu_window(fullscreen, false)}; - const bool use_secondary_window{ - Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows && - Settings::values.graphics_api.GetValue() != Settings::GraphicsAPI::Software}; - const auto secondary_window = use_secondary_window ? create_emu_window(false, true) : nullptr; - - const auto scope = emu_window->Acquire(); - - LOG_INFO(Frontend, "Lime3DS Version: {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - Settings::LogSettings(); - - const Core::System::ResultStatus load_result{ - system.Load(*emu_window, filepath, secondary_window.get())}; - - switch (load_result) { - case Core::System::ResultStatus::ErrorGetLoader: - LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); - return -1; - case Core::System::ResultStatus::ErrorLoader: - LOG_CRITICAL(Frontend, "Failed to load ROM!"); - return -1; - case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: - LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " - "being used with Lime3DS. \n\n For more information on dumping and " - "decrypting games, please refer to: " - "https://web.archive.org/web/20240304210021/https://citra-emu.org/" - "wiki/dumping-game-cartridges/"); - return -1; - case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: - LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); - return -1; - case Core::System::ResultStatus::ErrorNotInitialized: - LOG_CRITICAL(Frontend, "CPUCore not initialized"); - return -1; - case Core::System::ResultStatus::ErrorSystemMode: - LOG_CRITICAL(Frontend, "Failed to determine system mode!"); - return -1; - case Core::System::ResultStatus::Success: - break; // Expected case - default: - LOG_ERROR(Frontend, "Error while loading ROM: {}", system.GetStatusDetails()); - break; - } - - if (use_multiplayer) { - if (auto member = Network::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, Service::CFG::GetConsoleIdHash(system), address.c_str(), port, 0, - Network::NoPreferredMac, password); - } else { - LOG_ERROR(Network, "Could not access RoomMember"); - return 0; - } - } - - if (!movie_play.empty()) { - auto metadata = movie.GetMovieMetadata(movie_play); - LOG_INFO(Movie, "Author: {}", metadata.author); - LOG_INFO(Movie, "Rerecord count: {}", metadata.rerecord_count); - LOG_INFO(Movie, "Input count: {}", metadata.input_count); - movie.StartPlayback(movie_play); - } - if (!movie_record.empty()) { - movie.StartRecording(movie_record, movie_record_author); - } - if (!dump_video.empty() && DynamicLibrary::FFmpeg::LoadFFmpeg()) { - auto& renderer = system.GPU().Renderer(); - const auto layout{ - Layout::FrameLayoutFromResolutionScale(renderer.GetResolutionScaleFactor())}; - auto dumper = std::make_shared(renderer); - if (dumper->StartDumping(dump_video, layout)) { - system.RegisterVideoDumper(dumper); - } - } - -#ifdef __unix__ - Common::Linux::StartGamemode(); -#endif - - std::thread main_render_thread([&emu_window] { emu_window->Present(); }); - std::thread secondary_render_thread([&secondary_window] { - if (secondary_window) { - secondary_window->Present(); - } - }); - - std::atomic_bool stop_run; - system.GPU().Renderer().Rasterizer()->LoadDiskResources( - stop_run, [](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { - LOG_DEBUG(Frontend, "Loading stage {} progress {} {}", static_cast(stage), value, - total); - }); - - const auto secondary_is_open = [&secondary_window] { - // if the secondary window isn't created, it shouldn't affect the main loop - return secondary_window ? secondary_window->IsOpen() : true; - }; - while (emu_window->IsOpen() && secondary_is_open()) { - const auto result = system.RunLoop(); - - switch (result) { - case Core::System::ResultStatus::ShutdownRequested: - emu_window->RequestClose(); - break; - case Core::System::ResultStatus::Success: - break; - default: - LOG_ERROR(Frontend, "Error in main run loop: {}", result, system.GetStatusDetails()); - break; - } - } - emu_window->RequestClose(); - if (secondary_window) { - secondary_window->RequestClose(); - } - main_render_thread.join(); - secondary_render_thread.join(); - - movie.Shutdown(); - - auto video_dumper = system.GetVideoDumper(); - if (video_dumper && video_dumper->IsDumping()) { - video_dumper->StopDumping(); - } - - Network::Shutdown(); - InputCommon::Shutdown(); - - system.Shutdown(); - -#ifdef __unix__ - Common::Linux::StopGamemode(); -#endif - - detached_tasks.WaitForAllTasks(); - return 0; -} diff --git a/src/lime/lime.rc b/src/lime/lime.rc deleted file mode 100644 index 8ca683b8e..000000000 --- a/src/lime/lime.rc +++ /dev/null @@ -1,17 +0,0 @@ -#include "winresrc.h" -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -LIME3DS_ICON ICON "../../dist/lime.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -0 RT_MANIFEST "../../dist/lime.manifest" diff --git a/src/lime/precompiled_headers.h b/src/lime/precompiled_headers.h deleted file mode 100644 index ffbb5e177..000000000 --- a/src/lime/precompiled_headers.h +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2022 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_precompiled_headers.h" diff --git a/src/lime/resource.h b/src/lime/resource.h deleted file mode 100644 index df8e459e4..000000000 --- a/src/lime/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by pcafe.rc -// -#define IDI_ICON3 103 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/lime_qt/CMakeLists.txt b/src/lime_qt/CMakeLists.txt index 8ee3a56cd..f31ca9061 100644 --- a/src/lime_qt/CMakeLists.txt +++ b/src/lime_qt/CMakeLists.txt @@ -285,11 +285,6 @@ elseif(WIN32) endif() endif() -if(ENABLE_SDL2) - target_link_libraries(lime-qt PRIVATE SDL2::SDL2) - target_compile_definitions(lime-qt PRIVATE HAVE_SDL2) -endif() - create_target_directory_groups(lime-qt) target_link_libraries(lime-qt PRIVATE audio_core lime_common lime_core input_common network video_core) diff --git a/src/lime_qt/main.cpp b/src/lime_qt/main.cpp index 2e77c8157..68541d757 100644 --- a/src/lime_qt/main.cpp +++ b/src/lime_qt/main.cpp @@ -119,10 +119,6 @@ __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; } #endif -#ifdef HAVE_SDL2 -#include -#endif - constexpr int default_mouse_timeout = 2500; /** @@ -1133,58 +1129,9 @@ void GMainWindow::MigrateUserData() { QMessageBox::Ok); } -#if defined(HAVE_SDL2) && defined(__unix__) && !defined(__APPLE__) -static std::optional HoldWakeLockLinux(u32 window_id = 0) { - if (!QDBusConnection::sessionBus().isConnected()) { - return {}; - } - // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit - QDBusInterface xdp(QStringLiteral("org.freedesktop.portal.Desktop"), - QStringLiteral("/org/freedesktop/portal/desktop"), - QStringLiteral("org.freedesktop.portal.Inhibit")); - if (!xdp.isValid()) { - LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); - return {}; - } - QVariantMap options = {}; - //: TRANSLATORS: This string is shown to the user to explain why Lime3DS needs to prevent the - //: computer from sleeping - options.insert(QString::fromLatin1("reason"), - QCoreApplication::translate("GMainWindow", "Lime3DS is running a game")); - // 0x4: Suspend lock; 0x8: Idle lock - QDBusReply reply = - xdp.call(QString::fromLatin1("Inhibit"), - QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); - - if (reply.isValid()) { - return reply.value(); - } - LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", - reply.error().message().toStdString()); - return {}; -} - -static void ReleaseWakeLockLinux(const QDBusObjectPath& lock) { - if (!QDBusConnection::sessionBus().isConnected()) { - return; - } - QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), - QString::fromLatin1("org.freedesktop.portal.Request")); - unlocker.call(QString::fromLatin1("Close")); -} -#endif // __unix__ - void GMainWindow::PreventOSSleep() { #ifdef _WIN32 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); -#elif defined(HAVE_SDL2) - SDL_DisableScreenSaver(); -#if defined(__unix__) && !defined(__APPLE__) - auto reply = HoldWakeLockLinux(winId()); - if (reply) { - wake_lock = std::move(reply.value()); - } -#endif // defined(__unix__) && !defined(__APPLE__) #endif // _WIN32 }