WIP: [common] port to SDL3 #2645
41 changed files with 734 additions and 737 deletions
|
@ -97,8 +97,8 @@ cmake .. -G Ninja \
|
||||||
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
||||||
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||||
-DYUZU_USE_BUNDLED_QT=OFF \
|
-DYUZU_USE_BUNDLED_QT=OFF \
|
||||||
-DYUZU_USE_BUNDLED_SDL2=OFF \
|
-DYUZU_USE_BUNDLED_SDL3=OFF \
|
||||||
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
-DYUZU_USE_EXTERNAL_SDL3=ON \
|
||||||
-DYUZU_TESTS=OFF \
|
-DYUZU_TESTS=OFF \
|
||||||
-DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \
|
-DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \
|
||||||
-DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \
|
-DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \
|
||||||
|
|
|
@ -24,7 +24,7 @@ cmake .. -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE:-Release}" \
|
-DCMAKE_BUILD_TYPE="${BUILD_TYPE:-Release}" \
|
||||||
-DENABLE_QT_TRANSLATION=ON \
|
-DENABLE_QT_TRANSLATION=ON \
|
||||||
-DUSE_DISCORD_PRESENCE=ON \
|
-DUSE_DISCORD_PRESENCE=ON \
|
||||||
-DYUZU_USE_BUNDLED_SDL2=ON \
|
-DYUZU_USE_BUNDLED_SDL3=ON \
|
||||||
-DBUILD_TESTING=OFF \
|
-DBUILD_TESTING=OFF \
|
||||||
-DYUZU_TESTS=OFF \
|
-DYUZU_TESTS=OFF \
|
||||||
-DDYNARMIC_TESTS=OFF \
|
-DDYNARMIC_TESTS=OFF \
|
||||||
|
|
|
@ -147,14 +147,14 @@ if (PLATFORM_FREEBSD)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl3/qt as dependent options.
|
||||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
# On Linux system SDL3 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||||
cmake_dependent_option(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
|
cmake_dependent_option(ENABLE_SDL3 "Enable the SDL3 frontend" ON "NOT ANDROID" OFF)
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||||
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL3 "Compile external SDL3" OFF "NOT MSVC" OFF)
|
||||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# qt stuff
|
# qt stuff
|
||||||
|
@ -232,7 +232,7 @@ option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.
|
||||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||||
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
|
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL3;NOT ANDROID" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||||
|
|
||||||
|
@ -384,9 +384,6 @@ if (PLATFORM_LINUX OR CXX_CLANG)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Other presets, e.g. steamdeck
|
|
||||||
set(YUZU_SYSTEM_PROFILE "generic" CACHE STRING "CMake and Externals profile to use. One of: generic, steamdeck")
|
|
||||||
|
|
||||||
# Configure C++ standard
|
# Configure C++ standard
|
||||||
# ===========================
|
# ===========================
|
||||||
|
|
||||||
|
@ -578,8 +575,8 @@ if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS)
|
||||||
find_package(oaknut)
|
find_package(oaknut)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
find_package(SDL2)
|
find_package(SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (USE_DISCORD_PRESENCE)
|
if (USE_DISCORD_PRESENCE)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
function(copy_yuzu_SDL_deps target_dir)
|
function(copy_yuzu_SDL_deps target_dir)
|
||||||
include(WindowsCopyFiles)
|
include(WindowsCopyFiles)
|
||||||
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
||||||
windows_copy_files(${target_dir} ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
|
windows_copy_files(${target_dir} ${SDL3_DLL_DIR} ${DLL_DEST} SDL3.dll)
|
||||||
endfunction(copy_yuzu_SDL_deps)
|
endfunction(copy_yuzu_SDL_deps)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@ set(CMAKE_SYSTEM_NAME Windows)
|
||||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||||
set(SDL2_PATH ${MINGW_PREFIX})
|
set(SDL3_PATH ${MINGW_PREFIX})
|
||||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||||
|
|
||||||
# Specify the cross compiler
|
# Specify the cross compiler
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# SPDX-FileCopyrightText: 2018 tech4me <guiwanglong@gmail.com>
|
# SPDX-FileCopyrightText: 2018 tech4me <guiwanglong@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -9,7 +11,7 @@ set(CMAKE_HOST_WIN32 TRUE)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||||
set(SDL2_PATH ${MINGW_PREFIX})
|
set(SDL3_PATH ${MINGW_PREFIX})
|
||||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||||
|
|
||||||
# Specify the cross compiler
|
# Specify the cross compiler
|
||||||
|
|
12
cpmfile.json
12
cpmfile.json
|
@ -87,6 +87,18 @@
|
||||||
"hash": "d1dece16f3b209109de02123c537bfe1adf07a62b16c166367e7e5d62e0f7c323bf804c89b3192dd6871bc58a9d879d25a1cc3f7b9da0e497cf266f165816e2a",
|
"hash": "d1dece16f3b209109de02123c537bfe1adf07a62b16c166367e7e5d62e0f7c323bf804c89b3192dd6871bc58a9d879d25a1cc3f7b9da0e497cf266f165816e2a",
|
||||||
"bundled": true
|
"bundled": true
|
||||||
},
|
},
|
||||||
|
"discord-rpc": {
|
||||||
|
"repo": "eden-emulator/discord-rpc",
|
||||||
|
"sha": "1cf7772bb6",
|
||||||
|
"hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97"
|
||||||
|
},
|
||||||
|
"simpleini": {
|
||||||
|
"package": "SimpleIni",
|
||||||
|
"repo": "brofield/simpleini",
|
||||||
|
"sha": "09c21bda1d",
|
||||||
|
"hash": "99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c",
|
||||||
|
"find_args": "MODULE"
|
||||||
|
},
|
||||||
"llvm-mingw": {
|
"llvm-mingw": {
|
||||||
"repo": "misc/llvm-mingw",
|
"repo": "misc/llvm-mingw",
|
||||||
"git_host": "git.crueter.xyz",
|
"git_host": "git.crueter.xyz",
|
||||||
|
|
|
@ -38,7 +38,7 @@ export LIBGL_ALWAYS_SOFTWARE=1
|
||||||
```
|
```
|
||||||
|
|
||||||
- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`).
|
- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`).
|
||||||
- If using OpenIndiana, due to a bug in SDL2's CMake configuration, audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana. Using external or bundled SDL2 may solve this.
|
- If using OpenIndiana, due to a bug in SDL3's CMake configuration, audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana. Using external or bundled SDL3 may solve this.
|
||||||
- System OpenSSL generally does not work. Instead, use `-DYUZU_USE_BUNDLED_OPENSSL=ON` to use a bundled static OpenSSL, or build a system dependency from source.
|
- System OpenSSL generally does not work. Instead, use `-DYUZU_USE_BUNDLED_OPENSSL=ON` to use a bundled static OpenSSL, or build a system dependency from source.
|
||||||
|
|
||||||
## OpenBSD
|
## OpenBSD
|
||||||
|
|
16
docs/Deps.md
16
docs/Deps.md
|
@ -32,7 +32,7 @@ If you are on Windows and NOT building with MSYS2, you may go [back home](Build.
|
||||||
The following are handled by Eden's externals:
|
The following are handled by Eden's externals:
|
||||||
|
|
||||||
* [FFmpeg](https://ffmpeg.org/) (should use `-DYUZU_USE_EXTERNAL_FFMPEG=ON`)
|
* [FFmpeg](https://ffmpeg.org/) (should use `-DYUZU_USE_EXTERNAL_FFMPEG=ON`)
|
||||||
* [SDL2](https://www.libsdl.org/download-2.0.php) 2.0.18+ (should use `-DYUZU_USE_EXTERNAL_SDL2=ON` OR `-DYUZU_USE_BUNDLED_SDL2=ON` to reduce compile time)
|
* [SDL3](https://github.com/libsdl-org/SDL/releases) 3.2.12+ (should use `-DYUZU_USE_EXTERNAL_SDL3=ON` OR `-DYUZU_USE_BUNDLED_SDL3=ON` to reduce compile time)
|
||||||
octocar marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
All other dependencies will be downloaded and built by [CPM](https://github.com/cpm-cmake/CPM.cmake/) if `YUZU_USE_CPM` is on, but will always use system dependencies if available (UNIX-like only):
|
All other dependencies will be downloaded and built by [CPM](https://github.com/cpm-cmake/CPM.cmake/) if `YUZU_USE_CPM` is on, but will always use system dependencies if available (UNIX-like only):
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ Click on the arrows to expand.
|
||||||
<summary>Arch Linux</summary>
|
<summary>Arch Linux</summary>
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip zydis zycore vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
|
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl3 zlib zstd zip unzip zydis zycore vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
|
||||||
```
|
```
|
||||||
|
|
||||||
* Building with QT Web Engine requires `qt6-webengine` as well.
|
* Building with QT Web Engine requires `qt6-webengine` as well.
|
||||||
|
@ -117,7 +117,7 @@ sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
* Force system libraries via CMake arguments:
|
* Force system libraries via CMake arguments:
|
||||||
* SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF`
|
* SDL3: `-DYUZU_USE_BUNDLED_SDL3=OFF -DYUZU_USE_EXTERNAL_SDL3=OFF`
|
||||||
* FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF`
|
* FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF`
|
||||||
* [RPM Fusion](https://rpmfusion.org/) is required for `ffmpeg-devel`
|
* [RPM Fusion](https://rpmfusion.org/) is required for `ffmpeg-devel`
|
||||||
* Fedora 32 or later is required.
|
* Fedora 32 or later is required.
|
||||||
|
@ -130,7 +130,7 @@ sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel
|
||||||
Install dependencies from **[Homebrew](https://brew.sh/)**
|
Install dependencies from **[Homebrew](https://brew.sh/)**
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zstd cmake Catch2 molten-vk vulkan-loader spirv-tools
|
brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl3 speexdsp zlib zstd cmake Catch2 molten-vk vulkan-loader spirv-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are compiling on Intel Mac, or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` with `/usr/local`.
|
If you are compiling on Intel Mac, or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` with `/usr/local`.
|
||||||
|
@ -147,7 +147,7 @@ brew install molten-vk vulkan-loader
|
||||||
|
|
||||||
```
|
```
|
||||||
devel/cmake
|
devel/cmake
|
||||||
devel/sdl20
|
devel/sdl30
|
||||||
devel/boost-libs
|
devel/boost-libs
|
||||||
devel/catch2
|
devel/catch2
|
||||||
devel/libfmt
|
devel/libfmt
|
||||||
|
@ -181,7 +181,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pkg_add -u
|
pkg_add -u
|
||||||
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1.1.0.27
|
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1.1.0.27
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ Run the usual update + install of essential toolings: `sudo pkg update && sudo p
|
||||||
- **gcc**: `sudo pkg install developer/gcc-14`.
|
- **gcc**: `sudo pkg install developer/gcc-14`.
|
||||||
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
|
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
|
||||||
|
|
||||||
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
|
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -203,7 +203,7 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
|
||||||
|
|
||||||
* Open the `MSYS2 MinGW 64-bit` shell (`mingw64.exe`)
|
* Open the `MSYS2 MinGW 64-bit` shell (`mingw64.exe`)
|
||||||
* Download and install all dependencies using:
|
* Download and install all dependencies using:
|
||||||
octocar marked this conversation as resolved
Outdated
crueter
commented
sdl is now lower case here sdl is now lower case here
|
|||||||
* `pacman -Syu git make mingw-w64-x86_64-SDL2 mingw-w64-x86_64-cmake mingw-w64-x86_64-python-pip mingw-w64-x86_64-qt6 mingw-w64-x86_64-toolchain autoconf libtool automake-wrapper`
|
* `pacman -Syu git make mingw-w64-x86_64-sdl3 mingw-w64-x86_64-cmake mingw-w64-x86_64-python-pip mingw-w64-x86_64-qt6 mingw-w64-x86_64-toolchain autoconf libtool automake-wrapper`
|
||||||
* Add MinGW binaries to the PATH:
|
* Add MinGW binaries to the PATH:
|
||||||
* `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
|
* `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
|
||||||
* Add VulkanSDK to the PATH:
|
* Add VulkanSDK to the PATH:
|
||||||
|
|
|
@ -40,12 +40,12 @@ Notes:
|
||||||
* Unavailable on OpenBSD
|
* Unavailable on OpenBSD
|
||||||
|
|
||||||
The following options are desktop only:
|
The following options are desktop only:
|
||||||
- `ENABLE_SDL2` (ON) Enable the SDL2 desktop, audio, and input frontend (HIGHLY RECOMMENDED!)
|
- `ENABLE_SDL3` (ON) Enable the SDL3 desktop, audio, and input frontend (HIGHLY RECOMMENDED!)
|
||||||
* Unavailable on Android
|
* Unavailable on Android
|
||||||
- `YUZU_USE_EXTERNAL_SDL2` (ON for non-UNIX) Compiles SDL2 from source
|
- `YUZU_USE_EXTERNAL_SDL3` (ON for non-UNIX) Compiles SDL3 from source
|
||||||
- `YUZU_USE_BUNDLED_SDL2` (ON for MSVC) Download a prebuilt SDL2
|
- `YUZU_USE_BUNDLED_SDL3` (ON for MSVC) Download a prebuilt SDL3
|
||||||
* Unavailable on OpenBSD
|
* Unavailable on OpenBSD
|
||||||
* Only enabled if YUZU_USE_CPM and ENABLE_SDL2 are both ON
|
* Only enabled if YUZU_USE_CPM and ENABLE_SDL3 are both ON
|
||||||
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input frontend (HIGHLY RECOMMENDED)
|
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input frontend (HIGHLY RECOMMENDED)
|
||||||
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics frontend
|
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics frontend
|
||||||
* Unavailable on Windows/ARM64 and Android
|
* Unavailable on Windows/ARM64 and Android
|
||||||
|
@ -62,7 +62,7 @@ The following options are desktop only:
|
||||||
- `YUZU_ROOM` (ON) Enable dedicated room functionality
|
- `YUZU_ROOM` (ON) Enable dedicated room functionality
|
||||||
- `YUZU_ROOM_STANDALONE` (ON) Enable standalone room executable (eden-room)
|
- `YUZU_ROOM_STANDALONE` (ON) Enable standalone room executable (eden-room)
|
||||||
* Requires `YUZU_ROOM`
|
* Requires `YUZU_ROOM`
|
||||||
- `YUZU_CMD` (ON) Compile the SDL2 frontend (eden-cli) - requires SDL2
|
- `YUZU_CMD` (ON) Compile the SDL3 frontend (eden-cli) - requires SDL3
|
||||||
- `YUZU_CRASH_DUMPS` Compile crash dump (Minidump) support"
|
- `YUZU_CRASH_DUMPS` Compile crash dump (Minidump) support"
|
||||||
* Currently only available on Windows and Linux
|
* Currently only available on Windows and Linux
|
||||||
|
|
||||||
|
|
26
externals/CMakeLists.txt
vendored
26
externals/CMakeLists.txt
vendored
|
@ -109,10 +109,10 @@ if(ENABLE_CUBEB)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
|
# find SDL3 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
if (YUZU_USE_EXTERNAL_SDL2)
|
if (YUZU_USE_EXTERNAL_SDL3)
|
||||||
message(STATUS "Using SDL2 from externals.")
|
message(STATUS "Using SDL3 from externals.")
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||||
|
@ -133,18 +133,16 @@ if (ENABLE_SDL2)
|
||||||
set(SDL_FILE ON)
|
set(SDL_FILE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
|
AddJsonPackage(sdl3)
|
||||||
set(SDL_PIPEWIRE OFF) # build errors out with this on
|
|
||||||
AddJsonPackage("sdl2_steamdeck")
|
# annoying
|
||||||
else()
|
target_include_directories(SDL3_Headers INTERFACE ${SDL3_SOURCE_DIR}/include/SDL3)
|
||||||
AddJsonPackage("sdl2_generic")
|
elseif (YUZU_USE_BUNDLED_SDL3)
|
||||||
endif()
|
message(STATUS "Using bundled SDL3")
|
||||||
elseif (YUZU_USE_BUNDLED_SDL2)
|
AddJsonPackage(sdl3-ci)
|
||||||
message(STATUS "Using bundled SDL2")
|
|
||||||
AddJsonPackage(sdl2)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(SDL2 2.26.4 REQUIRED)
|
find_package(SDL3 3.2.12 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SPIRV Headers
|
# SPIRV Headers
|
||||||
|
|
39
externals/cpmfile.json
vendored
39
externals/cpmfile.json
vendored
|
@ -146,13 +146,21 @@
|
||||||
"BUNDLE_SPEEX ON"
|
"BUNDLE_SPEEX ON"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"sdl2": {
|
"sdl3": {
|
||||||
|
"package": "SDL3",
|
||||||
|
"repo": "libsdl-org/SDL",
|
||||||
|
"tag": "release-%VERSION%",
|
||||||
|
"hash": "93766ed1f2be0af75e82c05fcb1dc0aac29ded4d0ae9a98137edfc6a4ab85412ea51199d0469254e7e5751fb37d78daff8bc0cbbc20650972f182d976c6bcc61",
|
||||||
|
"git_version": "3.2.24",
|
||||||
|
"bundled": true
|
||||||
|
},
|
||||||
|
"sdl3-ci": {
|
||||||
"ci": true,
|
"ci": true,
|
||||||
"package": "SDL2",
|
"package": "SDL3",
|
||||||
"name": "SDL2",
|
"name": "SDL3",
|
||||||
"repo": "crueter-ci/SDL2",
|
"repo": "crueter-ci/SDL3",
|
||||||
"version": "2.32.10",
|
"version": "3.2.24",
|
||||||
"min_version": "2.26.4",
|
"min_version": "3.2.12",
|
||||||
"disabled_platforms": [
|
"disabled_platforms": [
|
||||||
"macos-universal"
|
"macos-universal"
|
||||||
]
|
]
|
||||||
|
@ -179,24 +187,5 @@
|
||||||
"hash": "6c198636816a0018adbf7f735d402c64245c6fcd540b7360d4388d46f007f3a520686cdaec4705cb8cb31401b2cb4797a80b42ea5d08a6a5807c0848386f7ca1",
|
"hash": "6c198636816a0018adbf7f735d402c64245c6fcd540b7360d4388d46f007f3a520686cdaec4705cb8cb31401b2cb4797a80b42ea5d08a6a5807c0848386f7ca1",
|
||||||
"find_args": "MODULE",
|
"find_args": "MODULE",
|
||||||
"git_version": "4.22"
|
"git_version": "4.22"
|
||||||
},
|
|
||||||
"sdl2_generic": {
|
|
||||||
"package": "SDL2",
|
|
||||||
"repo": "libsdl-org/SDL",
|
|
||||||
"tag": "release-%VERSION%",
|
|
||||||
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
|
|
||||||
"key": "generic",
|
|
||||||
"bundled": true,
|
|
||||||
"git_version": "2.32.10",
|
|
||||||
"skip_updates": true
|
|
||||||
},
|
|
||||||
"sdl2_steamdeck": {
|
|
||||||
"package": "SDL2",
|
|
||||||
"repo": "libsdl-org/SDL",
|
|
||||||
"sha": "cc016b0046",
|
|
||||||
"hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b",
|
|
||||||
"key": "steamdeck",
|
|
||||||
"bundled": true,
|
|
||||||
"skip_updates": "true"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
externals/gamemode/gamemode_client.h
vendored
4
externals/gamemode/gamemode_client.h
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright (c) 2017-2019, Feral Interactive
|
Copyright (c) 2017-2019, Feral Interactive
|
||||||
|
@ -89,7 +91,7 @@ static char internal_gamemode_client_error_string[512] = { 0 };
|
||||||
/**
|
/**
|
||||||
* Load libgamemode dynamically to dislodge us from most dependencies.
|
* Load libgamemode dynamically to dislodge us from most dependencies.
|
||||||
* This allows clients to link and/or use this regardless of runtime.
|
* This allows clients to link and/or use this regardless of runtime.
|
||||||
* See SDL2 for an example of the reasoning behind this in terms of
|
* See SDL3 for an example of the reasoning behind this in terms of
|
||||||
* dynamic versioning as well.
|
* dynamic versioning as well.
|
||||||
*/
|
*/
|
||||||
static volatile int internal_libgamemode_loaded = 1;
|
static volatile int internal_libgamemode_loaded = 1;
|
||||||
|
|
|
@ -223,7 +223,7 @@ if (YUZU_TESTS)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2 AND YUZU_CMD)
|
if (ENABLE_SDL3 AND YUZU_CMD)
|
||||||
add_subdirectory(yuzu_cmd)
|
add_subdirectory(yuzu_cmd)
|
||||||
set_target_properties(yuzu-cmd PROPERTIES OUTPUT_NAME "eden-cli")
|
set_target_properties(yuzu-cmd PROPERTIES OUTPUT_NAME "eden-cli")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -77,7 +77,7 @@ android {
|
||||||
cmake {
|
cmake {
|
||||||
arguments.addAll(listOf(
|
arguments.addAll(listOf(
|
||||||
"-DENABLE_QT=0", // Don't use QT
|
"-DENABLE_QT=0", // Don't use QT
|
||||||
"-DENABLE_SDL2=0", // Don't use SDL
|
"-DENABLE_SDL3=0", // Don't use SDL
|
||||||
"-DENABLE_WEB_SERVICE=1", // Enable web service
|
"-DENABLE_WEB_SERVICE=1", // Enable web service
|
||||||
"-DENABLE_OPENSSL=ON",
|
"-DENABLE_OPENSSL=ON",
|
||||||
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
||||||
|
|
|
@ -247,14 +247,18 @@ if (ENABLE_CUBEB)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_sources(audio_core PRIVATE
|
target_sources(audio_core PRIVATE
|
||||||
sink/sdl2_sink.cpp
|
sink/sdl3_sink.cpp
|
||||||
sink/sdl2_sink.h
|
sink/sdl3_sink.h
|
||||||
octocar marked this conversation as resolved
Outdated
crueter
commented
Update filenames to sdl3 Update filenames to sdl3
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
if (TARGET SDL3::Headers)
|
||||||
|
target_link_libraries(audio_core PRIVATE SDL3::Headers)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
crueter marked this conversation as resolved
Outdated
crueter
commented
Linking to SDL3::SDL3 should set the include directories to include the Linking to SDL3::SDL3 *should* set the include directories to include the `/path/to/include/SDL3` so SDL.h should still work.
octocar
commented
SDL.h does not seem to work for me on external dependency SDL.h does not seem to work for me on external dependency
|
|||||||
|
|
||||||
#include "audio_core/common/common.h"
|
#include "audio_core/common/common.h"
|
||||||
#include "audio_core/sink/sdl2_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#include "audio_core/sink/sink_stream.h"
|
#include "audio_core/sink/sink_stream.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|
||||||
namespace AudioCore::Sink {
|
namespace AudioCore::Sink {
|
||||||
|
@ -39,37 +39,53 @@ public:
|
||||||
system_channels = system_channels_;
|
system_channels = system_channels_;
|
||||||
device_channels = device_channels_;
|
device_channels = device_channels_;
|
||||||
|
|
||||||
SDL_AudioSpec spec;
|
SDL_AudioSpec spec{};
|
||||||
spec.freq = TargetSampleRate;
|
spec.freq = TargetSampleRate;
|
||||||
spec.channels = static_cast<u8>(device_channels);
|
spec.channels = static_cast<int>(device_channels);
|
||||||
spec.format = AUDIO_S16SYS;
|
spec.format = SDL_AUDIO_S16;
|
||||||
spec.samples = TargetSampleCount * 2;
|
|
||||||
spec.callback = &SDLSinkStream::DataCallback;
|
|
||||||
spec.userdata = this;
|
|
||||||
|
|
||||||
|
SDL_AudioDeviceID device_id = 0;
|
||||||
std::string device_name{output_device};
|
std::string device_name{output_device};
|
||||||
bool capture{false};
|
bool is_capture{false};
|
||||||
|
|
||||||
if (type == StreamType::In) {
|
if (type == StreamType::In) {
|
||||||
device_name = input_device;
|
device_name = input_device;
|
||||||
capture = true;
|
is_capture = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AudioSpec obtained;
|
if (!device_name.empty()) {
|
||||||
if (device_name.empty()) {
|
int count = 0;
|
||||||
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
|
SDL_AudioDeviceID* devices = is_capture ? SDL_GetAudioRecordingDevices(&count)
|
||||||
} else {
|
: SDL_GetAudioPlaybackDevices(&count);
|
||||||
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
|
|
||||||
|
if (devices) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
const char* devname = SDL_GetAudioDeviceName(devices[i]);
|
||||||
|
if (devname && device_name == devname) {
|
||||||
|
device_id = devices[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_free(devices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device == 0) {
|
if (device_id == 0) {
|
||||||
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
|
device_id =
|
||||||
|
is_capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING : SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = SDL_OpenAudioDeviceStream(
|
||||||
|
device_id, &spec,
|
||||||
|
is_capture ? &SDLSinkStream::CaptureCallback : &SDLSinkStream::PlaybackCallback, this);
|
||||||
|
|
||||||
|
if (!stream) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio stream: {}", SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(Service_Audio,
|
LOG_INFO(Service_Audio, "Opening SDL stream with: rate {} channels {} (system channels {})",
|
||||||
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
spec.freq, spec.channels, system_channels);
|
||||||
" samples {}",
|
|
||||||
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,13 +100,14 @@ public:
|
||||||
* Finalize the sink stream.
|
* Finalize the sink stream.
|
||||||
*/
|
*/
|
||||||
void Finalize() override {
|
void Finalize() override {
|
||||||
if (device == 0) {
|
if (!stream) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop();
|
Stop();
|
||||||
SDL_ClearQueuedAudio(device);
|
SDL_ClearAudioStream(stream);
|
||||||
SDL_CloseAudioDevice(device);
|
SDL_DestroyAudioStream(stream);
|
||||||
|
stream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,62 +117,80 @@ public:
|
||||||
* Default false.
|
* Default false.
|
||||||
*/
|
*/
|
||||||
void Start(bool resume = false) override {
|
void Start(bool resume = false) override {
|
||||||
if (device == 0 || !paused) {
|
if (!stream || !paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
paused = false;
|
paused = false;
|
||||||
SDL_PauseAudioDevice(device, 0);
|
SDL_ResumeAudioStreamDevice(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the sink stream.
|
* Stop the sink stream.
|
||||||
*/
|
*/
|
||||||
void Stop() override {
|
void Stop() override {
|
||||||
if (device == 0 || paused) {
|
if (!stream || paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SignalPause();
|
SignalPause();
|
||||||
SDL_PauseAudioDevice(device, 1);
|
SDL_PauseAudioStreamDevice(stream);
|
||||||
|
paused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
static void PlaybackCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
|
||||||
* Main callback from SDL. Either expects samples from us (audio render/audio out), or will
|
int total_amount) {
|
||||||
* provide samples to be copied (audio in).
|
|
||||||
*
|
|
||||||
* @param userdata - Custom data pointer passed along, points to a SDLSinkStream.
|
|
||||||
* @param stream - Buffer of samples to be filled or read.
|
|
||||||
* @param len - Length of the stream in bytes.
|
|
||||||
*/
|
|
||||||
static void DataCallback(void* userdata, Uint8* stream, int len) {
|
|
||||||
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
||||||
|
|
||||||
if (!impl) {
|
if (!impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t num_channels = impl->GetDeviceChannels();
|
const std::size_t num_channels = impl->GetDeviceChannels();
|
||||||
const std::size_t frame_size = num_channels;
|
const std::size_t frame_size = num_channels;
|
||||||
const std::size_t num_frames{len / num_channels / sizeof(s16)};
|
const std::size_t num_frames = additional_amount / (sizeof(s16) * frame_size);
|
||||||
|
|
||||||
if (impl->type == StreamType::In) {
|
if (num_frames == 0) {
|
||||||
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
|
return;
|
||||||
num_frames * frame_size};
|
}
|
||||||
impl->ProcessAudioIn(input_buffer, num_frames);
|
|
||||||
} else {
|
std::vector<s16> buffer(num_frames * frame_size);
|
||||||
std::span<s16> output_buffer{reinterpret_cast<s16*>(stream), num_frames * frame_size};
|
impl->ProcessAudioOutAndRender(buffer, num_frames);
|
||||||
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
|
SDL_PutAudioStreamData(stream, buffer.data(),
|
||||||
|
static_cast<int>(buffer.size() * sizeof(s16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CaptureCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
|
||||||
|
int total_amount) {
|
||||||
|
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
||||||
|
if (!impl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t num_channels = impl->GetDeviceChannels();
|
||||||
|
const std::size_t frame_size = num_channels;
|
||||||
|
const std::size_t bytes_available = SDL_GetAudioStreamAvailable(stream);
|
||||||
|
|
||||||
|
if (bytes_available == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t num_frames = bytes_available / (sizeof(s16) * frame_size);
|
||||||
|
std::vector<s16> buffer(num_frames * frame_size);
|
||||||
|
|
||||||
|
int bytes_read =
|
||||||
|
SDL_GetAudioStreamData(stream, buffer.data(), static_cast<int>(bytes_available));
|
||||||
|
if (bytes_read > 0) {
|
||||||
|
const std::size_t frames_read = bytes_read / (sizeof(s16) * frame_size);
|
||||||
|
impl->ProcessAudioIn(buffer, frames_read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SDL device id of the opened input/output device
|
SDL_AudioStream* stream{nullptr};
|
||||||
SDL_AudioDeviceID device{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -218,66 +253,31 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||||
std::vector<std::string> device_list;
|
std::vector<std::string> device_list;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int device_count = SDL_GetNumAudioDevices(capture);
|
int count = 0;
|
||||||
for (int i = 0; i < device_count; ++i) {
|
SDL_AudioDeviceID* devices =
|
||||||
if (const char* name = SDL_GetAudioDeviceName(i, capture)) {
|
capture ? SDL_GetAudioRecordingDevices(&count) : SDL_GetAudioPlaybackDevices(&count);
|
||||||
device_list.emplace_back(name);
|
|
||||||
|
if (devices) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
const char* name = SDL_GetAudioDeviceName(devices[i]);
|
||||||
|
if (name) {
|
||||||
|
device_list.emplace_back(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
SDL_free(devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
return device_list;
|
return device_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* REVERSION to 3833 - function GetSDLLatency() REINTRODUCED FROM 3833 - DIABLO 3 FIX */
|
|
||||||
u32 GetSDLLatency() {
|
u32 GetSDLLatency() {
|
||||||
return TargetSampleCount * 2;
|
return TargetSampleCount * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
|
|
||||||
/*
|
|
||||||
bool IsSDLSuitable() {
|
|
||||||
#if !defined(HAVE_SDL2)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
// Check SDL can init
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
|
||||||
LOG_ERROR(Audio_Sink, "SDL failed to init, it is not suitable. Error: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can set any latency frequency we want with SDL, so no need to check that.
|
|
||||||
|
|
||||||
// Check we can open a device with standard parameters
|
|
||||||
SDL_AudioSpec spec;
|
|
||||||
spec.freq = TargetSampleRate;
|
|
||||||
spec.channels = 2u;
|
|
||||||
spec.format = AUDIO_S16SYS;
|
|
||||||
spec.samples = TargetSampleCount * 2;
|
|
||||||
spec.callback = nullptr;
|
|
||||||
spec.userdata = nullptr;
|
|
||||||
|
|
||||||
SDL_AudioSpec obtained;
|
|
||||||
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
|
|
||||||
|
|
||||||
if (device == 0) {
|
|
||||||
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_CloseAudioDevice(device);
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // namespace AudioCore::Sink
|
} // namespace AudioCore::Sink
|
|
@ -16,8 +16,8 @@
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
#include "audio_core/sink/cubeb_sink.h"
|
#include "audio_core/sink/cubeb_sink.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include "audio_core/sink/sdl2_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#endif
|
#endif
|
||||||
#include "audio_core/sink/null_sink.h"
|
#include "audio_core/sink/null_sink.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -71,9 +71,9 @@ constexpr SinkDetails sink_details[] = {
|
||||||
&GetCubebLatency,
|
&GetCubebLatency,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
Settings::AudioEngine::Sdl2,
|
Settings::AudioEngine::Sdl3,
|
||||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
return std::make_unique<SDLSink>(device_id);
|
return std::make_unique<SDLSink>(device_id);
|
||||||
},
|
},
|
||||||
|
@ -115,10 +115,10 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
||||||
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
||||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||||
// causes audio issues, in that case go with SDL.
|
// causes audio issues, in that case go with SDL.
|
||||||
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
|
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
||||||
iter = find_backend(Settings::AudioEngine::Cubeb);
|
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||||
if (iter->latency() > TargetSampleCount * 3) {
|
if (iter->latency() > TargetSampleCount * 3) {
|
||||||
iter = find_backend(Settings::AudioEngine::Sdl2);
|
iter = find_backend(Settings::AudioEngine::Sdl3);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
iter = std::begin(sink_details);
|
iter = std::begin(sink_details);
|
||||||
|
|
|
@ -92,11 +92,11 @@ struct EnumMetadata {
|
||||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||||
// canonicalizations
|
// canonicalizations
|
||||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl2, Null, Oboe, };
|
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
|
||||||
template<>
|
template<>
|
||||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||||
return {
|
return {
|
||||||
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
|
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl3", AudioEngine::Sdl3},
|
||||||
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ void Config::Initialize(const std::string& config_name) {
|
||||||
|
|
||||||
void Config::Initialize(const std::optional<std::string> config_path) {
|
void Config::Initialize(const std::optional<std::string> config_path) {
|
||||||
const std::filesystem::path default_sdl_config_path =
|
const std::filesystem::path default_sdl_config_path =
|
||||||
FS::GetEdenPath(FS::EdenPath::ConfigDir) / "sdl2-config.ini";
|
FS::GetEdenPath(FS::EdenPath::ConfigDir) / "sdl3-config.ini";
|
||||||
config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
|
config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
|
||||||
void(FS::CreateParentDir(config_loc));
|
void(FS::CreateParentDir(config_loc));
|
||||||
SetUpIni();
|
SetUpIni();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -47,7 +49,7 @@ else()
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_sources(input_common PRIVATE
|
target_sources(input_common PRIVATE
|
||||||
drivers/joycon.cpp
|
drivers/joycon.cpp
|
||||||
drivers/joycon.h
|
drivers/joycon.h
|
||||||
|
@ -73,8 +75,8 @@ if (ENABLE_SDL2)
|
||||||
helpers/joycon_protocol/rumble.cpp
|
helpers/joycon_protocol/rumble.cpp
|
||||||
helpers/joycon_protocol/rumble.h
|
helpers/joycon_protocol/rumble.h
|
||||||
)
|
)
|
||||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
target_link_libraries(input_common PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
target_compile_definitions(input_common PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LIBUSB)
|
if (ENABLE_LIBUSB)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <SDL_hidapi.h>
|
#include <SDL3/SDL_hidapi.h>
|
||||||
|
|
||||||
#include "input_common/input_engine.h"
|
#include "input_common/input_engine.h"
|
||||||
|
|
||||||
|
|
|
@ -8,55 +8,50 @@
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "input_common/drivers/sdl_driver.h"
|
#include "input_common/drivers/sdl_driver.h"
|
||||||
octocar marked this conversation as resolved
Outdated
crueter
commented
If it's not used you can remove it, no need for comment If it's not used you can remove it, no need for comment
|
|||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Common::UUID GetGUID(SDL_Joystick* joystick) {
|
Common::UUID GetGUID(SDL_Joystick* joystick) {
|
||||||
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
|
const SDL_GUID guid = SDL_GetJoystickGUID(joystick);
|
||||||
std::array<u8, 16> data{};
|
std::array<u8, 16> data{};
|
||||||
std::memcpy(data.data(), guid.data, sizeof(data));
|
std::memcpy(data.data(), guid.data, sizeof(data));
|
||||||
// Clear controller name crc
|
|
||||||
std::memset(data.data() + 2, 0, sizeof(u16));
|
std::memset(data.data() + 2, 0, sizeof(u16));
|
||||||
return Common::UUID{data};
|
return Common::UUID{data};
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
|
static bool SDLEventWatcher(void* user_data, SDL_Event* event) {
|
||||||
auto* const sdl_state = static_cast<SDLDriver*>(user_data);
|
auto* const sdl_state = static_cast<SDLDriver*>(user_data);
|
||||||
|
|
||||||
sdl_state->HandleGameControllerEvent(*event);
|
sdl_state->HandleGameControllerEvent(*event);
|
||||||
|
return false;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SDLJoystick {
|
class SDLJoystick {
|
||||||
public:
|
public:
|
||||||
SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick,
|
SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick, SDL_Gamepad* gamepad)
|
||||||
SDL_GameController* game_controller)
|
: guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_CloseJoystick},
|
||||||
: guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
|
sdl_gamepad{gamepad, &SDL_CloseGamepad} {
|
||||||
sdl_controller{game_controller, &SDL_GameControllerClose} {
|
|
||||||
EnableMotion();
|
EnableMotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnableMotion() {
|
void EnableMotion() {
|
||||||
if (!sdl_controller) {
|
if (!sdl_gamepad) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_GameController* controller = sdl_controller.get();
|
SDL_Gamepad* gamepad = sdl_gamepad.get();
|
||||||
if (HasMotion()) {
|
if (HasMotion()) {
|
||||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE);
|
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, false);
|
||||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE);
|
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_GYRO, false);
|
||||||
}
|
}
|
||||||
has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
|
has_accel = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_ACCEL);
|
||||||
has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
|
has_gyro = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_GYRO);
|
||||||
if (has_accel) {
|
if (has_accel) {
|
||||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
|
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, true);
|
||||||
}
|
}
|
||||||
if (has_gyro) {
|
if (has_gyro) {
|
||||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
|
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_GYRO, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +59,7 @@ public:
|
||||||
return has_gyro || has_accel;
|
return has_gyro || has_accel;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateMotion(SDL_ControllerSensorEvent event) {
|
bool UpdateMotion(SDL_GamepadSensorEvent event) {
|
||||||
constexpr float gravity_constant = 9.80665f;
|
constexpr float gravity_constant = 9.80665f;
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const u64 time_difference = event.timestamp - last_motion_update;
|
const u64 time_difference = event.timestamp - last_motion_update;
|
||||||
|
@ -84,25 +79,22 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore duplicated timestamps
|
|
||||||
if (time_difference == 0) {
|
if (time_difference == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Motion data is invalid
|
|
||||||
if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 &&
|
if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 &&
|
||||||
motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) {
|
motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) {
|
||||||
if (motion_error_count++ < 200) {
|
if (motion_error_count++ < 200) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Try restarting the sensor
|
|
||||||
motion_error_count = 0;
|
motion_error_count = 0;
|
||||||
EnableMotion();
|
EnableMotion();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
motion_error_count = 0;
|
motion_error_count = 0;
|
||||||
motion.delta_timestamp = time_difference * 1000;
|
motion.delta_timestamp = time_difference;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +108,13 @@ public:
|
||||||
constexpr f32 low_width_sensitivity_limit = 400.0f;
|
constexpr f32 low_width_sensitivity_limit = 400.0f;
|
||||||
constexpr f32 high_start_sensitivity_limit = 200.0f;
|
constexpr f32 high_start_sensitivity_limit = 200.0f;
|
||||||
constexpr f32 high_width_sensitivity_limit = 700.0f;
|
constexpr f32 high_width_sensitivity_limit = 700.0f;
|
||||||
// Try to provide some feeling of the frequency by reducing the amplitude depending on it.
|
|
||||||
f32 low_frequency_scale = 1.0f;
|
f32 low_frequency_scale = 1.0f;
|
||||||
if (vibration.low_frequency > low_start_sensitivity_limit) {
|
if (vibration.low_frequency > low_start_sensitivity_limit) {
|
||||||
low_frequency_scale =
|
low_frequency_scale =
|
||||||
(std::max)(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
|
(std::max)(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
|
||||||
low_width_sensitivity_limit,
|
low_width_sensitivity_limit,
|
||||||
0.3f);
|
0.3f);
|
||||||
}
|
}
|
||||||
f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
|
f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
|
||||||
|
|
||||||
|
@ -130,31 +122,29 @@ public:
|
||||||
if (vibration.high_frequency > high_start_sensitivity_limit) {
|
if (vibration.high_frequency > high_start_sensitivity_limit) {
|
||||||
high_frequency_scale =
|
high_frequency_scale =
|
||||||
(std::max)(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
|
(std::max)(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
|
||||||
high_width_sensitivity_limit,
|
high_width_sensitivity_limit,
|
||||||
0.3f);
|
0.3f);
|
||||||
}
|
}
|
||||||
f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
|
f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
|
||||||
|
|
||||||
if (sdl_controller) {
|
if (sdl_gamepad) {
|
||||||
return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
|
return SDL_RumbleGamepad(sdl_gamepad.get(), static_cast<u16>(low_amplitude),
|
||||||
static_cast<u16>(high_amplitude),
|
static_cast<u16>(high_amplitude), rumble_max_duration_ms);
|
||||||
rumble_max_duration_ms) != -1;
|
|
||||||
} else if (sdl_joystick) {
|
} else if (sdl_joystick) {
|
||||||
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
return SDL_RumbleJoystick(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
||||||
static_cast<u16>(high_amplitude),
|
static_cast<u16>(high_amplitude), rumble_max_duration_ms);
|
||||||
rumble_max_duration_ms) != -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasHDRumble() const {
|
bool HasHDRumble() const {
|
||||||
if (sdl_controller) {
|
if (sdl_gamepad) {
|
||||||
const auto type = SDL_GameControllerGetType(sdl_controller.get());
|
const auto type = SDL_GetGamepadType(sdl_gamepad.get());
|
||||||
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
|
return (type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO) ||
|
||||||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
|
(type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
|
||||||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
|
(type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
|
||||||
(type == SDL_CONTROLLER_TYPE_PS5);
|
(type == SDL_GAMEPAD_TYPE_PS5);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -172,9 +162,6 @@ public:
|
||||||
return is_vibration_tested;
|
return is_vibration_tested;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Pad identifier of the joystick
|
|
||||||
*/
|
|
||||||
const PadIdentifier GetPadIdentifier() const {
|
const PadIdentifier GetPadIdentifier() const {
|
||||||
return {
|
return {
|
||||||
.guid = guid,
|
.guid = guid,
|
||||||
|
@ -183,16 +170,10 @@ public:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The guid of the joystick
|
|
||||||
*/
|
|
||||||
const Common::UUID& GetGUID() const {
|
const Common::UUID& GetGUID() const {
|
||||||
return guid;
|
return guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of joystick from the same type that were connected before this joystick
|
|
||||||
*/
|
|
||||||
int GetPort() const {
|
int GetPort() const {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
@ -201,13 +182,13 @@ public:
|
||||||
return sdl_joystick.get();
|
return sdl_joystick.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GameController* GetSDLGameController() const {
|
SDL_Gamepad* GetSDLGamepad() const {
|
||||||
return sdl_controller.get();
|
return sdl_gamepad.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
|
void SetSDLJoystick(SDL_Joystick* joystick, SDL_Gamepad* gamepad) {
|
||||||
sdl_joystick.reset(joystick);
|
sdl_joystick.reset(joystick);
|
||||||
sdl_controller.reset(controller);
|
sdl_gamepad.reset(gamepad);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsJoyconLeft() const {
|
bool IsJoyconLeft() const {
|
||||||
|
@ -232,49 +213,48 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) {
|
Common::Input::BatteryLevel GetBatteryLevel(SDL_PowerState battery_level) {
|
||||||
switch (battery_level) {
|
switch (battery_level) {
|
||||||
case SDL_JOYSTICK_POWER_EMPTY:
|
case SDL_POWERSTATE_ERROR:
|
||||||
return Common::Input::BatteryLevel::Empty;
|
case SDL_POWERSTATE_UNKNOWN:
|
||||||
case SDL_JOYSTICK_POWER_LOW:
|
return Common::Input::BatteryLevel::None;
|
||||||
|
case SDL_POWERSTATE_ON_BATTERY:
|
||||||
return Common::Input::BatteryLevel::Low;
|
return Common::Input::BatteryLevel::Low;
|
||||||
case SDL_JOYSTICK_POWER_MEDIUM:
|
case SDL_POWERSTATE_NO_BATTERY:
|
||||||
return Common::Input::BatteryLevel::Medium;
|
return Common::Input::BatteryLevel::None;
|
||||||
case SDL_JOYSTICK_POWER_FULL:
|
case SDL_POWERSTATE_CHARGING:
|
||||||
case SDL_JOYSTICK_POWER_MAX:
|
|
||||||
return Common::Input::BatteryLevel::Full;
|
|
||||||
case SDL_JOYSTICK_POWER_WIRED:
|
|
||||||
return Common::Input::BatteryLevel::Charging;
|
return Common::Input::BatteryLevel::Charging;
|
||||||
case SDL_JOYSTICK_POWER_UNKNOWN:
|
case SDL_POWERSTATE_CHARGED:
|
||||||
|
return Common::Input::BatteryLevel::Full;
|
||||||
default:
|
default:
|
||||||
return Common::Input::BatteryLevel::None;
|
return Common::Input::BatteryLevel::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetControllerName() const {
|
std::string GetControllerName() const {
|
||||||
if (sdl_controller) {
|
if (sdl_gamepad) {
|
||||||
switch (SDL_GameControllerGetType(sdl_controller.get())) {
|
switch (SDL_GetGamepadType(sdl_gamepad.get())) {
|
||||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
case SDL_GAMEPAD_TYPE_XBOX360:
|
||||||
return "Xbox 360 Controller";
|
return "Xbox 360 Controller";
|
||||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||||
return "Xbox One Controller";
|
return "Xbox One Controller";
|
||||||
case SDL_CONTROLLER_TYPE_PS3:
|
case SDL_GAMEPAD_TYPE_PS3:
|
||||||
return "DualShock 3 Controller";
|
return "DualShock 3 Controller";
|
||||||
case SDL_CONTROLLER_TYPE_PS4:
|
case SDL_GAMEPAD_TYPE_PS4:
|
||||||
return "DualShock 4 Controller";
|
return "DualShock 4 Controller";
|
||||||
case SDL_CONTROLLER_TYPE_PS5:
|
case SDL_GAMEPAD_TYPE_PS5:
|
||||||
return "DualSense Controller";
|
return "DualSense Controller";
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const auto name = SDL_GameControllerName(sdl_controller.get());
|
const auto name = SDL_GetGamepadName(sdl_gamepad.get());
|
||||||
if (name) {
|
if (name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdl_joystick) {
|
if (sdl_joystick) {
|
||||||
const auto name = SDL_JoystickName(sdl_joystick.get());
|
const auto name = SDL_GetJoystickName(sdl_joystick.get());
|
||||||
if (name) {
|
if (name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -286,8 +266,8 @@ public:
|
||||||
private:
|
private:
|
||||||
Common::UUID guid;
|
Common::UUID guid;
|
||||||
int port;
|
int port;
|
||||||
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
|
std::unique_ptr<SDL_Joystick, decltype(&SDL_CloseJoystick)> sdl_joystick;
|
||||||
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
|
std::unique_ptr<SDL_Gamepad, decltype(&SDL_CloseGamepad)> sdl_gamepad;
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
|
|
||||||
u64 last_motion_update{};
|
u64 last_motion_update{};
|
||||||
|
@ -323,7 +303,7 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickByGUID(const std::string&
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
|
std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
|
||||||
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
|
auto sdl_joystick = SDL_GetJoystickFromID(sdl_id);
|
||||||
const auto guid = GetGUID(sdl_joystick);
|
const auto guid = GetGUID(sdl_joystick);
|
||||||
|
|
||||||
std::scoped_lock lock{joystick_map_mutex};
|
std::scoped_lock lock{joystick_map_mutex};
|
||||||
|
@ -345,16 +325,16 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl
|
||||||
return *vec_it;
|
return *vec_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLDriver::InitJoystick(int joystick_index) {
|
void SDLDriver::InitJoystick(SDL_JoystickID joystick_id) {
|
||||||
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
|
SDL_Joystick* sdl_joystick = SDL_OpenJoystick(joystick_id);
|
||||||
SDL_GameController* sdl_gamecontroller = nullptr;
|
SDL_Gamepad* sdl_gamepad = nullptr;
|
||||||
|
|
||||||
if (SDL_IsGameController(joystick_index)) {
|
if (SDL_IsGamepad(joystick_id)) {
|
||||||
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
|
sdl_gamepad = SDL_OpenGamepad(joystick_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdl_joystick) {
|
if (!sdl_joystick) {
|
||||||
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
|
LOG_ERROR(Input, "Failed to open joystick {}", joystick_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,23 +343,23 @@ void SDLDriver::InitJoystick(int joystick_index) {
|
||||||
if (Settings::values.enable_joycon_driver) {
|
if (Settings::values.enable_joycon_driver) {
|
||||||
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e &&
|
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e &&
|
||||||
(guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) {
|
(guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) {
|
||||||
LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
|
LOG_WARNING(Input, "Preferring joycon driver for device ID {}", joystick_id);
|
||||||
SDL_JoystickClose(sdl_joystick);
|
SDL_CloseJoystick(sdl_joystick);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::values.enable_procon_driver) {
|
if (Settings::values.enable_procon_driver) {
|
||||||
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) {
|
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) {
|
||||||
LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
|
LOG_WARNING(Input, "Preferring joycon driver for device ID {}", joystick_id);
|
||||||
SDL_JoystickClose(sdl_joystick);
|
SDL_CloseJoystick(sdl_joystick);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock{joystick_map_mutex};
|
std::scoped_lock lock{joystick_map_mutex};
|
||||||
if (joystick_map.find(guid) == joystick_map.end()) {
|
if (joystick_map.find(guid) == joystick_map.end()) {
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamepad);
|
||||||
PreSetController(joystick->GetPadIdentifier());
|
PreSetController(joystick->GetPadIdentifier());
|
||||||
joystick->EnableMotion();
|
joystick->EnableMotion();
|
||||||
joystick_map[guid].emplace_back(std::move(joystick));
|
joystick_map[guid].emplace_back(std::move(joystick));
|
||||||
|
@ -392,13 +372,13 @@ void SDLDriver::InitJoystick(int joystick_index) {
|
||||||
[](const auto& joystick) { return !joystick->GetSDLJoystick(); });
|
[](const auto& joystick) { return !joystick->GetSDLJoystick(); });
|
||||||
|
|
||||||
if (joystick_it != joystick_guid_list.end()) {
|
if (joystick_it != joystick_guid_list.end()) {
|
||||||
(*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
|
(*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamepad);
|
||||||
(*joystick_it)->EnableMotion();
|
(*joystick_it)->EnableMotion();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int port = static_cast<int>(joystick_guid_list.size());
|
const int port = static_cast<int>(joystick_guid_list.size());
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
|
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamepad);
|
||||||
PreSetController(joystick->GetPadIdentifier());
|
PreSetController(joystick->GetPadIdentifier());
|
||||||
joystick->EnableMotion();
|
joystick->EnableMotion();
|
||||||
joystick_guid_list.emplace_back(std::move(joystick));
|
joystick_guid_list.emplace_back(std::move(joystick));
|
||||||
|
@ -408,7 +388,6 @@ void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
|
||||||
const auto guid = GetGUID(sdl_joystick);
|
const auto guid = GetGUID(sdl_joystick);
|
||||||
|
|
||||||
std::scoped_lock lock{joystick_map_mutex};
|
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_guid_list = joystick_map[guid];
|
||||||
const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
|
const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
|
||||||
[&sdl_joystick](const auto& joystick) {
|
[&sdl_joystick](const auto& joystick) {
|
||||||
|
@ -428,56 +407,85 @@ void SDLDriver::PumpEvents() const {
|
||||||
|
|
||||||
void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
|
void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_JOYBUTTONUP: {
|
case SDL_EVENT_GAMEPAD_BUTTON_UP: {
|
||||||
|
if (const auto joystick = GetSDLJoystickBySDLID(event.gbutton.which)) {
|
||||||
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
|
SetButton(identifier, event.gbutton.button, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: {
|
||||||
|
if (const auto joystick = GetSDLJoystickBySDLID(event.gbutton.which)) {
|
||||||
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
|
SetButton(identifier, event.gbutton.button, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION: {
|
||||||
|
if (const auto joystick = GetSDLJoystickBySDLID(event.gaxis.which)) {
|
||||||
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
|
SetAxis(identifier, event.gaxis.axis, event.gaxis.value / 32767.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_EVENT_JOYSTICK_BUTTON_UP: {
|
||||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetButton(identifier, event.jbutton.button, false);
|
SetButton(identifier, event.jbutton.button, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYBUTTONDOWN: {
|
case SDL_EVENT_JOYSTICK_BUTTON_DOWN: {
|
||||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetButton(identifier, event.jbutton.button, true);
|
SetButton(identifier, event.jbutton.button, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYHATMOTION: {
|
case SDL_EVENT_JOYSTICK_HAT_MOTION: {
|
||||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
|
if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetHatButton(identifier, event.jhat.hat, event.jhat.value);
|
SetHatButton(identifier, event.jhat.hat, event.jhat.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYAXISMOTION: {
|
case SDL_EVENT_JOYSTICK_AXIS_MOTION: {
|
||||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
|
if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f);
|
SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_CONTROLLERSENSORUPDATE: {
|
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: {
|
||||||
if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
|
if (auto joystick = GetSDLJoystickBySDLID(event.gsensor.which)) {
|
||||||
if (joystick->UpdateMotion(event.csensor)) {
|
if (joystick->UpdateMotion(event.gsensor)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetMotion(identifier, 0, joystick->GetMotion());
|
SetMotion(identifier, 0, joystick->GetMotion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYBATTERYUPDATED: {
|
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED: {
|
||||||
if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
|
if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
|
||||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||||
SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level));
|
SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.state));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYDEVICEREMOVED:
|
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||||
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
|
LOG_DEBUG(Input, "Gamepad removed with Instance_ID {}", event.gdevice.which);
|
||||||
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
|
CloseJoystick(SDL_GetJoystickFromID(event.gdevice.which));
|
||||||
break;
|
break;
|
||||||
case SDL_JOYDEVICEADDED:
|
case SDL_EVENT_GAMEPAD_ADDED:
|
||||||
LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
|
LOG_DEBUG(Input, "Gamepad connected with device ID {}", event.gdevice.which);
|
||||||
|
InitJoystick(event.gdevice.which);
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_JOYSTICK_REMOVED:
|
||||||
|
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
|
||||||
|
CloseJoystick(SDL_GetJoystickFromID(event.jdevice.which));
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_JOYSTICK_ADDED:
|
||||||
|
LOG_DEBUG(Input, "Controller connected with device ID {}", event.jdevice.which);
|
||||||
InitJoystick(event.jdevice.which);
|
InitJoystick(event.jdevice.which);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -489,24 +497,17 @@ void SDLDriver::CloseJoysticks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||||
// Set our application name. Currently passed to DBus by SDL and visible to the user through
|
|
||||||
// their desktop environment.
|
|
||||||
SDL_SetHint(SDL_HINT_APP_NAME, "Eden");
|
SDL_SetHint(SDL_HINT_APP_NAME, "Eden");
|
||||||
|
|
||||||
if (!Settings::values.enable_raw_input) {
|
if (!Settings::values.enable_raw_input) {
|
||||||
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent SDL from adding undesired axis
|
// SDL_HINT_ACCELEROMETER_AS_JOYSTICK was removed in SDL3
|
||||||
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
|
// SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE and SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE were removed in
|
||||||
|
// SDL3 These are now handled by SDL_HINT_JOYSTICK_ENHANCED_REPORTS
|
||||||
// Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||||
|
|
||||||
// Disable hidapi drivers for joycon controllers when the custom joycon driver is enabled
|
|
||||||
if (Settings::values.enable_joycon_driver) {
|
if (Settings::values.enable_joycon_driver) {
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
|
||||||
} else {
|
} else {
|
||||||
|
@ -516,7 +517,6 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1");
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
|
|
||||||
if (Settings::values.enable_procon_driver) {
|
if (Settings::values.enable_procon_driver) {
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
|
||||||
} else {
|
} else {
|
||||||
|
@ -525,16 +525,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
|
||||||
// Share the same button mapping with non-Nintendo controllers
|
// SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS was removed in SDL3
|
||||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
|
|
||||||
|
|
||||||
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
|
|
||||||
// driver on Linux.
|
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
|
||||||
|
|
||||||
// If the frontend is going to manage the event loop, then we don't start one here
|
start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);
|
||||||
start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0;
|
if (start_thread && !SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) {
|
||||||
if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
|
|
||||||
LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError());
|
LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -552,21 +547,25 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Because the events for joystick connection happens before we have our event watcher added, we
|
|
||||||
// can just open all the joysticks right here
|
int num_joysticks;
|
||||||
for (int i = 0; i < SDL_NumJoysticks(); ++i) {
|
SDL_JoystickID* joysticks = SDL_GetJoysticks(&num_joysticks);
|
||||||
InitJoystick(i);
|
if (joysticks) {
|
||||||
|
for (int i = 0; i < num_joysticks; ++i) {
|
||||||
|
InitJoystick(joysticks[i]);
|
||||||
|
}
|
||||||
|
SDL_free(joysticks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLDriver::~SDLDriver() {
|
SDLDriver::~SDLDriver() {
|
||||||
CloseJoysticks();
|
CloseJoysticks();
|
||||||
SDL_DelEventWatch(&SDLEventWatcher, this);
|
SDL_RemoveEventWatch(&SDLEventWatcher, this);
|
||||||
|
|
||||||
initialized = false;
|
initialized = false;
|
||||||
if (start_thread) {
|
if (start_thread) {
|
||||||
vibration_thread.join();
|
vibration_thread.join();
|
||||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,7 +591,6 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add dual controllers
|
|
||||||
for (const auto& [key, value] : joystick_map) {
|
for (const auto& [key, value] : joystick_map) {
|
||||||
for (const auto& joystick : value) {
|
for (const auto& joystick : value) {
|
||||||
if (joystick->IsJoyconRight()) {
|
if (joystick->IsJoyconRight()) {
|
||||||
|
@ -624,15 +622,12 @@ Common::Input::DriverResult SDLDriver::SetVibration(
|
||||||
return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF;
|
return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default exponential curve for rumble
|
|
||||||
f32 factor = 0.35f;
|
f32 factor = 0.35f;
|
||||||
|
|
||||||
// If vibration is set as a linear output use a flatter value
|
|
||||||
if (vibration.type == Common::Input::VibrationAmplificationType::Linear) {
|
if (vibration.type == Common::Input::VibrationAmplificationType::Linear) {
|
||||||
factor = 0.5f;
|
factor = 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amplitude for HD rumble needs no modification
|
|
||||||
if (joystick->HasHDRumble()) {
|
if (joystick->HasHDRumble()) {
|
||||||
factor = 1.0f;
|
factor = 1.0f;
|
||||||
}
|
}
|
||||||
|
@ -677,10 +672,7 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
|
||||||
return joystick->HasVibration();
|
return joystick->HasVibration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// First vibration might fail
|
|
||||||
joystick->RumblePlay(test_vibration);
|
joystick->RumblePlay(test_vibration);
|
||||||
|
|
||||||
// Wait for about 15ms to ensure the controller is ready for the stop command
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(15));
|
std::this_thread::sleep_for(std::chrono::milliseconds(15));
|
||||||
|
|
||||||
if (!joystick->RumblePlay(zero_vibration)) {
|
if (!joystick->RumblePlay(zero_vibration)) {
|
||||||
|
@ -760,17 +752,17 @@ Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& g
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
|
Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
|
||||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
|
int port, const Common::UUID& guid, const SDL_GamepadBinding& binding) const {
|
||||||
switch (binding.bindType) {
|
switch (binding.input_type) {
|
||||||
case SDL_CONTROLLER_BINDTYPE_NONE:
|
case SDL_GAMEPAD_BINDTYPE_NONE:
|
||||||
break;
|
break;
|
||||||
case SDL_CONTROLLER_BINDTYPE_AXIS:
|
case SDL_GAMEPAD_BINDTYPE_AXIS:
|
||||||
return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
|
return BuildAnalogParamPackageForButton(port, guid, binding.input.axis.axis);
|
||||||
case SDL_CONTROLLER_BINDTYPE_BUTTON:
|
case SDL_GAMEPAD_BINDTYPE_BUTTON:
|
||||||
return BuildButtonParamPackageForButton(port, guid, binding.value.button);
|
return BuildButtonParamPackageForButton(port, guid, binding.input.button);
|
||||||
case SDL_CONTROLLER_BINDTYPE_HAT:
|
case SDL_GAMEPAD_BINDTYPE_HAT:
|
||||||
return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
|
return BuildHatParamPackageForButton(port, guid, binding.input.hat.hat,
|
||||||
static_cast<u8>(binding.value.hat.hat_mask));
|
static_cast<u8>(binding.input.hat.hat_mask));
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -797,28 +789,23 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||||
}
|
}
|
||||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||||
|
|
||||||
auto* controller = joystick->GetSDLGameController();
|
auto* gamepad = joystick->GetSDLGamepad();
|
||||||
if (controller == nullptr) {
|
if (gamepad == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
|
|
||||||
// We will add those afterwards
|
|
||||||
ButtonBindings switch_to_sdl_button;
|
ButtonBindings switch_to_sdl_button;
|
||||||
|
|
||||||
switch_to_sdl_button = GetDefaultButtonBinding(joystick);
|
switch_to_sdl_button = GetDefaultButtonBinding(joystick);
|
||||||
|
|
||||||
// Add the missing bindings for ZL/ZR
|
|
||||||
static constexpr ZButtonBindings switch_to_sdl_axis{{
|
static constexpr ZButtonBindings switch_to_sdl_axis{{
|
||||||
{Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
|
{Settings::NativeButton::ZL, SDL_GAMEPAD_AXIS_LEFT_TRIGGER},
|
||||||
{Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
|
{Settings::NativeButton::ZR, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Parameters contain two joysticks return dual
|
|
||||||
if (params.Has("guid2")) {
|
if (params.Has("guid2")) {
|
||||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||||
|
|
||||||
if (joystick2->GetSDLGameController() != nullptr) {
|
if (joystick2->GetSDLGamepad() != nullptr) {
|
||||||
return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
|
return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button,
|
||||||
switch_to_sdl_axis);
|
switch_to_sdl_axis);
|
||||||
}
|
}
|
||||||
|
@ -829,42 +816,41 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
|
||||||
|
|
||||||
ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
||||||
const std::shared_ptr<SDLJoystick>& joystick) const {
|
const std::shared_ptr<SDLJoystick>& joystick) const {
|
||||||
// Default SL/SR mapping for other controllers
|
auto sll_button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
|
||||||
auto sll_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
auto srl_button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
|
||||||
auto srl_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
auto slr_button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
|
||||||
auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
auto srr_button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
|
||||||
auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
|
||||||
|
|
||||||
if (joystick->IsJoyconLeft()) {
|
if (joystick->IsJoyconLeft()) {
|
||||||
sll_button = SDL_CONTROLLER_BUTTON_PADDLE2;
|
sll_button = SDL_GAMEPAD_BUTTON_LEFT_PADDLE1;
|
||||||
srl_button = SDL_CONTROLLER_BUTTON_PADDLE4;
|
srl_button = SDL_GAMEPAD_BUTTON_LEFT_PADDLE2;
|
||||||
}
|
}
|
||||||
if (joystick->IsJoyconRight()) {
|
if (joystick->IsJoyconRight()) {
|
||||||
slr_button = SDL_CONTROLLER_BUTTON_PADDLE3;
|
slr_button = SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2;
|
||||||
srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
srr_button = SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
|
std::pair{Settings::NativeButton::A, SDL_GAMEPAD_BUTTON_EAST},
|
||||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
|
{Settings::NativeButton::B, SDL_GAMEPAD_BUTTON_SOUTH},
|
||||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
|
{Settings::NativeButton::X, SDL_GAMEPAD_BUTTON_NORTH},
|
||||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
|
{Settings::NativeButton::Y, SDL_GAMEPAD_BUTTON_WEST},
|
||||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
{Settings::NativeButton::LStick, SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
{Settings::NativeButton::RStick, SDL_GAMEPAD_BUTTON_RIGHT_STICK},
|
||||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
{Settings::NativeButton::L, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
||||||
{Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
{Settings::NativeButton::R, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
||||||
{Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
|
{Settings::NativeButton::Plus, SDL_GAMEPAD_BUTTON_START},
|
||||||
{Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
|
{Settings::NativeButton::Minus, SDL_GAMEPAD_BUTTON_BACK},
|
||||||
{Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
|
{Settings::NativeButton::DLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||||
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
|
{Settings::NativeButton::DUp, SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||||
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
{Settings::NativeButton::DRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||||
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
{Settings::NativeButton::DDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||||
{Settings::NativeButton::SLLeft, sll_button},
|
{Settings::NativeButton::SLLeft, sll_button},
|
||||||
{Settings::NativeButton::SRLeft, srl_button},
|
{Settings::NativeButton::SRLeft, srl_button},
|
||||||
{Settings::NativeButton::SLRight, slr_button},
|
{Settings::NativeButton::SLRight, slr_button},
|
||||||
{Settings::NativeButton::SRRight, srr_button},
|
{Settings::NativeButton::SRRight, srr_button},
|
||||||
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
|
{Settings::NativeButton::Home, SDL_GAMEPAD_BUTTON_GUIDE},
|
||||||
{Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
|
{Settings::NativeButton::Screenshot, SDL_GAMEPAD_BUTTON_MISC1},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,16 +859,25 @@ ButtonMapping SDLDriver::GetSingleControllerMapping(
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
const ZButtonBindings& switch_to_sdl_axis) const {
|
||||||
ButtonMapping mapping;
|
ButtonMapping mapping;
|
||||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||||
auto* controller = joystick->GetSDLGameController();
|
|
||||||
|
|
||||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||||
const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
|
// SDL_GetGamepadBindForButton was removed in SDL3
|
||||||
|
// We need to use SDL_GetGamepadStringForButton or work with joystick directly
|
||||||
|
// For now, create a dummy binding
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_BUTTON;
|
||||||
|
binding.input.button = sdl_button;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
}
|
}
|
||||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||||
const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
|
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||||
|
// We need to use SDL_GetGamepadStringForAxis or work with joystick directly
|
||||||
|
// For now, create a dummy binding
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding.input.axis.axis = sdl_axis;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
|
@ -897,31 +892,41 @@ ButtonMapping SDLDriver::GetDualControllerMapping(const std::shared_ptr<SDLJoyst
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
const ZButtonBindings& switch_to_sdl_axis) const {
|
||||||
ButtonMapping mapping;
|
ButtonMapping mapping;
|
||||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||||
auto* controller = joystick->GetSDLGameController();
|
|
||||||
auto* controller2 = joystick2->GetSDLGameController();
|
|
||||||
|
|
||||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||||
if (IsButtonOnLeftSide(switch_button)) {
|
if (IsButtonOnLeftSide(switch_button)) {
|
||||||
const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button);
|
// SDL_GetGamepadBindForButton was removed in SDL3
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_BUTTON;
|
||||||
|
binding.input.button = sdl_button;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
|
// SDL_GetGamepadBindForButton was removed in SDL3
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_BUTTON;
|
||||||
|
binding.input.button = sdl_button;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
}
|
}
|
||||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||||
if (IsButtonOnLeftSide(switch_button)) {
|
if (IsButtonOnLeftSide(switch_button)) {
|
||||||
const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis);
|
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding.input.axis.axis = sdl_axis;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
|
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||||
|
SDL_GamepadBinding binding{};
|
||||||
|
binding.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding.input.axis.axis = sdl_axis;
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(
|
||||||
switch_button,
|
switch_button,
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
|
@ -953,53 +958,70 @@ AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& p
|
||||||
}
|
}
|
||||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||||
auto* controller = joystick->GetSDLGameController();
|
auto* gamepad = joystick->GetSDLGamepad();
|
||||||
if (controller == nullptr) {
|
if (gamepad == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalogMapping mapping = {};
|
AnalogMapping mapping = {};
|
||||||
const auto& binding_left_x =
|
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
// We need to work with the underlying joystick directly
|
||||||
const auto& binding_left_y =
|
SDL_Joystick* sdl_joystick = SDL_GetGamepadJoystick(gamepad);
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
if (!sdl_joystick) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, use hardcoded axis mappings
|
||||||
|
SDL_GamepadBinding binding_left_x{};
|
||||||
|
binding_left_x.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding_left_x.input.axis.axis = 0; // Left stick X
|
||||||
|
|
||||||
|
SDL_GamepadBinding binding_left_y{};
|
||||||
|
binding_left_y.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding_left_y.input.axis.axis = 1; // Left stick Y
|
||||||
|
|
||||||
if (params.Has("guid2")) {
|
if (params.Has("guid2")) {
|
||||||
const auto identifier = joystick2->GetPadIdentifier();
|
const auto identifier = joystick2->GetPadIdentifier();
|
||||||
PreSetController(identifier);
|
PreSetController(identifier);
|
||||||
PreSetAxis(identifier, binding_left_x.value.axis);
|
PreSetAxis(identifier, binding_left_x.input.axis.axis);
|
||||||
PreSetAxis(identifier, binding_left_y.value.axis);
|
PreSetAxis(identifier, binding_left_y.input.axis.axis);
|
||||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
|
const auto left_offset_x = -GetAxis(identifier, binding_left_x.input.axis.axis);
|
||||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
|
const auto left_offset_y = GetAxis(identifier, binding_left_y.input.axis.axis);
|
||||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
BuildParamPackageForAnalog(
|
||||||
binding_left_y.value.axis,
|
identifier, binding_left_x.input.axis.axis,
|
||||||
left_offset_x, left_offset_y));
|
binding_left_y.input.axis.axis, left_offset_x, left_offset_y));
|
||||||
} else {
|
} else {
|
||||||
const auto identifier = joystick->GetPadIdentifier();
|
const auto identifier = joystick->GetPadIdentifier();
|
||||||
PreSetController(identifier);
|
PreSetController(identifier);
|
||||||
PreSetAxis(identifier, binding_left_x.value.axis);
|
PreSetAxis(identifier, binding_left_x.input.axis.axis);
|
||||||
PreSetAxis(identifier, binding_left_y.value.axis);
|
PreSetAxis(identifier, binding_left_y.input.axis.axis);
|
||||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
|
const auto left_offset_x = -GetAxis(identifier, binding_left_x.input.axis.axis);
|
||||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
|
const auto left_offset_y = GetAxis(identifier, binding_left_y.input.axis.axis);
|
||||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
BuildParamPackageForAnalog(
|
||||||
binding_left_y.value.axis,
|
identifier, binding_left_x.input.axis.axis,
|
||||||
left_offset_x, left_offset_y));
|
binding_left_y.input.axis.axis, left_offset_x, left_offset_y));
|
||||||
}
|
}
|
||||||
const auto& binding_right_x =
|
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
// For right stick
|
||||||
const auto& binding_right_y =
|
SDL_GamepadBinding binding_right_x{};
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
binding_right_x.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding_right_x.input.axis.axis = 2; // Right stick X
|
||||||
|
|
||||||
|
SDL_GamepadBinding binding_right_y{};
|
||||||
|
binding_right_y.input_type = SDL_GAMEPAD_BINDTYPE_AXIS;
|
||||||
|
binding_right_y.input.axis.axis = 3; // Right stick Y
|
||||||
const auto identifier = joystick->GetPadIdentifier();
|
const auto identifier = joystick->GetPadIdentifier();
|
||||||
PreSetController(identifier);
|
PreSetController(identifier);
|
||||||
PreSetAxis(identifier, binding_right_x.value.axis);
|
PreSetAxis(identifier, binding_right_x.input.axis.axis);
|
||||||
PreSetAxis(identifier, binding_right_y.value.axis);
|
PreSetAxis(identifier, binding_right_y.input.axis.axis);
|
||||||
const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis);
|
const auto right_offset_x = -GetAxis(identifier, binding_right_x.input.axis.axis);
|
||||||
const auto right_offset_y = GetAxis(identifier, binding_right_y.value.axis);
|
const auto right_offset_y = GetAxis(identifier, binding_right_y.input.axis.axis);
|
||||||
mapping.insert_or_assign(Settings::NativeAnalog::RStick,
|
mapping.insert_or_assign(Settings::NativeAnalog::RStick,
|
||||||
BuildParamPackageForAnalog(identifier, binding_right_x.value.axis,
|
BuildParamPackageForAnalog(identifier, binding_right_x.input.axis.axis,
|
||||||
binding_right_y.value.axis, right_offset_x,
|
binding_right_y.input.axis.axis,
|
||||||
right_offset_y));
|
right_offset_x, right_offset_y));
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1009,8 +1031,8 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p
|
||||||
}
|
}
|
||||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||||
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||||
auto* controller = joystick->GetSDLGameController();
|
auto* gamepad = joystick->GetSDLGamepad();
|
||||||
if (controller == nullptr) {
|
if (gamepad == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,7 +1061,6 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p
|
||||||
|
|
||||||
Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const {
|
Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const {
|
||||||
if (params.Has("button")) {
|
if (params.Has("button")) {
|
||||||
// TODO(German77): Find how to substitute the values for real button names
|
|
||||||
return Common::Input::ButtonNames::Value;
|
return Common::Input::ButtonNames::Value;
|
||||||
}
|
}
|
||||||
if (params.Has("hat")) {
|
if (params.Has("hat")) {
|
||||||
|
@ -1097,29 +1118,27 @@ bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
|
||||||
if (joystick == nullptr) {
|
if (joystick == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto* controller = joystick->GetSDLGameController();
|
auto* gamepad = joystick->GetSDLGamepad();
|
||||||
if (controller == nullptr) {
|
if (gamepad == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& axis_x = params.Get("axis_x", 0);
|
const auto& axis_x = params.Get("axis_x", 0);
|
||||||
const auto& axis_y = params.Get("axis_y", 0);
|
const auto& axis_y = params.Get("axis_y", 0);
|
||||||
const auto& binding_left_x =
|
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
// Use hardcoded axis mappings for now
|
||||||
const auto& binding_right_x =
|
const int binding_left_x = 0; // Left stick X
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
const int binding_right_x = 2; // Right stick X
|
||||||
const auto& binding_left_y =
|
const int binding_left_y = 1; // Left stick Y
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
const int binding_right_y = 3; // Right stick Y
|
||||||
const auto& binding_right_y =
|
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
|
||||||
|
|
||||||
if (axis_x != binding_left_y.value.axis && axis_x != binding_right_y.value.axis) {
|
if (axis_x != binding_left_y && axis_x != binding_right_y) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (axis_y != binding_left_x.value.axis && axis_y != binding_right_x.value.axis) {
|
if (axis_y != binding_left_x && axis_y != binding_right_x) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: 2018 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2018 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -8,46 +10,33 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/threadsafe_queue.h"
|
#include "common/threadsafe_queue.h"
|
||||||
#include "input_common/input_engine.h"
|
#include "input_common/input_engine.h"
|
||||||
|
|
||||||
union SDL_Event;
|
union SDL_Event;
|
||||||
using SDL_GameController = struct _SDL_GameController;
|
using SDL_Gamepad = struct SDL_Gamepad;
|
||||||
using SDL_Joystick = struct _SDL_Joystick;
|
using SDL_Joystick = struct SDL_Joystick;
|
||||||
using SDL_JoystickID = s32;
|
using SDL_JoystickID = Uint32;
|
||||||
|
|
||||||
namespace InputCommon {
|
namespace InputCommon {
|
||||||
|
|
||||||
class SDLJoystick;
|
class SDLJoystick;
|
||||||
|
|
||||||
using ButtonBindings =
|
using ButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadButton>, 20>;
|
||||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
|
using ZButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadAxis>, 2>;
|
||||||
using ZButtonBindings =
|
|
||||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
|
||||||
|
|
||||||
class SDLDriver : public InputEngine {
|
class SDLDriver : public InputEngine {
|
||||||
public:
|
public:
|
||||||
/// Initializes and registers SDL device factories
|
|
||||||
explicit SDLDriver(std::string input_engine_);
|
explicit SDLDriver(std::string input_engine_);
|
||||||
|
|
||||||
/// Unregisters SDL device factories and shut them down.
|
|
||||||
~SDLDriver() override;
|
~SDLDriver() override;
|
||||||
|
|
||||||
void PumpEvents() const;
|
void PumpEvents() const;
|
||||||
|
|
||||||
/// Handle SDL_Events for joysticks from SDL_PollEvent
|
|
||||||
void HandleGameControllerEvent(const SDL_Event& event);
|
void HandleGameControllerEvent(const SDL_Event& event);
|
||||||
|
|
||||||
/// Get the nth joystick with the corresponding GUID
|
|
||||||
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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> GetSDLJoystickByGUID(const Common::UUID& guid, int port);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const Common::UUID& guid, int port);
|
||||||
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
|
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
|
||||||
|
|
||||||
|
@ -69,59 +58,40 @@ public:
|
||||||
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
|
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitJoystick(int joystick_index);
|
void InitJoystick(SDL_JoystickID joystick_id);
|
||||||
void CloseJoystick(SDL_Joystick* sdl_joystick);
|
void CloseJoystick(SDL_Joystick* sdl_joystick);
|
||||||
|
|
||||||
/// Needs to be called before SDL_QuitSubSystem.
|
|
||||||
void CloseJoysticks();
|
void CloseJoysticks();
|
||||||
|
|
||||||
/// Takes all vibrations from the queue and sends the command to the controller
|
|
||||||
void SendVibrations();
|
void SendVibrations();
|
||||||
|
|
||||||
Common::ParamPackage BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
|
Common::ParamPackage BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
|
||||||
s32 axis, float value = 0.1f) const;
|
s32 axis, float value = 0.1f) const;
|
||||||
Common::ParamPackage BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
|
Common::ParamPackage BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
|
||||||
s32 button) const;
|
s32 button) const;
|
||||||
|
|
||||||
Common::ParamPackage BuildHatParamPackageForButton(int port, const Common::UUID& guid, s32 hat,
|
Common::ParamPackage BuildHatParamPackageForButton(int port, const Common::UUID& guid, s32 hat,
|
||||||
u8 value) const;
|
u8 value) const;
|
||||||
|
|
||||||
Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
|
Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
|
||||||
|
Common::ParamPackage BuildParamPackageForBinding(int port, const Common::UUID& guid,
|
||||||
Common::ParamPackage BuildParamPackageForBinding(
|
const SDL_GamepadBinding& binding) const;
|
||||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const;
|
|
||||||
|
|
||||||
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
||||||
int axis_y, float offset_x,
|
int axis_y, float offset_x,
|
||||||
float offset_y) const;
|
float offset_y) const;
|
||||||
|
|
||||||
/// Returns the default button bindings list
|
|
||||||
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
ButtonBindings GetDefaultButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;
|
||||||
|
|
||||||
/// Returns the button mappings from a single controller
|
|
||||||
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||||
const ButtonBindings& switch_to_sdl_button,
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
|
||||||
/// Returns the button mappings from two different controllers
|
|
||||||
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||||
const std::shared_ptr<SDLJoystick>& joystick2,
|
const std::shared_ptr<SDLJoystick>& joystick2,
|
||||||
const ButtonBindings& switch_to_sdl_button,
|
const ButtonBindings& switch_to_sdl_button,
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||||
|
|
||||||
/// Returns true if the button is on the left joycon
|
|
||||||
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
||||||
|
|
||||||
/// Queue of vibration request to controllers
|
|
||||||
Common::SPSCQueue<VibrationRequest> vibration_queue;
|
Common::SPSCQueue<VibrationRequest> vibration_queue;
|
||||||
|
|
||||||
/// Map of GUID of a list of corresponding virtual Joysticks
|
|
||||||
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
|
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
|
||||||
std::mutex joystick_map_mutex;
|
std::mutex joystick_map_mutex;
|
||||||
|
|
||||||
bool start_thread = false;
|
bool start_thread = false;
|
||||||
std::atomic<bool> initialized = false;
|
std::atomic<bool> initialized = false;
|
||||||
|
|
||||||
std::thread vibration_thread;
|
std::thread vibration_thread;
|
||||||
};
|
};
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -10,7 +12,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <SDL_hidapi.h>
|
#include <SDL3/SDL_hidapi.h>
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@
|
||||||
#ifdef HAVE_LIBUSB
|
#ifdef HAVE_LIBUSB
|
||||||
#include "input_common/drivers/gc_adapter.h"
|
#include "input_common/drivers/gc_adapter.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include "input_common/drivers/joycon.h"
|
#include "input_common/drivers/joycon.h"
|
||||||
#include "input_common/drivers/sdl_driver.h"
|
#include "input_common/drivers/sdl_driver.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,7 +89,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
||||||
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
RegisterEngine("sdl", sdl);
|
RegisterEngine("sdl", sdl);
|
||||||
RegisterEngine("joycon", joycon);
|
RegisterEngine("joycon", joycon);
|
||||||
#endif
|
#endif
|
||||||
|
@ -121,7 +123,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
UnregisterEngine(virtual_amiibo);
|
UnregisterEngine(virtual_amiibo);
|
||||||
UnregisterEngine(virtual_gamepad);
|
UnregisterEngine(virtual_gamepad);
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
UnregisterEngine(sdl);
|
UnregisterEngine(sdl);
|
||||||
UnregisterEngine(joycon);
|
UnregisterEngine(joycon);
|
||||||
#endif
|
#endif
|
||||||
|
@ -151,7 +153,7 @@ struct InputSubsystem::Impl {
|
||||||
#endif
|
#endif
|
||||||
auto udp_devices = udp_client->GetInputDevices();
|
auto udp_devices = udp_client->GetInputDevices();
|
||||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
auto joycon_devices = joycon->GetInputDevices();
|
auto joycon_devices = joycon->GetInputDevices();
|
||||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||||
auto sdl_devices = sdl->GetInputDevices();
|
auto sdl_devices = sdl->GetInputDevices();
|
||||||
|
@ -186,7 +188,7 @@ struct InputSubsystem::Impl {
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return udp_client;
|
return udp_client;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return sdl;
|
return sdl;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +279,7 @@ struct InputSubsystem::Impl {
|
||||||
if (engine == virtual_gamepad->GetEngineName()) {
|
if (engine == virtual_gamepad->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +300,7 @@ struct InputSubsystem::Impl {
|
||||||
gcadapter->BeginConfiguration();
|
gcadapter->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->BeginConfiguration();
|
udp_client->BeginConfiguration();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->BeginConfiguration();
|
sdl->BeginConfiguration();
|
||||||
joycon->BeginConfiguration();
|
joycon->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
@ -314,7 +316,7 @@ struct InputSubsystem::Impl {
|
||||||
gcadapter->EndConfiguration();
|
gcadapter->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
udp_client->EndConfiguration();
|
udp_client->EndConfiguration();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->EndConfiguration();
|
sdl->EndConfiguration();
|
||||||
joycon->EndConfiguration();
|
joycon->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
@ -322,7 +324,7 @@ struct InputSubsystem::Impl {
|
||||||
|
|
||||||
void PumpEvents() const {
|
void PumpEvents() const {
|
||||||
update_engine->PumpEvents();
|
update_engine->PumpEvents();
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
sdl->PumpEvents();
|
sdl->PumpEvents();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -347,7 +349,7 @@ struct InputSubsystem::Impl {
|
||||||
std::shared_ptr<GCAdapter> gcadapter;
|
std::shared_ptr<GCAdapter> gcadapter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
std::shared_ptr<SDLDriver> sdl;
|
std::shared_ptr<SDLDriver> sdl;
|
||||||
std::shared_ptr<Joycons> joycon;
|
std::shared_ptr<Joycons> joycon;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -466,9 +466,9 @@ if (YUZU_USE_BUNDLED_QT)
|
||||||
copy_yuzu_Qt6_deps(yuzu)
|
copy_yuzu_Qt6_deps(yuzu)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_SDL2)
|
if (ENABLE_SDL3)
|
||||||
target_link_libraries(yuzu PRIVATE SDL2::SDL2)
|
target_link_libraries(yuzu PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(yuzu PRIVATE HAVE_SDL2)
|
target_compile_definitions(yuzu PRIVATE HAVE_SDL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
|
@ -98,8 +98,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QStringLiteral>
|
#include <QStringLiteral>
|
||||||
|
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL3
|
||||||
#include <SDL.h> // For SDL ScreenSaver functions
|
#include <SDL3/SDL.h> // For SDL ScreenSaver functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
@ -588,7 +588,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||||
VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
|
VkDeviceInfo::PopulateRecords(vk_device_records, this->window()->windowHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_SDL2) && !defined(_WIN32)
|
#if defined(HAVE_SDL3) && !defined(_WIN32)
|
||||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
// Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to
|
// Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to
|
||||||
|
@ -1868,7 +1868,7 @@ void GMainWindow::OnSigInterruptNotifierActivated() {
|
||||||
void GMainWindow::PreventOSSleep() {
|
void GMainWindow::PreventOSSleep() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
|
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
|
||||||
#elif defined(HAVE_SDL2)
|
#elif defined(HAVE_SDL3)
|
||||||
SDL_DisableScreenSaver();
|
SDL_DisableScreenSaver();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1876,7 +1876,7 @@ void GMainWindow::PreventOSSleep() {
|
||||||
void GMainWindow::AllowOSSleep() {
|
void GMainWindow::AllowOSSleep() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetThreadExecutionState(ES_CONTINUOUS);
|
SetThreadExecutionState(ES_CONTINUOUS);
|
||||||
#elif defined(HAVE_SDL2)
|
#elif defined(HAVE_SDL3)
|
||||||
SDL_EnableScreenSaver();
|
SDL_EnableScreenSaver();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,14 @@ function(create_resource file output filename)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_executable(yuzu-cmd
|
add_executable(yuzu-cmd
|
||||||
emu_window/emu_window_sdl2.cpp
|
emu_window/emu_window_sdl3.cpp
|
||||||
emu_window/emu_window_sdl2.h
|
emu_window/emu_window_sdl3.h
|
||||||
emu_window/emu_window_sdl2_gl.cpp
|
emu_window/emu_window_sdl3_gl.cpp
|
||||||
emu_window/emu_window_sdl2_gl.h
|
emu_window/emu_window_sdl3_gl.h
|
||||||
emu_window/emu_window_sdl2_null.cpp
|
emu_window/emu_window_sdl3_null.cpp
|
||||||
emu_window/emu_window_sdl2_null.h
|
emu_window/emu_window_sdl3_null.h
|
||||||
emu_window/emu_window_sdl2_vk.cpp
|
emu_window/emu_window_sdl3_vk.cpp
|
||||||
emu_window/emu_window_sdl2_vk.h
|
emu_window/emu_window_sdl3_vk.h
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
sdl_config.cpp
|
sdl_config.cpp
|
||||||
sdl_config.h
|
sdl_config.h
|
||||||
|
@ -41,7 +41,7 @@ target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||||
create_resource("../../dist/yuzu.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon")
|
create_resource("../../dist/yuzu.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon")
|
||||||
target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR})
|
target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR})
|
||||||
|
|
||||||
target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2)
|
target_link_libraries(yuzu-cmd PRIVATE SDL3::SDL3)
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
install(TARGETS yuzu-cmd)
|
install(TARGETS yuzu-cmd)
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fmt/ranges.h>
|
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "common/scm_rev.h"
|
|
||||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
|
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <SDL_syswm.h>
|
|
||||||
|
|
||||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_,
|
|
||||||
Core::System& system_, bool fullscreen)
|
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
|
||||||
const std::string window_title = fmt::format("Eden {} | {}-{} (Vulkan)",
|
|
||||||
Common::g_build_name,
|
|
||||||
Common::g_scm_branch,
|
|
||||||
Common::g_scm_desc);
|
|
||||||
render_window =
|
|
||||||
SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
|
||||||
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: {}",
|
|
||||||
SDL_GetError());
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetWindowIcon();
|
|
||||||
|
|
||||||
if (fullscreen) {
|
|
||||||
Fullscreen();
|
|
||||||
ShowCursor(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (wm.subsystem) {
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
|
||||||
window_info.type = Core::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 = Core::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 = Core::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 = Core::Frontend::WindowSystemType::Cocoa;
|
|
||||||
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
|
||||||
window_info.type = Core::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnResize();
|
|
||||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
|
||||||
SDL_PumpEvents();
|
|
||||||
LOG_INFO(Frontend, "Eden Version: {} | {}-{} (Vulkan)", Common::g_build_name,
|
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default;
|
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
|
|
||||||
return std::make_unique<DummyContext>();
|
|
||||||
}
|
|
|
@ -3,8 +3,10 @@
|
||||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
#include "SDL3/SDL_video.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
@ -15,26 +17,26 @@
|
||||||
#include "input_common/drivers/mouse.h"
|
#include "input_common/drivers/mouse.h"
|
||||||
#include "input_common/drivers/touch_screen.h"
|
#include "input_common/drivers/touch_screen.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||||
#include "yuzu_cmd/yuzu_icon.h"
|
#include "yuzu_cmd/yuzu_icon.h"
|
||||||
|
|
||||||
EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
|
EmuWindow_SDL3::EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
|
||||||
: input_subsystem{input_subsystem_}, system{system_} {
|
: input_subsystem{input_subsystem_}, system{system_} {
|
||||||
input_subsystem->Initialize();
|
input_subsystem->Initialize();
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
SDL_SetMainReady();
|
SDL_SetMainReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2::~EmuWindow_SDL2() {
|
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
||||||
system.HIDCore().UnloadInputDevices();
|
system.HIDCore().UnloadInputDevices();
|
||||||
input_subsystem->Shutdown();
|
input_subsystem->Shutdown();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
|
InputCommon::MouseButton EmuWindow_SDL3::SDLButtonToMouseButton(u32 button) const {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
case SDL_BUTTON_LEFT:
|
case SDL_BUTTON_LEFT:
|
||||||
return InputCommon::MouseButton::Left;
|
return InputCommon::MouseButton::Left;
|
||||||
|
@ -52,21 +54,17 @@ InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) cons
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Translates pixel position to float position
|
/// @brief Translates pixel position to float position
|
||||||
EmuWindow_SDL2::FloatPairNonHFA EmuWindow_SDL2::MouseToTouchPos(s32 touch_x, s32 touch_y) const {
|
EmuWindow_SDL3::FloatPairNonHFA EmuWindow_SDL3::MouseToTouchPos(s32 touch_x, s32 touch_y) const {
|
||||||
int w = 0, h = 0;
|
int w = 0, h = 0;
|
||||||
SDL_GetWindowSize(render_window, &w, &h);
|
SDL_GetWindowSize(render_window, &w, &h);
|
||||||
const float fx = float(touch_x) / w;
|
const float fx = float(touch_x) / w;
|
||||||
const float fy = float(touch_y) / h;
|
const float fy = float(touch_y) / h;
|
||||||
return {
|
return {std::clamp<float>(fx, 0.0f, 1.0f), std::clamp<float>(fy, 0.0f, 1.0f), 0};
|
||||||
std::clamp<float>(fx, 0.0f, 1.0f),
|
|
||||||
std::clamp<float>(fy, 0.0f, 1.0f),
|
|
||||||
0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
void EmuWindow_SDL3::OnMouseButton(u32 button, bool pressed, s32 x, s32 y) {
|
||||||
const auto mouse_button = SDLButtonToMouseButton(button);
|
const auto mouse_button = SDLButtonToMouseButton(button);
|
||||||
if (state == SDL_PRESSED) {
|
if (pressed) {
|
||||||
auto const [touch_x, touch_y, _] = MouseToTouchPos(x, y);
|
auto const [touch_x, touch_y, _] = MouseToTouchPos(x, y);
|
||||||
input_subsystem->GetMouse()->PressButton(x, y, mouse_button);
|
input_subsystem->GetMouse()->PressButton(x, y, mouse_button);
|
||||||
input_subsystem->GetMouse()->PressMouseButton(mouse_button);
|
input_subsystem->GetMouse()->PressMouseButton(mouse_button);
|
||||||
|
@ -76,64 +74,65 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
|
void EmuWindow_SDL3::OnMouseMotion(s32 x, s32 y) {
|
||||||
auto const [touch_x, touch_y, _] = MouseToTouchPos(x, y);
|
auto const [touch_x, touch_y, _] = MouseToTouchPos(x, y);
|
||||||
input_subsystem->GetMouse()->Move(x, y, 0, 0);
|
input_subsystem->GetMouse()->Move(x, y, 0, 0);
|
||||||
input_subsystem->GetMouse()->MouseMove(touch_x, touch_y);
|
input_subsystem->GetMouse()->MouseMove(touch_x, touch_y);
|
||||||
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
|
void EmuWindow_SDL3::OnFingerDown(float x, float y, std::size_t id) {
|
||||||
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
|
void EmuWindow_SDL3::OnFingerMotion(float x, float y, std::size_t id) {
|
||||||
input_subsystem->GetTouchScreen()->TouchMoved(x, y, id);
|
input_subsystem->GetTouchScreen()->TouchMoved(x, y, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerUp() {
|
void EmuWindow_SDL3::OnFingerUp() {
|
||||||
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
|
input_subsystem->GetTouchScreen()->ReleaseAllTouch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
|
void EmuWindow_SDL3::OnKeyEvent(int key, bool pressed) {
|
||||||
if (state == SDL_PRESSED) {
|
if (pressed) {
|
||||||
input_subsystem->GetKeyboard()->PressKey(static_cast<std::size_t>(key));
|
input_subsystem->GetKeyboard()->PressKey(static_cast<std::size_t>(key));
|
||||||
} else if (state == SDL_RELEASED) {
|
} else {
|
||||||
input_subsystem->GetKeyboard()->ReleaseKey(static_cast<std::size_t>(key));
|
input_subsystem->GetKeyboard()->ReleaseKey(static_cast<std::size_t>(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_SDL2::IsOpen() const {
|
bool EmuWindow_SDL3::IsOpen() const {
|
||||||
return is_open;
|
return is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_SDL2::IsShown() const {
|
bool EmuWindow_SDL3::IsShown() const {
|
||||||
return is_shown;
|
return is_shown;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnResize() {
|
void EmuWindow_SDL3::OnResize() {
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GL_GetDrawableSize(render_window, &width, &height);
|
SDL_GetWindowSizeInPixels(render_window, &width, &height);
|
||||||
UpdateCurrentFramebufferLayout(width, height);
|
UpdateCurrentFramebufferLayout(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::ShowCursor(bool show_cursor) {
|
void EmuWindow_SDL3::ShowCursor(bool show_cursor) {
|
||||||
SDL_ShowCursor(show_cursor ? SDL_ENABLE : SDL_DISABLE);
|
show_cursor ? SDL_ShowCursor() : SDL_HideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::Fullscreen() {
|
void EmuWindow_SDL3::Fullscreen() {
|
||||||
SDL_DisplayMode display_mode;
|
const SDL_DisplayMode* display_mode;
|
||||||
switch (Settings::values.fullscreen_mode.GetValue()) {
|
switch (Settings::values.fullscreen_mode.GetValue()) {
|
||||||
case Settings::FullscreenMode::Exclusive:
|
case Settings::FullscreenMode::Exclusive:
|
||||||
// Set window size to render size before entering fullscreen -- SDL2 does not resize window
|
// Set window size to render size before entering fullscreen -- SDL3 does not resize window
|
||||||
// to display dimensions automatically in this mode.
|
// to display dimensions automatically in this mode.
|
||||||
if (SDL_GetDesktopDisplayMode(0, &display_mode) == 0) {
|
display_mode = SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window));
|
||||||
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
if (display_mode) {
|
||||||
|
SDL_SetWindowSize(render_window, display_mode->w, display_mode->h);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Frontend, "SDL_GetDesktopDisplayMode failed: {}", SDL_GetError());
|
LOG_ERROR(Frontend, "SDL_GetDesktopDisplayMode failed: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
|
if (!SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,12 +140,13 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||||
LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
|
LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case Settings::FullscreenMode::Borderless:
|
case Settings::FullscreenMode::Borderless:
|
||||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
|
SDL_SetWindowFullscreenMode(render_window, NULL);
|
||||||
|
if (!SDL_SetWindowFullscreen(render_window, true)) {
|
||||||
|
LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError());
|
||||||
|
[[fallthrough]];
|
||||||
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError());
|
|
||||||
[[fallthrough]];
|
|
||||||
default:
|
default:
|
||||||
// Fallback algorithm: Maximise window.
|
// Fallback algorithm: Maximise window.
|
||||||
// Works on all systems (unless something is seriously wrong), so no fallback for this one.
|
// Works on all systems (unless something is seriously wrong), so no fallback for this one.
|
||||||
|
@ -156,11 +156,13 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::WaitEvent() {
|
void EmuWindow_SDL3::WaitEvent() {
|
||||||
// Called on main thread
|
// Called on main thread
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
|
||||||
if (!SDL_WaitEvent(&event)) {
|
if (SDL_WaitEvent(&event)) {
|
||||||
|
// Event received successfully
|
||||||
|
} else {
|
||||||
const char* error = SDL_GetError();
|
const char* error = SDL_GetError();
|
||||||
if (!error || strcmp(error, "") == 0) {
|
if (!error || strcmp(error, "") == 0) {
|
||||||
// https://github.com/libsdl-org/SDL/issues/5780
|
// https://github.com/libsdl-org/SDL/issues/5780
|
||||||
|
@ -174,52 +176,49 @@ void EmuWindow_SDL2::WaitEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
switch (event.window.event) {
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
OnResize();
|
||||||
case SDL_WINDOWEVENT_RESTORED:
|
|
||||||
OnResize();
|
|
||||||
break;
|
|
||||||
case SDL_WINDOWEVENT_MINIMIZED:
|
|
||||||
case SDL_WINDOWEVENT_EXPOSED:
|
|
||||||
is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED;
|
|
||||||
OnResize();
|
|
||||||
break;
|
|
||||||
case SDL_WINDOWEVENT_CLOSE:
|
|
||||||
is_open = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SDL_KEYDOWN:
|
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||||
case SDL_KEYUP:
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
|
is_shown = event.type == SDL_EVENT_WINDOW_EXPOSED;
|
||||||
|
OnResize();
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
|
is_open = false;
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
case SDL_EVENT_KEY_UP:
|
||||||
|
OnKeyEvent(static_cast<int>(event.key.scancode), event.type == SDL_EVENT_KEY_DOWN);
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID)
|
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||||
OnMouseMotion(event.motion.x, event.motion.y);
|
OnMouseMotion(event.motion.x, event.motion.y);
|
||||||
break;
|
break;
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_MOUSEBUTTONUP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
||||||
OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y);
|
OnMouseButton(event.button.button, event.type == SDL_EVENT_MOUSE_BUTTON_DOWN,
|
||||||
|
event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERDOWN:
|
case SDL_EVENT_FINGER_DOWN:
|
||||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
||||||
static_cast<std::size_t>(event.tfinger.touchId));
|
static_cast<std::size_t>(event.tfinger.touchID));
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERMOTION:
|
case SDL_EVENT_FINGER_MOTION:
|
||||||
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
||||||
static_cast<std::size_t>(event.tfinger.touchId));
|
static_cast<std::size_t>(event.tfinger.touchID));
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERUP:
|
case SDL_EVENT_FINGER_UP:
|
||||||
OnFingerUp();
|
OnFingerUp();
|
||||||
break;
|
break;
|
||||||
case SDL_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -229,34 +228,31 @@ void EmuWindow_SDL2::WaitEvent() {
|
||||||
const u32 current_time = SDL_GetTicks();
|
const u32 current_time = SDL_GetTicks();
|
||||||
if (current_time > last_time + 2000) {
|
if (current_time > last_time + 2000) {
|
||||||
const auto results = system.GetAndResetPerfStats();
|
const auto results = system.GetAndResetPerfStats();
|
||||||
const auto title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)",
|
const auto title = fmt::format(
|
||||||
Common::g_build_fullname,
|
"{} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, Common::g_scm_branch,
|
||||||
Common::g_scm_branch,
|
Common::g_scm_desc, results.average_game_fps, results.emulation_speed * 100.0);
|
||||||
Common::g_scm_desc,
|
|
||||||
results.average_game_fps,
|
|
||||||
results.emulation_speed * 100.0);
|
|
||||||
SDL_SetWindowTitle(render_window, title.c_str());
|
SDL_SetWindowTitle(render_window, title.c_str());
|
||||||
last_time = current_time;
|
last_time = current_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credits to Samantas5855 and others for this function.
|
// Credits to Samantas5855 and others for this function.
|
||||||
void EmuWindow_SDL2::SetWindowIcon() {
|
void EmuWindow_SDL3::SetWindowIcon() {
|
||||||
SDL_RWops* const yuzu_icon_stream = SDL_RWFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
||||||
if (yuzu_icon_stream == nullptr) {
|
if (yuzu_icon_stream == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_Surface* const window_icon = SDL_LoadBMP_RW(yuzu_icon_stream, 1);
|
SDL_Surface* const window_icon = SDL_LoadBMP_IO(yuzu_icon_stream, 1);
|
||||||
if (window_icon == nullptr) {
|
if (window_icon == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to read BMP from stream.");
|
LOG_WARNING(Frontend, "Failed to read BMP from stream.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The icon is attached to the window pointer
|
// The icon is attached to the window pointer
|
||||||
SDL_SetWindowIcon(render_window, window_icon);
|
SDL_SetWindowIcon(render_window, window_icon);
|
||||||
SDL_FreeSurface(window_icon);
|
SDL_DestroySurface(window_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||||
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
|
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
|
||||||
}
|
}
|
|
@ -22,10 +22,10 @@ class InputSubsystem;
|
||||||
enum class MouseButton;
|
enum class MouseButton;
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
||||||
|
|
||||||
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
class EmuWindow_SDL3 : public Core::Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_);
|
explicit EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_);
|
||||||
~EmuWindow_SDL2();
|
~EmuWindow_SDL3();
|
||||||
|
|
||||||
/// Whether the window is still open, and a close request hasn't yet been sent
|
/// Whether the window is still open, and a close request hasn't yet been sent
|
||||||
bool IsOpen() const;
|
bool IsOpen() const;
|
||||||
|
@ -41,7 +41,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Called by WaitEvent when a key is pressed or released.
|
/// Called by WaitEvent when a key is pressed or released.
|
||||||
void OnKeyEvent(int key, u8 state);
|
void OnKeyEvent(int key, bool pressed);
|
||||||
|
|
||||||
/// Converts a SDL mouse button into MouseInput mouse button
|
/// Converts a SDL mouse button into MouseInput mouse button
|
||||||
InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const;
|
InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const;
|
||||||
|
@ -53,7 +53,7 @@ protected:
|
||||||
FloatPairNonHFA MouseToTouchPos(s32 touch_x, s32 touch_y) const;
|
FloatPairNonHFA MouseToTouchPos(s32 touch_x, s32 touch_y) const;
|
||||||
|
|
||||||
/// Called by WaitEvent when a mouse button is pressed or released
|
/// Called by WaitEvent when a mouse button is pressed or released
|
||||||
void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
|
void OnMouseButton(u32 button, bool pressed, s32 x, s32 y);
|
||||||
|
|
||||||
/// Called by WaitEvent when the mouse moves.
|
/// Called by WaitEvent when the mouse moves.
|
||||||
void OnMouseMotion(s32 x, s32 y);
|
void OnMouseMotion(s32 x, s32 y);
|
||||||
|
@ -85,7 +85,7 @@ protected:
|
||||||
/// Is the window being shown?
|
/// Is the window being shown?
|
||||||
bool is_shown = true;
|
bool is_shown = true;
|
||||||
|
|
||||||
/// Internal SDL2 render window
|
/// Internal SDL3 render window
|
||||||
SDL_Window* render_window{};
|
SDL_Window* render_window{};
|
||||||
|
|
||||||
/// Keeps track of how often to update the title bar during gameplay
|
/// Keeps track of how often to update the title bar during gameplay
|
|
@ -4,23 +4,21 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/string_util.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_gl.h"
|
||||||
|
|
||||||
class SDLGLContext : public Core::Frontend::GraphicsContext {
|
class SDLGLContext : public Core::Frontend::GraphicsContext {
|
||||||
public:
|
public:
|
||||||
|
@ -30,7 +28,7 @@ public:
|
||||||
|
|
||||||
~SDLGLContext() {
|
~SDLGLContext() {
|
||||||
DoneCurrent();
|
DoneCurrent();
|
||||||
SDL_GL_DeleteContext(context);
|
SDL_GL_DestroyContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapBuffers() override {
|
void SwapBuffers() override {
|
||||||
|
@ -58,7 +56,7 @@ private:
|
||||||
bool is_current = false;
|
bool is_current = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
|
bool EmuWindow_SDL3_GL::SupportsRequiredGLExtensions() {
|
||||||
std::vector<std::string_view> unsupported_ext;
|
std::vector<std::string_view> unsupported_ext;
|
||||||
|
|
||||||
// Extensions required to support some texture formats.
|
// Extensions required to support some texture formats.
|
||||||
|
@ -76,9 +74,9 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
|
||||||
return unsupported_ext.empty();
|
return unsupported_ext.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_,
|
EmuWindow_SDL3_GL::EmuWindow_SDL3_GL(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system_, bool fullscreen)
|
Core::System& system_, bool fullscreen)
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||||
|
@ -95,15 +93,12 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
|
|
||||||
std::string window_title = fmt::format("{} | {}-{}", Common::g_build_fullname,
|
std::string window_title = fmt::format("{} | {}-{}", Common::g_build_fullname,
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
render_window =
|
render_window = SDL_CreateWindow(
|
||||||
SDL_CreateWindow(window_title.c_str(),
|
window_title.c_str(), Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
||||||
SDL_WINDOWPOS_UNDEFINED, // x position
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||||
SDL_WINDOWPOS_UNDEFINED, // y position
|
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
|
||||||
|
|
||||||
if (render_window == nullptr) {
|
if (render_window == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create SDL3 window! {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,15 +115,17 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
core_context = CreateSharedContext();
|
core_context = CreateSharedContext();
|
||||||
|
|
||||||
if (window_context == nullptr) {
|
if (window_context == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context: {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create SDL3 GL context: {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (core_context == nullptr) {
|
if (core_context == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to create shared SDL2 GL context: {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to create shared SDL3 GL context: {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
if (!gladLoadGLLoader([](const char* name) -> void* {
|
||||||
|
return reinterpret_cast<void*>(SDL_GL_GetProcAddress(name));
|
||||||
|
})) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -146,11 +143,11 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
|
||||||
Settings::LogSettings();
|
Settings::LogSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
|
EmuWindow_SDL3_GL::~EmuWindow_SDL3_GL() {
|
||||||
core_context.reset();
|
core_context.reset();
|
||||||
SDL_GL_DeleteContext(window_context);
|
SDL_GL_DestroyContext(window_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_GL::CreateSharedContext() const {
|
||||||
return std::make_unique<SDLGLContext>(render_window);
|
return std::make_unique<SDLGLContext>(render_window);
|
||||||
}
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -15,11 +18,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_GL final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_,
|
explicit EmuWindow_SDL3_GL(InputCommon::InputSubsystem* input_subsystem_, Core::System& system_,
|
||||||
bool fullscreen);
|
bool fullscreen);
|
||||||
~EmuWindow_SDL2_GL();
|
~EmuWindow_SDL3_GL();
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
||||||
|
@ -27,8 +30,6 @@ private:
|
||||||
/// Whether the GPU and driver supports the OpenGL extension required
|
/// Whether the GPU and driver supports the OpenGL extension required
|
||||||
bool SupportsRequiredGLExtensions();
|
bool SupportsRequiredGLExtensions();
|
||||||
|
|
||||||
using SDL_GLContext = void*;
|
|
||||||
|
|
||||||
/// The OpenGL context associated with the window
|
/// The OpenGL context associated with the window
|
||||||
SDL_GLContext window_context;
|
SDL_GLContext window_context;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -10,25 +12,24 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
#include "video_core/renderer_null/renderer_null.h"
|
#include "video_core/renderer_null/renderer_null.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_null.h"
|
||||||
|
|
||||||
#ifdef YUZU_USE_EXTERNAL_SDL2
|
#ifdef YUZU_USE_EXTERNAL_SDL3
|
||||||
// Include this before SDL.h to prevent the external from including a dummy
|
// Include this before SDL.h to prevent the external from including a dummy
|
||||||
#define USING_GENERATED_CONFIG_H
|
#define USING_GENERATED_CONFIG_H
|
||||||
#include <SDL_config.h>
|
#include <SDL3/SDL_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_,
|
EmuWindow_SDL3_Null::EmuWindow_SDL3_Null(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system_, bool fullscreen)
|
Core::System& system_, bool fullscreen)
|
||||||
: EmuWindow_SDL2{input_subsystem_, system_} {
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
const std::string window_title = fmt::format("Eden {} | {}-{} (Vulkan)", Common::g_build_name,
|
const std::string window_title = fmt::format("Eden {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
render_window =
|
render_window = SDL_CreateWindow(window_title.c_str(), Layout::ScreenUndocked::Width,
|
||||||
SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
Layout::ScreenUndocked::Height,
|
||||||
Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
|
SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
|
||||||
|
|
||||||
SetWindowIcon();
|
SetWindowIcon();
|
||||||
|
|
||||||
|
@ -44,8 +45,8 @@ EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subs
|
||||||
Common::g_scm_branch, Common::g_scm_desc);
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL2_Null::~EmuWindow_SDL2_Null() = default;
|
EmuWindow_SDL3_Null::~EmuWindow_SDL3_Null() = default;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Null::CreateSharedContext() const {
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_Null::CreateSharedContext() const {
|
||||||
return std::make_unique<DummyContext>();
|
return std::make_unique<DummyContext>();
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -16,11 +18,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_Null final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_Null final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_,
|
explicit EmuWindow_SDL3_Null(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
Core::System& system, bool fullscreen);
|
Core::System& system, bool fullscreen);
|
||||||
~EmuWindow_SDL2_Null() override;
|
~EmuWindow_SDL3_Null() override;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
};
|
};
|
84
src/yuzu_cmd/emu_window/emu_window_sdl3_vk.cpp
Normal file
84
src/yuzu_cmd/emu_window/emu_window_sdl3_vk.cpp
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/scm_rev.h"
|
||||||
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_vk.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
EmuWindow_SDL3_VK::EmuWindow_SDL3_VK(InputCommon::InputSubsystem* input_subsystem_,
|
||||||
|
Core::System& system_, bool fullscreen)
|
||||||
|
: EmuWindow_SDL3{input_subsystem_, system_} {
|
||||||
|
const std::string window_title = fmt::format("Eden {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||||
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
|
render_window = SDL_CreateWindow(window_title.c_str(), Layout::ScreenUndocked::Width,
|
||||||
|
Layout::ScreenUndocked::Height,
|
||||||
|
SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||||
|
|
||||||
|
SetWindowIcon();
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
Fullscreen();
|
||||||
|
ShowCursor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SDL_PropertiesID props = SDL_GetWindowProperties(render_window);
|
||||||
|
|
||||||
|
#if defined(SDL_PLATFORM_WIN32)
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
||||||
|
window_info.render_surface =
|
||||||
|
SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
||||||
|
#elif defined(SDL_PLATFORM_MACOS)
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Cocoa;
|
||||||
|
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
||||||
|
#elif defined(SDL_PLATFORM_LINUX)
|
||||||
|
const char* video_driver = SDL_GetCurrentVideoDriver();
|
||||||
|
if (video_driver && SDL_strcmp(video_driver, "x11") == 0) {
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::X11;
|
||||||
|
window_info.display_connection =
|
||||||
|
SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr);
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(
|
||||||
|
SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0));
|
||||||
|
} else if (video_driver && SDL_strcmp(video_driver, "wayland") == 0) {
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Wayland;
|
||||||
|
window_info.display_connection =
|
||||||
|
SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr);
|
||||||
|
window_info.render_surface =
|
||||||
|
SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
|
||||||
|
} else {
|
||||||
|
LOG_CRITICAL(Frontend, "Unsupported SDL video driver: {}",
|
||||||
|
video_driver ? video_driver : "(null)");
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#elif defined(SDL_PLATFORM_ANDROID)
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface =
|
||||||
|
SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr);
|
||||||
|
#else
|
||||||
|
LOG_CRITICAL(Frontend, "Unsupported platform for SDL window properties");
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
OnResize();
|
||||||
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
|
SDL_PumpEvents();
|
||||||
|
LOG_INFO(Frontend, "Eden Version: {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||||
|
Common::g_scm_branch, Common::g_scm_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmuWindow_SDL3_VK::~EmuWindow_SDL3_VK() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL3_VK::CreateSharedContext() const {
|
||||||
|
return std::make_unique<DummyContext>();
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -16,11 +18,11 @@ namespace InputCommon {
|
||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
class EmuWindow_SDL3_VK final : public EmuWindow_SDL3 {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system,
|
explicit EmuWindow_SDL3_VK(InputCommon::InputSubsystem* input_subsystem_, Core::System& system,
|
||||||
bool fullscreen);
|
bool fullscreen);
|
||||||
~EmuWindow_SDL2_VK() override;
|
~EmuWindow_SDL3_VK() override;
|
||||||
|
|
||||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||||
};
|
};
|
|
@ -1,9 +1,11 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
// SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h
|
// SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h
|
||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#include <SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
|
|
@ -34,10 +34,10 @@
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "sdl_config.h"
|
#include "sdl_config.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_gl.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_null.h"
|
||||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
|
#include "yuzu_cmd/emu_window/emu_window_sdl3_vk.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// windows.h needs to be included before shellapi.h
|
// windows.h needs to be included before shellapi.h
|
||||||
|
@ -346,16 +346,16 @@ int main(int argc, char** argv) {
|
||||||
// Apply the command line arguments
|
// Apply the command line arguments
|
||||||
system.ApplySettings();
|
system.ApplySettings();
|
||||||
|
|
||||||
std::unique_ptr<EmuWindow_SDL2> emu_window;
|
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
||||||
switch (Settings::values.renderer_backend.GetValue()) {
|
switch (Settings::values.renderer_backend.GetValue()) {
|
||||||
case Settings::RendererBackend::OpenGL:
|
case Settings::RendererBackend::OpenGL:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Vulkan:
|
case Settings::RendererBackend::Vulkan:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Null:
|
case Settings::RendererBackend::Null:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL2_Null>(&input_subsystem, system, fullscreen);
|
emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, system, fullscreen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue
change to 3.2.12+