From 07858a015ead4d0717a851847ddd5407a3073c3d Mon Sep 17 00:00:00 2001
From: OpenSauce04 <opensauce04@gmail.com>
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
 
-    $<$<BOOL:${ENABLE_SDL2}>:sdl2_sink.cpp sdl2_sink.h>
     $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h cubeb_input.cpp cubeb_input.h>
     $<$<BOOL:${ENABLE_OPENAL}>: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 <string>
-#include <vector>
-#include <SDL.h>
-#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<void(s16*, std::size_t)> cb;
-
-    static void Callback(void* impl_, u8* buffer, int buffer_size_in_bytes);
-};
-
-SDL2Sink::SDL2Sink(std::string device_name) : impl(std::make_unique<Impl>()) {
-    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<void(s16*, std::size_t)> cb) {
-    impl->cb = cb;
-}
-
-void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes) {
-    Impl* impl = reinterpret_cast<Impl*>(impl_);
-    if (!impl || !impl->cb)
-        return;
-
-    const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
-
-    impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
-}
-
-std::vector<std::string> ListSDL2SinkDevices() {
-    if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
-        LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem failed with: {}", SDL_GetError());
-        return {};
-    }
-
-    std::vector<std::string> 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 <cstddef>
-#include <memory>
-#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<void(s16*, std::size_t)> cb) override;
-
-private:
-    struct Impl;
-    std::unique_ptr<Impl> impl;
-};
-
-std::vector<std::string> 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 <vector>
 #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<OpenALSink>(std::string(device_id));
                 },
                 &ListOpenALSinkDevices},
-#endif
-#ifdef HAVE_SDL2
-    SinkDetails{SinkType::SDL2, "SDL2",
-                [](std::string_view device_id) -> std::unique_ptr<Sink> {
-                    return std::make_unique<SDL2Sink>(std::string(device_id));
-                },
-                &ListSDL2SinkDevices},
 #endif
     SinkDetails{SinkType::Null, "None",
                 [](std::string_view device_id) -> std::unique_ptr<Sink> {
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::Adapter> gcadapter;
 static std::shared_ptr<Keyboard> keyboard;
 static std::shared_ptr<MotionEmu> motion_emu;
 static std::unique_ptr<CemuhookUDP::State> udp;
-static std::unique_ptr<SDL::State> sdl;
 
 void Init() {
 #ifdef ENABLE_GCADAPTER
@@ -47,8 +44,6 @@ void Init() {
     Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
                                                std::make_shared<TouchFromButtonFactory>());
 
-    sdl = SDL::Init();
-
     udp = CemuhookUDP::Init();
 }
 
@@ -66,7 +61,6 @@ void Shutdown() {
     motion_emu.reset();
     Input::UnregisterFactory<Input::TouchDevice>("emu_window");
     Input::UnregisterFactory<Input::TouchDevice>("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<Settings::NativeButton::Values>(button)};
     const auto engine{params.Get("engine", "")};
-    if (engine == "sdl") {
-        return dynamic_cast<SDL::SDLState*>(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<Settings::NativeAnalog::Values>(analog)};
     const auto engine{params.Get("engine", "")};
-    if (engine == "sdl") {
-        return dynamic_cast<SDL::SDLState*>(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<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
     std::vector<std::unique_ptr<DevicePoller>> 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<State> Init() {
-#ifdef HAVE_SDL2
-    return std::make_unique<SDLState>();
-#else
-    return std::make_unique<NullState>();
-#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 <memory>
-#include <vector>
-#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<std::unique_ptr<Polling::DevicePoller>>;
-
-    /// 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<State> 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 <algorithm>
-#include <atomic>
-#include <cmath>
-#include <functional>
-#include <iterator>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <tuple>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-#include <SDL.h>
-#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<SDLState*>(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<SDL_GameControllerButton, Settings::NativeButton::NumButtons>
-    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<float, float> 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<float>, Common::Vec3<float>> 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<int, bool> buttons;
-        std::unordered_map<int, Sint16> axes;
-        std::unordered_map<int, Uint8> hats;
-        Common::Vec3<float> accel;
-        Common::Vec3<float> gyro;
-    } state;
-    std::string guid;
-    int port;
-    bool has_gyro{false};
-    bool has_accel{false};
-    std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
-    std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> 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<SDL_GameController, SDLGameControllerDeleter>(controller);
-    }
-
-private:
-    std::string guid;
-    int port;
-    std::unique_ptr<SDL_GameController, SDLGameControllerDeleter> sdl_controller;
-};
-
-/**
- * Get the nth joystick with the corresponding GUID
- */
-std::shared_ptr<SDLJoystick> 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<std::size_t>(port)) {
-            auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
-                                                          nullptr, nullptr);
-            it->second.emplace_back(std::move(joystick));
-        }
-        return it->second[static_cast<std::size_t>(port)];
-    }
-    auto joystick = std::make_shared<SDLJoystick>(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<SDLJoystick> 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<int>(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<SDLJoystick>(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<int>(joystick_guid_list.size());
-    auto joystick = std::make_shared<SDLJoystick>(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<SDLJoystick> joystick_, int button_)
-        : joystick(std::move(joystick_)), button(button_) {}
-
-    bool GetStatus() const override {
-        return joystick->GetButton(button);
-    }
-
-private:
-    std::shared_ptr<SDLJoystick> joystick;
-    int button;
-};
-
-class SDLDirectionButton final : public Input::ButtonDevice {
-public:
-    explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> 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<SDLJoystick> joystick;
-    int hat;
-    Uint8 direction;
-};
-
-class SDLAxisButton final : public Input::ButtonDevice {
-public:
-    explicit SDLAxisButton(std::shared_ptr<SDLJoystick> 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<SDLJoystick> joystick;
-    int axis;
-    float threshold;
-    bool trigger_if_greater;
-};
-
-class SDLAnalog final : public Input::AnalogDevice {
-public:
-    SDLAnalog(std::shared_ptr<SDLJoystick> 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<float, float> 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<float, float>(0.0f, 0.0f);
-    }
-
-private:
-    std::shared_ptr<SDLJoystick> joystick;
-    const int axis_x;
-    const int axis_y;
-    const float deadzone;
-};
-
-class SDLMotion final : public Input::MotionDevice {
-public:
-    explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
-
-    std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
-        return joystick->GetMotion();
-    }
-
-private:
-    std::shared_ptr<SDLJoystick> joystick;
-};
-
-/// A button device factory that creates button devices from SDL joystick
-class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
-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<Input::ButtonDevice> 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<SDLDirectionButton>(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<SDLAxisButton>(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<SDLButton>(joystick, button);
-    }
-
-private:
-    SDLState& state;
-};
-
-/// An analog device factory that creates analog devices from SDL joystick
-class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
-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<Input::AnalogDevice> 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<SDLAnalog>(joystick, axis_x, axis_y, deadzone);
-    }
-
-private:
-    SDLState& state;
-};
-
-class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
-public:
-    explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
-
-    std::unique_ptr<Input::MotionDevice> 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<SDLMotion>(joystick);
-    }
-
-private:
-    SDLState& state;
-};
-
-SDLState::SDLState() {
-    using namespace Input;
-    RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
-    RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
-    RegisterFactory<MotionDevice>("sdl", std::make_shared<SDLMotionFactory>(*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<ButtonDevice>("sdl");
-    UnregisterFactory<AnalogDevice>("sdl");
-    UnregisterFactory<MotionDevice>("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<Sint16>(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<Sint16>(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<SDL_JoystickID, std::unordered_map<uint8_t, int16_t>> axis_memory;
-    std::unordered_map<SDL_JoystickID, std::unordered_map<uint8_t, uint32_t>> 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<Polling::SDLAnalogPoller>(*this));
-        break;
-    case InputCommon::Polling::DeviceType::Button:
-        pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*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 <atomic>
-#include <memory>
-#include <thread>
-#include <unordered_map>
-#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<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
-    std::shared_ptr<SDLJoystick> 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<bool> polling = false;
-    Common::SPSCQueue<SDL_Event> 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<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
-    std::mutex joystick_map_mutex;
-
-    std::shared_ptr<SDLButtonFactory> button_factory;
-    std::shared_ptr<SDLAnalogFactory> analog_factory;
-    std::shared_ptr<SDLMotionFactory> motion_factory;
-
-    bool start_thread = false;
-    std::atomic<bool> 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 <iomanip>
-#include <memory>
-#include <sstream>
-#include <type_traits>
-#include <INIReader.h>
-#include <SDL.h>
-#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<INIReader>(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<INIReader>(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<int, Settings::NativeButton::NumButtons> 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<std::array<int, 5>, 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<std::string>& 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<bool>& setting) {
-    setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
-}
-
-template <typename Type, bool ranged>
-void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
-    if constexpr (std::is_floating_point_v<Type>) {
-        setting = static_cast<Type>(
-            sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault()));
-    } else {
-        setting = static_cast<Type>(sdl2_config->GetInteger(
-            group, setting.GetLabel(), static_cast<long>(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<u16>(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::seconds>(
-                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<std::chrono::seconds>(time_offset).count();
-
-        Settings::values.init_time_offset = static_cast<long long>(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 <memory>
-#include <string>
-#include "common/settings.h"
-
-class INIReader;
-
-class Config {
-    std::unique_ptr<INIReader> 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 <typename Type, bool ranged>
-    void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& 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\<module name>=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 <algorithm>
-#include <cstdlib>
-#include <string>
-#define SDL_MAIN_HANDLED
-#include <SDL.h>
-#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<unsigned, unsigned> 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<unsigned>(std::max(std::round(touch_x), 0.0f)),
-            static_cast<unsigned>(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<SDL_Event> 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<int>(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<u32, u32> 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 <utility>
-#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<unsigned, unsigned> 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<u32, u32> 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 <algorithm>
-#include <cstdlib>
-#include <string>
-#define SDL_MAIN_HANDLED
-#include <SDL.h>
-#include <glad/glad.h>
-#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<GLADloadproc>(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<Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
-    return std::make_unique<SDLGLContext>();
-}
-
-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 <memory>
-#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<GraphicsContext> 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<Frontend::GraphicsContext> 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 <algorithm>
-#include <cstdlib>
-#include <string>
-#define SDL_MAIN_HANDLED
-#include <SDL.h>
-#include <SDL_rect.h>
-#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<Frontend::GraphicsContext> EmuWindow_SDL2_SW::CreateSharedContext() const {
-    return std::make_unique<DummyContext>();
-}
-
-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<Uint8>(Settings::values.bg_red.GetValue() * 255),
-                               static_cast<Uint8>(Settings::values.bg_green.GetValue() * 255),
-                               static_cast<Uint8>(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<int>(dst_rect.left), static_cast<int>(dst_rect.top),
-                              static_cast<int>(dst_rect.GetWidth()),
-                              static_cast<int>(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<SwRenderer::RendererSoftware&>(system.GPU().Renderer());
-    const auto& info = renderer.Screen(screen_id);
-    const int width = static_cast<int>(info.width);
-    const int height = static_cast<int>(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 <memory>
-#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<GraphicsContext> 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 <cstdlib>
-#include <memory>
-#include <string>
-#include <SDL.h>
-#include <SDL_syswm.h>
-#include <fmt/format.h>
-#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<void*>(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<void*>(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<void*>(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<Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
-    return std::make_unique<DummyContext>();
-}
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 <memory>
-#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<Frontend::GraphicsContext> 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 <iostream>
-#include <memory>
-#include <regex>
-#include <string>
-#include <thread>
-
-// 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 <getopt.h>
-#ifndef _MSC_VER
-#include <unistd.h>
-#endif
-
-#ifdef _WIN32
-// windows.h needs to be included before shellapi.h
-#include <windows.h>
-
-#include <shellapi.h>
-
-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] <filename>\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<u32>(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<char>(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<EmuWindow_SDL2> {
-        const auto graphics_api = Settings::values.graphics_api.GetValue();
-        switch (graphics_api) {
-#ifdef ENABLE_OPENGL
-        case Settings::GraphicsAPI::OpenGL:
-            return std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
-#endif
-#ifdef ENABLE_VULKAN
-        case Settings::GraphicsAPI::Vulkan:
-            return std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, is_secondary);
-#endif
-#ifdef ENABLE_SOFTWARE_RENDERER
-        case Settings::GraphicsAPI::Software:
-            return std::make_unique<EmuWindow_SDL2_SW>(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<EmuWindow_SDL2_GL>(system, fullscreen, is_secondary);
-#elif ENABLE_VULKAN
-            return std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, is_secondary);
-#elif ENABLE_SOFTWARE_RENDERER
-            return std::make_unique<EmuWindow_SDL2_SW>(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<VideoDumper::FFmpegBackend>(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<u32>(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 <SDL.h>
-#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<QDBusObjectPath> 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<QDBusObjectPath> 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
 }