forked from eden-emu/eden
Compare commits
36 commits
02bd53f0e6
...
6c0f4a3472
Author | SHA1 | Date | |
---|---|---|---|
6c0f4a3472 | |||
2e91844ad4 | |||
2f137b3884 | |||
92201b95a0 | |||
eb164861da | |||
73b9ac9b7d | |||
a6a0b513dc | |||
9d91f9cbed | |||
fb75c34ee8 | |||
b4a844a378 | |||
35f73386b6 | |||
a6ccd907af | |||
4175e0266f | |||
86af32a736 | |||
c5eb0e7d2e | |||
cf0628af46 | |||
dbeae7add0 | |||
62369aa2d5 | |||
badd913bee | |||
6a4fa11ac3 | |||
5d4cfe195b | |||
bc1d093fe9 | |||
f6d99e5032 | |||
a52ddf78a6 | |||
191dd892e5 | |||
9f385bf627 | |||
1a13e79c3d | |||
268918aece | |||
83730cd4c1 | |||
272df1fa83 | |||
71a87b2c55 | |||
f4f3425d86 | |||
9173eec402 | |||
de594c8792 | |||
2d8cb2d457 | |||
990a43a48c |
156 changed files with 3327 additions and 1772 deletions
|
@ -13,8 +13,8 @@ fi
|
|||
cd src/android
|
||||
chmod +x ./gradlew
|
||||
|
||||
./gradlew assembleRelease
|
||||
./gradlew bundleRelease
|
||||
./gradlew assembleMainlineRelease
|
||||
./gradlew bundleMainlineRelease
|
||||
|
||||
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
|
||||
rm "${ANDROID_KEYSTORE_FILE}"
|
||||
|
|
|
@ -97,8 +97,8 @@ cmake .. -G Ninja \
|
|||
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
||||
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||
-DYUZU_USE_BUNDLED_QT=OFF \
|
||||
-DYUZU_USE_BUNDLED_SDL2=OFF \
|
||||
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
||||
-DYUZU_USE_BUNDLED_SDL3=OFF \
|
||||
-DYUZU_USE_EXTERNAL_SDL3=ON \
|
||||
-DYUZU_TESTS=OFF \
|
||||
-DYUZU_USE_QT_MULTIMEDIA=$MULTIMEDIA \
|
||||
-DYUZU_USE_QT_WEB_ENGINE=$WEBENGINE \
|
||||
|
|
|
@ -24,7 +24,7 @@ cmake .. -G Ninja \
|
|||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE:-Release}" \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON \
|
||||
-DYUZU_USE_BUNDLED_SDL2=ON \
|
||||
-DYUZU_USE_BUNDLED_SDL3=ON \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DYUZU_TESTS=OFF \
|
||||
-DDYNARMIC_TESTS=OFF \
|
||||
|
|
1
.shellcheckrc
Normal file
1
.shellcheckrc
Normal file
|
@ -0,0 +1 @@
|
|||
shell=sh
|
220
CMakeLists.txt
220
CMakeLists.txt
|
@ -32,10 +32,20 @@ endif()
|
|||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
|
||||
# NB: this does not account for SPARC
|
||||
# If you get Eden working on SPARC, please shoot crueter@crueter.xyz multiple emails
|
||||
# and you will be hailed for eternity
|
||||
if (PLATFORM_SUN)
|
||||
# Terrific Solaris pkg shenanigans
|
||||
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
|
||||
# amazing
|
||||
# absolutely incredible
|
||||
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "/usr/lib/amd64/cmake")
|
||||
|
||||
# For some mighty reason, doing a normal release build sometimes may not trigger
|
||||
# the proper -O3 switch to materialize
|
||||
if (CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
|
@ -137,16 +147,17 @@ if (PLATFORM_FREEBSD)
|
|||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
|
||||
endif()
|
||||
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# On Linux system SDL2 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)
|
||||
# Set bundled sdl3/qt as dependent options.
|
||||
# On Linux system SDL3 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
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
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL3 "Compile external SDL3" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}")
|
||||
endif()
|
||||
|
||||
# qt stuff
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
|
@ -163,8 +174,12 @@ if (MSVC OR ANDROID)
|
|||
endif()
|
||||
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
|
||||
|
||||
# ffmpeg
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
# sirit
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT})
|
||||
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||
|
||||
|
@ -212,10 +227,12 @@ endif()
|
|||
# TODO(crueter): CI this?
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.g. Snapdragon 865) at the cost of performance" 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_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)
|
||||
|
||||
|
@ -309,10 +326,14 @@ if (UNIX)
|
|||
add_compile_definitions(YUZU_UNIX=1)
|
||||
endif()
|
||||
|
||||
if (YUZU_LEGACY)
|
||||
message(WARNING "Making legacy build. Performance may suffer.")
|
||||
add_compile_definitions(YUZU_LEGACY)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
|
||||
set(HAS_NCE 1)
|
||||
add_compile_definitions(HAS_NCE=1)
|
||||
find_package(oaknut 2.0.1)
|
||||
endif()
|
||||
|
||||
if (YUZU_ROOM)
|
||||
|
@ -450,22 +471,7 @@ if (YUZU_USE_CPM)
|
|||
|
||||
if (zstd_ADDED)
|
||||
add_library(zstd::zstd ALIAS libzstd_static)
|
||||
endif()
|
||||
|
||||
# Catch2
|
||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||
AddJsonPackage(catch2)
|
||||
endif()
|
||||
|
||||
# ENet
|
||||
AddJsonPackage(enet)
|
||||
|
||||
if (enet_ADDED)
|
||||
target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET enet::enet)
|
||||
add_library(enet::enet ALIAS enet)
|
||||
add_library(zstd::libzstd ALIAS libzstd_static)
|
||||
endif()
|
||||
|
||||
# Opus
|
||||
|
@ -482,31 +488,10 @@ if (YUZU_USE_CPM)
|
|||
if (NOT TARGET Opus::opus)
|
||||
add_library(Opus::opus ALIAS opus)
|
||||
endif()
|
||||
|
||||
# VulkanUtilityHeaders - pulls in headers and utility libs
|
||||
AddJsonPackage(vulkan-utility-headers)
|
||||
|
||||
# small hack
|
||||
if (NOT VulkanUtilityLibraries_ADDED)
|
||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
||||
endif()
|
||||
|
||||
# SPIRV Headers
|
||||
AddJsonPackage(spirv-headers)
|
||||
|
||||
# SPIRV Tools
|
||||
AddJsonPackage(spirv-tools)
|
||||
|
||||
if (SPIRV-Tools_ADDED)
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static)
|
||||
target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link)
|
||||
endif()
|
||||
|
||||
# mbedtls
|
||||
AddJsonPackage(mbedtls)
|
||||
else()
|
||||
# Enforce the search mode of non-required packages for better and shorter failure messages
|
||||
find_package(fmt 8 REQUIRED)
|
||||
|
||||
if (NOT YUZU_DISABLE_LLVM)
|
||||
find_package(LLVM MODULE COMPONENTS Demangle)
|
||||
endif()
|
||||
|
@ -515,39 +500,16 @@ else()
|
|||
find_package(lz4 REQUIRED)
|
||||
find_package(RenderDoc MODULE)
|
||||
find_package(stb MODULE)
|
||||
find_package(enet 1.3 MODULE REQUIRED)
|
||||
|
||||
find_package(Opus 1.3 MODULE REQUIRED)
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED MODULE)
|
||||
|
||||
# wow
|
||||
if (PLATFORM_LINUX)
|
||||
find_package(Boost 1.57.0 REQUIRED headers context system fiber)
|
||||
find_package(Boost 1.57.0 CONFIG REQUIRED headers context system fiber)
|
||||
else()
|
||||
find_package(Boost 1.57.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
# OpenBSD does not package mbedtls3 (only 2)
|
||||
if (PLATFORM_OPENBSD)
|
||||
AddJsonPackage(mbedtls)
|
||||
else()
|
||||
find_package(MbedTLS 3 REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(VulkanUtilityLibraries REQUIRED)
|
||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
||||
|
||||
# FreeBSD does not package spirv-headers
|
||||
if (PLATFORM_FREEBSD)
|
||||
AddJsonPackage(spirv-headers)
|
||||
else()
|
||||
find_package(SPIRV-Headers 1.3.274 REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(SPIRV-Tools MODULE REQUIRED)
|
||||
|
||||
if (YUZU_TESTS)
|
||||
find_package(Catch2 3.0.1 REQUIRED)
|
||||
find_package(Boost 1.57.0 CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
|
||||
|
@ -563,90 +525,6 @@ if(NOT TARGET Boost::headers)
|
|||
AddJsonPackage(boost_headers)
|
||||
endif()
|
||||
|
||||
# DiscordRPC
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
if (ARCHITECTURE_arm64)
|
||||
add_compile_definitions(RAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(discord-rpc)
|
||||
|
||||
target_include_directories(discord-rpc INTERFACE ${discord-rpc_SOURCE_DIR}/include)
|
||||
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
|
||||
endif()
|
||||
|
||||
# SimpleIni
|
||||
AddJsonPackage(simpleini)
|
||||
|
||||
# Most linux distros don't package cubeb, so enable regardless of cpm settings
|
||||
if(ENABLE_CUBEB)
|
||||
AddJsonPackage(cubeb)
|
||||
|
||||
if (cubeb_ADDED)
|
||||
if (NOT MSVC)
|
||||
if (TARGET speex)
|
||||
target_compile_options(speex PRIVATE -Wno-sign-compare)
|
||||
endif()
|
||||
|
||||
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
|
||||
target_compile_options(cubeb INTERFACE
|
||||
-Wno-implicit-const-int-float-conversion
|
||||
-Wno-shadow
|
||||
-Wno-missing-declarations
|
||||
-Wno-return-type
|
||||
-Wno-uninitialized
|
||||
)
|
||||
else()
|
||||
target_compile_options(cubeb PRIVATE
|
||||
/wd4456
|
||||
/wd4458
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT TARGET cubeb::cubeb)
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
if (NOT WIN32)
|
||||
# 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)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(SDL_FILE ON)
|
||||
endif()
|
||||
|
||||
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
|
||||
set(SDL_PIPEWIRE OFF) # build errors out with this on
|
||||
AddJsonPackage("sdl2_steamdeck")
|
||||
else()
|
||||
AddJsonPackage("sdl2_generic")
|
||||
endif()
|
||||
elseif (YUZU_USE_BUNDLED_SDL2)
|
||||
message(STATUS "Using bundled SDL2")
|
||||
AddJsonPackage(sdl2)
|
||||
endif()
|
||||
|
||||
find_package(SDL2 2.26.4 REQUIRED)
|
||||
endif()
|
||||
|
||||
# List of all FFmpeg components required
|
||||
set(FFmpeg_COMPONENTS
|
||||
avcodec
|
||||
|
@ -677,6 +555,12 @@ add_subdirectory(externals)
|
|||
# pass targets from externals
|
||||
find_package(libusb)
|
||||
find_package(VulkanMemoryAllocator)
|
||||
find_package(enet)
|
||||
find_package(MbedTLS)
|
||||
find_package(VulkanUtilityLibraries)
|
||||
find_package(SimpleIni)
|
||||
find_package(SPIRV-Tools)
|
||||
find_package(sirit)
|
||||
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
find_package(xbyak)
|
||||
|
@ -690,6 +574,26 @@ if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
|
|||
find_package(cpp-jwt)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS)
|
||||
find_package(oaknut)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
find_package(SDL2)
|
||||
endif()
|
||||
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
find_package(DiscordRPC)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
find_package(cubeb)
|
||||
endif()
|
||||
|
||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||
find_package(Catch2)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
download_qt(6.8.3)
|
||||
|
@ -708,6 +612,8 @@ if (ENABLE_QT)
|
|||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# yes Qt, we get it
|
||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||
find_package(Qt6 REQUIRED COMPONENTS DBus OPTIONAL_COMPONENTS GuiPrivate)
|
||||
elseif (UNIX AND NOT APPLE)
|
||||
find_package(Qt6 REQUIRED COMPONENTS DBus Gui)
|
||||
|
|
|
@ -743,9 +743,11 @@ function(CPMAddPackage)
|
|||
if(NOT DEFINED CPM_ARGS_NAME)
|
||||
set(CPM_ARGS_NAME ${nameFromUrl})
|
||||
endif()
|
||||
if(NOT DEFINED CPM_ARGS_VERSION)
|
||||
set(CPM_ARGS_VERSION ${verFromUrl})
|
||||
endif()
|
||||
|
||||
# this is dumb and should not be done
|
||||
# if(NOT DEFINED CPM_ARGS_VERSION)
|
||||
# set(CPM_ARGS_VERSION ${verFromUrl})
|
||||
# endif()
|
||||
|
||||
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
|
||||
endif()
|
||||
|
|
|
@ -107,7 +107,6 @@ function(AddJsonPackage)
|
|||
get_json_element("${object}" name name "${JSON_NAME}")
|
||||
get_json_element("${object}" extension extension "tar.zst")
|
||||
get_json_element("${object}" min_version min_version "")
|
||||
get_json_element("${object}" cmake_filename cmake_filename "")
|
||||
get_json_element("${object}" raw_disabled disabled_platforms "")
|
||||
|
||||
if (raw_disabled)
|
||||
|
@ -124,7 +123,6 @@ function(AddJsonPackage)
|
|||
EXTENSION ${extension}
|
||||
MIN_VERSION ${min_version}
|
||||
DISABLED_PLATFORMS ${disabled_platforms}
|
||||
CMAKE_FILENAME ${cmake_filename}
|
||||
)
|
||||
|
||||
# pass stuff to parent scope
|
||||
|
@ -139,6 +137,7 @@ function(AddJsonPackage)
|
|||
endif()
|
||||
|
||||
get_json_element("${object}" hash hash "")
|
||||
get_json_element("${object}" hash_suffix hash_suffix "")
|
||||
get_json_element("${object}" sha sha "")
|
||||
get_json_element("${object}" url url "")
|
||||
get_json_element("${object}" key key "")
|
||||
|
@ -208,6 +207,7 @@ function(AddJsonPackage)
|
|||
VERSION "${version}"
|
||||
URL "${url}"
|
||||
HASH "${hash}"
|
||||
HASH_SUFFIX "${hash_suffix}"
|
||||
SHA "${sha}"
|
||||
REPO "${repo}"
|
||||
KEY "${key}"
|
||||
|
@ -277,6 +277,7 @@ function(AddPackage)
|
|||
|
||||
KEY
|
||||
BUNDLED_PACKAGE
|
||||
FORCE_BUNDLED_PACKAGE
|
||||
FIND_PACKAGE_ARGUMENTS
|
||||
)
|
||||
|
||||
|
@ -426,7 +427,9 @@ function(AddPackage)
|
|||
- BUNDLED_PACKAGE
|
||||
- default to allow local
|
||||
]]#
|
||||
if (${PKG_ARGS_NAME}_FORCE_SYSTEM)
|
||||
if (PKG_ARGS_FORCE_BUNDLED_PACKAGE)
|
||||
set_precedence(OFF OFF)
|
||||
elseif (${PKG_ARGS_NAME}_FORCE_SYSTEM)
|
||||
set_precedence(ON ON)
|
||||
elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED)
|
||||
set_precedence(OFF OFF)
|
||||
|
@ -446,9 +449,14 @@ function(AddPackage)
|
|||
set_precedence(ON OFF)
|
||||
endif()
|
||||
|
||||
if (DEFINED PKG_ARGS_VERSION)
|
||||
list(APPEND EXTRA_ARGS
|
||||
VERSION ${PKG_ARGS_VERSION}
|
||||
)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ${PKG_ARGS_NAME}
|
||||
VERSION ${PKG_ARGS_VERSION}
|
||||
URL ${pkg_url}
|
||||
URL_HASH ${pkg_hash}
|
||||
CUSTOM_CACHE_KEY ${pkg_key}
|
||||
|
@ -459,6 +467,8 @@ function(AddPackage)
|
|||
PATCHES ${PKG_ARGS_PATCHES}
|
||||
EXCLUDE_FROM_ALL ON
|
||||
|
||||
${EXTRA_ARGS}
|
||||
|
||||
${PKG_ARGS_UNPARSED_ARGUMENTS}
|
||||
)
|
||||
|
||||
|
@ -511,12 +521,12 @@ function(add_ci_package key)
|
|||
NAME ${ARTIFACT_PACKAGE}
|
||||
REPO ${ARTIFACT_REPO}
|
||||
TAG v${ARTIFACT_VERSION}
|
||||
VERSION ${ARTIFACT_VERSION}
|
||||
GIT_VERSION ${ARTIFACT_VERSION}
|
||||
ARTIFACT ${ARTIFACT}
|
||||
|
||||
KEY ${key}
|
||||
KEY ${key}-${ARTIFACT_VERSION}
|
||||
HASH_SUFFIX sha512sum
|
||||
BUNDLED_PACKAGE ON
|
||||
FORCE_BUNDLED_PACKAGE ON
|
||||
)
|
||||
|
||||
set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}_SOURCE_DIR} PARENT_SCOPE)
|
||||
|
@ -533,7 +543,6 @@ function(AddCIPackage)
|
|||
EXTENSION
|
||||
MIN_VERSION
|
||||
DISABLED_PLATFORMS
|
||||
CMAKE_FILENAME
|
||||
)
|
||||
|
||||
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN})
|
||||
|
@ -589,25 +598,28 @@ function(AddCIPackage)
|
|||
add_ci_package(android)
|
||||
endif()
|
||||
|
||||
if(PLATFORM_SUN AND NOT "solaris" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(solaris)
|
||||
if(PLATFORM_SUN AND NOT "solaris-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(solaris-amd64)
|
||||
endif()
|
||||
|
||||
if(PLATFORM_FREEBSD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(freebsd)
|
||||
if(PLATFORM_FREEBSD AND NOT "freebsd-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(freebsd-amd64)
|
||||
endif()
|
||||
|
||||
if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(linux)
|
||||
if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(linux-amd64)
|
||||
endif()
|
||||
|
||||
if((PLATFORM_LINUX AND ARCHITECTURE_arm64) AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(linux-aarch64)
|
||||
endif()
|
||||
|
||||
if (DEFINED ARTIFACT_DIR)
|
||||
include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake)
|
||||
# TODO(crueter): macOS amd64/aarch64 split mayhaps
|
||||
if (APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(macos-universal)
|
||||
endif()
|
||||
|
||||
if (DEFINED ARTIFACT_DIR)
|
||||
set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE)
|
||||
set(${ARTIFACT_PACKAGE}_SOURCE_DIR "${ARTIFACT_DIR}" PARENT_SCOPE)
|
||||
else()
|
||||
|
|
|
@ -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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
function(copy_yuzu_SDL_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
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)
|
||||
|
|
|
@ -13,9 +13,12 @@ find_package_handle_standard_args(zstd
|
|||
if (zstd_FOUND AND NOT TARGET zstd::zstd)
|
||||
if (TARGET zstd::libzstd_shared)
|
||||
add_library(zstd::zstd ALIAS zstd::libzstd_shared)
|
||||
add_library(zstd::libzstd ALIAS zstd::libzstd_shared)
|
||||
elseif (TARGET zstd::libzstd_static)
|
||||
add_library(zstd::zstd ALIAS zstd::libzstd_static)
|
||||
add_library(zstd::libzstd ALIAS zstd::libzstd_static)
|
||||
else()
|
||||
add_library(zstd::zstd ALIAS PkgConfig::ZSTD)
|
||||
add_library(zstd::libzstd ALIAS PkgConfig::ZSTD)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -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-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -6,7 +8,7 @@ set(CMAKE_SYSTEM_NAME Windows)
|
|||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
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-)
|
||||
|
||||
# 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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -9,7 +11,7 @@ set(CMAKE_HOST_WIN32 TRUE)
|
|||
|
||||
|
||||
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-)
|
||||
|
||||
# Specify the cross compiler
|
||||
|
|
|
@ -48,6 +48,8 @@ A list of supported games will be available in future. Please be patient.
|
|||
|
||||
Check out our [website](https://eden-emu.dev) for the latest news on exciting features, monthly progress reports, and more!
|
||||
|
||||
[](https://repology.org/project/eden-emulator/versions)
|
||||
|
||||
## Development
|
||||
|
||||
Most of the development happens on our Git server. It is also where [our central repository](https://git.eden-emu.dev/eden-emu/eden) is hosted. For development discussions, please join us on [Discord](https://discord.gg/kXAmGCXBGD) or [Revolt](https://rvlt.gg/qKgFEAbH).
|
||||
|
@ -63,6 +65,8 @@ Alternatively, if you wish to add translations, go to the [Eden project on Trans
|
|||
|
||||
See the [General Build Guide](docs/Build.md)
|
||||
|
||||
For information on provided development tooling, see the [Tools directory](./tools)
|
||||
|
||||
## Download
|
||||
|
||||
You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
|
||||
|
|
121
cpmfile.json
121
cpmfile.json
|
@ -4,8 +4,11 @@
|
|||
"package": "OpenSSL",
|
||||
"name": "openssl",
|
||||
"repo": "crueter-ci/OpenSSL",
|
||||
"version": "3.5.3",
|
||||
"min_version": "1.1.1"
|
||||
"version": "3.6.0",
|
||||
"min_version": "1.1.1",
|
||||
"disabled_platforms": [
|
||||
"macos-universal"
|
||||
]
|
||||
},
|
||||
"boost": {
|
||||
"package": "Boost",
|
||||
|
@ -15,6 +18,7 @@
|
|||
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
|
||||
"git_version": "1.89.0",
|
||||
"version": "1.57",
|
||||
"find_args": "CONFIG",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch",
|
||||
"0002-use-marmasm.patch",
|
||||
|
@ -23,12 +27,10 @@
|
|||
},
|
||||
"fmt": {
|
||||
"repo": "fmtlib/fmt",
|
||||
"sha": "40626af88b",
|
||||
"hash": "d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "c4ab814c20fbad7e3f0ae169125a4988a2795631194703251481dc36b18da65c886c4faa9acd046b0a295005217b3689eb0126108a9ba5aac2ca909aae263c2f",
|
||||
"version": "8",
|
||||
"options": [
|
||||
"FMT_INSTALL OFF"
|
||||
]
|
||||
"git_version": "12.0.0"
|
||||
},
|
||||
"lz4": {
|
||||
"name": "lz4",
|
||||
|
@ -40,16 +42,18 @@
|
|||
"nlohmann": {
|
||||
"package": "nlohmann_json",
|
||||
"repo": "nlohmann/json",
|
||||
"sha": "55f93686c0",
|
||||
"hash": "b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486",
|
||||
"version": "3.8"
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "6cc1e86261f8fac21cc17a33da3b6b3c3cd5c116755651642af3c9e99bb3538fd42c1bd50397a77c8fb6821bc62d90e6b91bcdde77a78f58f2416c62fc53b97d",
|
||||
"version": "3.8",
|
||||
"git_version": "3.12.0"
|
||||
},
|
||||
"zlib": {
|
||||
"package": "ZLIB",
|
||||
"repo": "madler/zlib",
|
||||
"sha": "51b7f2abda",
|
||||
"hash": "16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "8c9642495bafd6fad4ab9fb67f09b268c69ff9af0f4f20cf15dfc18852ff1f312bd8ca41de761b3f8d8e90e77d79f2ccacd3d4c5b19e475ecf09d021fdfe9088",
|
||||
"version": "1.2",
|
||||
"git_version": "1.3.1",
|
||||
"options": [
|
||||
"ZLIB_BUILD_SHARED OFF",
|
||||
"ZLIB_INSTALL OFF"
|
||||
|
@ -57,8 +61,8 @@
|
|||
},
|
||||
"zstd": {
|
||||
"repo": "facebook/zstd",
|
||||
"sha": "f8745da6ff",
|
||||
"hash": "3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee",
|
||||
"sha": "b8d6101fba",
|
||||
"hash": "a6c8e5272214fd3e65e03ae4fc375f452bd2f646623886664ee23e239e35751cfc842db4d34a84a8039d89fc8f76556121f2a4ae350d017bdff5e22150f9c3de",
|
||||
"version": "1.5",
|
||||
"source_subdir": "build/cmake",
|
||||
"find_args": "MODULE",
|
||||
|
@ -66,20 +70,6 @@
|
|||
"ZSTD_BUILD_SHARED OFF"
|
||||
]
|
||||
},
|
||||
"catch2": {
|
||||
"package": "Catch2",
|
||||
"repo": "catchorg/Catch2",
|
||||
"sha": "644821ce28",
|
||||
"hash": "f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f",
|
||||
"version": "3.0.1"
|
||||
},
|
||||
"enet": {
|
||||
"repo": "lsalzman/enet",
|
||||
"sha": "2662c0de09",
|
||||
"hash": "3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd",
|
||||
"version": "1.3",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"opus": {
|
||||
"package": "Opus",
|
||||
"repo": "crueter/opus",
|
||||
|
@ -91,54 +81,6 @@
|
|||
"OPUS_PRESUME_NEON ON"
|
||||
]
|
||||
},
|
||||
"vulkan-utility-headers": {
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"repo": "scripts/VulkanUtilityHeaders",
|
||||
"tag": "1.4.326",
|
||||
"artifact": "VulkanUtilityHeaders.tar.zst",
|
||||
"git_host": "git.crueter.xyz",
|
||||
"hash": "5924629755cb1605c4aa4eee20ef7957a9dd8d61e4df548be656d98054f2730c4109693c1bd35811f401f4705d2ccff9fc849be32b0d8480bc3f73541a5e0964"
|
||||
},
|
||||
"spirv-tools": {
|
||||
"package": "SPIRV-Tools",
|
||||
"repo": "KhronosGroup/SPIRV-Tools",
|
||||
"sha": "40eb301f32",
|
||||
"hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa",
|
||||
"find_args": "MODULE",
|
||||
"options": [
|
||||
"SPIRV_SKIP_EXECUTABLES ON"
|
||||
]
|
||||
},
|
||||
"spirv-headers": {
|
||||
"package": "SPIRV-Headers",
|
||||
"repo": "KhronosGroup/SPIRV-Headers",
|
||||
"sha": "4e209d3d7e",
|
||||
"hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4",
|
||||
"options": [
|
||||
"SPIRV_WERROR OFF"
|
||||
]
|
||||
},
|
||||
"mbedtls": {
|
||||
"package": "MbedTLS",
|
||||
"repo": "Mbed-TLS/mbedtls",
|
||||
"tag": "mbedtls-%VERSION%",
|
||||
"hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da",
|
||||
"version": "3",
|
||||
"git_version": "3.6.4",
|
||||
"artifact": "%TAG%.tar.bz2"
|
||||
},
|
||||
"cubeb": {
|
||||
"repo": "mozilla/cubeb",
|
||||
"sha": "fa02160712",
|
||||
"hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"USE_SANITIZERS OFF",
|
||||
"BUILD_TESTS OFF",
|
||||
"BUILD_TOOLS OFF",
|
||||
"BUNDLE_SPEEX ON"
|
||||
]
|
||||
},
|
||||
"boost_headers": {
|
||||
"repo": "boostorg/headers",
|
||||
"sha": "95930ca8f5",
|
||||
|
@ -157,35 +99,10 @@
|
|||
"hash": "99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"sdl2_generic": {
|
||||
"package": "SDL2",
|
||||
"repo": "libsdl-org/SDL",
|
||||
"sha": "54772f345a",
|
||||
"hash": "2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4",
|
||||
"key": "generic",
|
||||
"bundled": true
|
||||
},
|
||||
"sdl2_steamdeck": {
|
||||
"package": "SDL2",
|
||||
"repo": "libsdl-org/SDL",
|
||||
"sha": "cc016b0046",
|
||||
"hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b",
|
||||
"key": "steamdeck",
|
||||
"bundled": true
|
||||
},
|
||||
"sdl2": {
|
||||
"ci": true,
|
||||
"package": "SDL2",
|
||||
"name": "SDL2",
|
||||
"repo": "crueter-ci/SDL2",
|
||||
"version": "2.32.8",
|
||||
"min_version": "2.26.4",
|
||||
"cmake_filename": "sdl2"
|
||||
},
|
||||
"llvm-mingw": {
|
||||
"repo": "misc/llvm-mingw",
|
||||
"git_host": "git.crueter.xyz",
|
||||
"tag": "20250828",
|
||||
"tag": "%VERSION%",
|
||||
"version": "20250828",
|
||||
"artifact": "clang-rt-builtins.tar.zst",
|
||||
"hash": "d902392caf94e84f223766e2cc51ca5fab6cae36ab8dc6ef9ef6a683ab1c483bfcfe291ef0bd38ab16a4ecc4078344fa8af72da2f225ab4c378dee23f6186181"
|
||||
|
|
250
docs/CPM.md
250
docs/CPM.md
|
@ -1,250 +0,0 @@
|
|||
# CPM
|
||||
|
||||
CPM (CMake Package Manager) is the preferred method of managing dependencies within Eden.
|
||||
|
||||
Global Options:
|
||||
|
||||
- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing
|
||||
* If this is `OFF`, required system dependencies will be searched via `find_package`, although certain externals use CPM regardless.
|
||||
- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED!
|
||||
* Many packages, e.g. mcl, sirit, xbyak, discord-rpc, are not generally available as a system package.
|
||||
* You may optionally override these (see CPMUtil section)
|
||||
- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages.
|
||||
|
||||
## CPMUtil
|
||||
|
||||
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
|
||||
|
||||
### AddPackage
|
||||
|
||||
`AddPackage` is the core of the CPMUtil wrapper, and is generally the lowest level you will need to go when dealing with dependencies.
|
||||
|
||||
**Identification/Fetching**
|
||||
|
||||
- `NAME` (required): The package name (must be the same as the `find_package` name if applicable)
|
||||
- `VERSION`: The minimum version of this package that can be used on the system
|
||||
- `GIT_VERSION`: The "version" found within git
|
||||
- `URL`: The URL to fetch.
|
||||
- `REPO`: The GitHub repo to use (`owner/repo`).
|
||||
* Only GitHub is supported for now, though other platforms will see support at some point
|
||||
- `TAG`: The tag to fetch, if applicable.
|
||||
- `ARTIFACT`: The name of the artifact, if applicable.
|
||||
- `SHA`: Commit sha to fetch, if applicable.
|
||||
- `BRANCH`: Branch to fetch, if applicable.
|
||||
|
||||
The following configurations are supported, in descending order of precedence:
|
||||
|
||||
- `URL`: Bare URL download, useful for custom artifacts
|
||||
* If this is set, `GIT_URL` or `REPO` should be set to allow the dependency viewer to link to the project's Git repository.
|
||||
* If this is NOT set, `REPO` must be defined.
|
||||
- `REPO + TAG + ARTIFACT`: GitHub release artifact
|
||||
* The final download URL will be `https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}`
|
||||
* Useful for prebuilt libraries and prefetched archives
|
||||
- `REPO + TAG`: GitHub tag archive
|
||||
* The final download URL will be `https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz`
|
||||
* Useful for pinning to a specific tag, better for build identification
|
||||
- `REPO + SHA`: GitHub commit archive
|
||||
* The final download URL will be `https://github.com/${REPO}/archive/${SHA}.zip`
|
||||
* Useful for pinning to a specific commit
|
||||
- `REPO + BRANCH`: GitHub branch archive
|
||||
* The final download URL will be `https://github.com/${REPO}/archive/refs/heads/${BRANCH}.zip`
|
||||
* Generally not recommended unless the branch is frozen
|
||||
- `REPO`: GitHub master archive
|
||||
* The final download URL will be `https://github.com/${REPO}/archive/refs/heads/master.zip`
|
||||
* Generally not recommended unless the project is dead
|
||||
|
||||
**Hashing**
|
||||
|
||||
Hashing is used for verifying downloads. It's highly recommended to use these.
|
||||
|
||||
- `HASH_ALGO` (default `SHA512`): Hash algorithm to use
|
||||
|
||||
Hashing strategies, descending order of precedence:
|
||||
|
||||
- `HASH`: Bare hash verification, useful for static downloads e.g. commit archives
|
||||
- `HASH_SUFFIX`: Download the hash as `${DOWNLOAD_URL}.${HASH_SUFFIX}`
|
||||
* The downloaded hash *must* match the hash algorithm and contain nothing but the hash; no filenames or extra content.
|
||||
- `HASH_URL`: Download the hash from a separate URL
|
||||
|
||||
**Additional Options**
|
||||
|
||||
- `KEY`: Custom cache key to use (stored as `.cache/cpm/${packagename_lower}/${key}`)
|
||||
* Default is based on, in descending order of precedence:
|
||||
- First 4 characters of the sha
|
||||
- `GIT_VERSION`
|
||||
- Tag
|
||||
- `VERSION`
|
||||
- Otherwise, CPM defaults will be used. This is not recommended as it doesn't produce reproducible caches
|
||||
- `DOWNLOAD_ONLY`: Whether or not to configure the downloaded package via CMake
|
||||
* Useful to turn `OFF` if the project doesn't use CMake
|
||||
- `SOURCE_SUBDIR`: Subdirectory of the project containing a CMakeLists.txt file
|
||||
- `FIND_PACKAGE_ARGUMENTS`: Arguments to pass to the `find_package` call
|
||||
- `BUNDLED_PACKAGE`: Set to `ON` to force the usage of a bundled package
|
||||
- `OPTIONS`: Options to pass to the configuration of the package
|
||||
- `PATCHES`: Patches to apply to the package, stored in `.patch/${packagename_lower}/0001-patch-name.patch` and so on
|
||||
- Other arguments can be passed to CPM as well
|
||||
|
||||
**Extra Variables**
|
||||
|
||||
For each added package, users may additionally force usage of the system/bundled package.
|
||||
|
||||
- `${package}_FORCE_SYSTEM`: Require the package to be installed on the system
|
||||
- `${package}_FORCE_BUNDLED`: Force the package to be fetched and use the bundled version
|
||||
|
||||
**Bundled/System Switching**
|
||||
|
||||
Descending order of precedence:
|
||||
- If `${package}_FORCE_SYSTEM` is true, requires the package to be on the system
|
||||
- If `${package}_FORCE_BUNDLED` is true, forcefully uses the bundled package
|
||||
- If `CPMUTIL_FORCE_SYSTEM` is true, requires the package to be on the system
|
||||
- If `CPMUTIL_FORCE_BUNDLED` is true, forcefully uses the bundled package
|
||||
- If the `BUNDLED_PACKAGE` argument is true, forcefully uses the bundled package
|
||||
- Otherwise, CPM will search for the package first, and if not found, will use the bundled package
|
||||
|
||||
**Identification**
|
||||
|
||||
All dependencies must be identifiable in some way for usage in the dependency viewer. Lists are provided in descending order of precedence.
|
||||
|
||||
URLs:
|
||||
|
||||
- `GIT_URL`
|
||||
- `REPO` as a GitHub repository
|
||||
- `URL`
|
||||
|
||||
Versions (bundled):
|
||||
|
||||
- `SHA`
|
||||
- `GIT_VERSION`
|
||||
- `VERSION`
|
||||
- `TAG`
|
||||
- "unknown"
|
||||
|
||||
If the package is a system package, AddPackage will attempt to determine the package version and append ` (system)` to the identifier. Otherwise, it will be marked as `unknown (system)`
|
||||
|
||||
### AddCIPackage
|
||||
|
||||
Adds a package that follows crueter's CI repository spec.
|
||||
|
||||
- `VERSION` (required): The version to get (the tag will be `v${VERSION}`)
|
||||
- `NAME` (required): Name used within the artifacts
|
||||
- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL`
|
||||
- `PACKAGE` (required): `find_package` package name
|
||||
- `EXTENSION`: Artifact extension (default `tar.zst`)
|
||||
- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact
|
||||
- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. One of:
|
||||
* `windows-amd64`
|
||||
* `windows-arm64`
|
||||
* `android`
|
||||
* `solaris`
|
||||
* `freebsd`
|
||||
* `linux`
|
||||
* `linux-aarch64`
|
||||
- `CMAKE_FILENAME`: Custom CMake filename, relative to the package root (default `${PACKAGE_ROOT}/${NAME}.cmake`)
|
||||
|
||||
### AddJsonPackage
|
||||
|
||||
This is the recommended method of usage for CPMUtil. In each directory that utilizes `CPMUtil`, there must be a `cpmfile.json` that defines dependencies in a similar manner to the individual calls.
|
||||
|
||||
The cpmfile is an object of objects, with each sub-object being named according to the package's identifier, e.g. `openssl`, which can then be fetched with `AddJsonPackage(<identifier>)`. Options are designed to map closely to the argument names, and are always strings unless otherwise specified.
|
||||
|
||||
- `package` -> `NAME` (`PACKAGE` for CI), defaults to the object key
|
||||
- `repo` -> `REPO`
|
||||
- `version` -> `VERSION`
|
||||
- `ci` (bool)
|
||||
|
||||
If `ci` is `false`:
|
||||
|
||||
- `hash` -> `HASH`
|
||||
- `sha` -> `SHA`
|
||||
- `tag` -> `TAG`
|
||||
- `artifact` -> `ARTIFACT`
|
||||
- `git_version` -> `GIT_VERSION`
|
||||
- `source_subdir` -> `SOURCE_SUBDIR`
|
||||
- `bundled` -> `BUNDLED_PACKAGE`
|
||||
- `find_args` -> `FIND_PACKAGE_ARGUMENTS`
|
||||
- `patches` -> `PATCHES` (array)
|
||||
- `options` -> `OPTIONS` (array)
|
||||
|
||||
Other arguments aren't currently supported. If you wish to add them, see the `AddJsonPackage` function in `CMakeModules/CPMUtil.cmake`.
|
||||
|
||||
If `ci` is `true`:
|
||||
|
||||
- `name` -> `NAME`, defaults to the object key
|
||||
- `extension` -> `EXTENSION`, defaults to `tar.zst`
|
||||
- `min_version` -> `MIN_VERSION`
|
||||
- `cmake_filename` -> `CMAKE_FILENAME`
|
||||
- `extension` -> `EXTENSION`
|
||||
|
||||
### Examples
|
||||
|
||||
In order: OpenSSL CI, Boost (tag + artifact), Opus (options + find_args), discord-rpc (sha + options + patches)
|
||||
|
||||
```json
|
||||
{
|
||||
"openssl": {
|
||||
"ci": true,
|
||||
"package": "OpenSSL",
|
||||
"name": "openssl",
|
||||
"repo": "crueter-ci/OpenSSL",
|
||||
"version": "3.5.2",
|
||||
"min_version": "1.1.1"
|
||||
},
|
||||
"boost": {
|
||||
"package": "Boost",
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-1.88.0",
|
||||
"artifact": "boost-1.88.0-cmake.7z",
|
||||
"hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01",
|
||||
"git_version": "1.88.0",
|
||||
"version": "1.57"
|
||||
},
|
||||
"opus": {
|
||||
"package": "Opus",
|
||||
"repo": "xiph/opus",
|
||||
"sha": "5ded705cf4",
|
||||
"hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203",
|
||||
"version": "1.3",
|
||||
"find_args": "MODULE",
|
||||
"options": [
|
||||
"OPUS_BUILD_TESTING OFF",
|
||||
"OPUS_BUILD_PROGRAMS OFF",
|
||||
"OPUS_INSTALL_PKG_CONFIG_MODULE OFF",
|
||||
"OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF"
|
||||
]
|
||||
},
|
||||
"discord-rpc": {
|
||||
"repo": "discord/discord-rpc",
|
||||
"sha": "963aa9f3e5",
|
||||
"hash": "386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde",
|
||||
"options": [
|
||||
"BUILD_EXAMPLES OFF"
|
||||
],
|
||||
"patches": [
|
||||
"0001-cmake-version.patch",
|
||||
"0002-no-clang-format.patch",
|
||||
"0003-fix-cpp17.patch"
|
||||
]
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Inclusion
|
||||
|
||||
To include CPMUtil:
|
||||
|
||||
```cmake
|
||||
include(CPMUtil)
|
||||
```
|
||||
|
||||
## Prefetching
|
||||
|
||||
- To prefetch a CPM dependency (requires cpmfile):
|
||||
* `tools/cpm-fetch.sh <packages>`
|
||||
- To prefetch all CPM dependencies:
|
||||
* `tools/cpm-fetch-all.sh`
|
||||
|
||||
Currently, `cpm-fetch.sh` defines the following directories for cpmfiles (max depth of 2, so subdirs are caught as well):
|
||||
|
||||
`externals src/qt_common src/dynarmic .`
|
||||
|
||||
Whenever you add a new cpmfile, update the script accordingly
|
14
docs/CPMUtil.md
Normal file
14
docs/CPMUtil.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# CPMUtil
|
||||
|
||||
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
|
||||
|
||||
See more in [its repository](https://git.crueter.xyz/CMake/CPMUtil)
|
||||
|
||||
Eden-specific options:
|
||||
|
||||
- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing
|
||||
* If this is `OFF`, required system dependencies will be searched via `find_package`, although most externals use CPM regardless.
|
||||
|
||||
## Tooling
|
||||
|
||||
See the [tooling docs](../tools/cpm)
|
|
@ -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`).
|
||||
- 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.
|
||||
|
||||
## OpenBSD
|
||||
|
|
17
docs/Deps.md
17
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:
|
||||
|
||||
* [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)
|
||||
|
||||
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):
|
||||
|
||||
|
@ -63,6 +63,7 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
|
|||
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
|
||||
* [sirit](https://github.com/eden-emulator/sirit)
|
||||
* [httplib](https://github.com/yhirose/cpp-httplib) - if `ENABLE_QT_UPDATE_CHECKER` or `ENABLE_WEB_SERVICE` are on
|
||||
- This package is known to be broken on the AUR.
|
||||
* [cpp-jwt](https://github.com/arun11299/cpp-jwt) 1.4+ - if `ENABLE_WEB_SERVICE` is on
|
||||
* [unordered-dense](https://github.com/martinus/unordered_dense)
|
||||
* [mcl](https://github.com/azahar-emu/mcl) - subject to removal
|
||||
|
@ -89,7 +90,7 @@ Click on the arrows to expand.
|
|||
<summary>Arch Linux</summary>
|
||||
|
||||
```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.
|
||||
|
@ -116,7 +117,7 @@ sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel
|
|||
```
|
||||
|
||||
* 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`
|
||||
* [RPM Fusion](https://rpmfusion.org/) is required for `ffmpeg-devel`
|
||||
* Fedora 32 or later is required.
|
||||
|
@ -129,7 +130,7 @@ sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel
|
|||
Install dependencies from **[Homebrew](https://brew.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`.
|
||||
|
@ -146,7 +147,7 @@ brew install molten-vk vulkan-loader
|
|||
|
||||
```
|
||||
devel/cmake
|
||||
devel/sdl20
|
||||
devel/sdl30
|
||||
devel/boost-libs
|
||||
devel/catch2
|
||||
devel/libfmt
|
||||
|
@ -180,7 +181,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
|||
|
||||
```sh
|
||||
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>
|
||||
|
||||
|
@ -194,7 +195,7 @@ Run the usual update + install of essential toolings: `sudo pkg update && sudo p
|
|||
- **gcc**: `sudo pkg install developer/gcc-14`.
|
||||
- **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 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>
|
||||
|
@ -202,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`)
|
||||
* Download and install all dependencies using:
|
||||
* `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:
|
||||
* `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
|
||||
* Add VulkanSDK to the PATH:
|
||||
|
|
|
@ -40,12 +40,12 @@ Notes:
|
|||
* Unavailable on OpenBSD
|
||||
|
||||
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
|
||||
- `YUZU_USE_EXTERNAL_SDL2` (ON for non-UNIX) Compiles SDL2 from source
|
||||
- `YUZU_USE_BUNDLED_SDL2` (ON for MSVC) Download a prebuilt SDL2
|
||||
- `YUZU_USE_EXTERNAL_SDL3` (ON for non-UNIX) Compiles SDL3 from source
|
||||
- `YUZU_USE_BUNDLED_SDL3` (ON for MSVC) Download a prebuilt SDL3
|
||||
* 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_OPENGL` (ON) Enable the OpenGL graphics frontend
|
||||
* 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_STANDALONE` (ON) Enable standalone room executable (eden-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"
|
||||
* Currently only available on Windows and Linux
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@ This contains documentation created by developers. This contains build instructi
|
|||
- **[General Build Instructions](Build.md)**
|
||||
- **[Development Guidelines](Development.md)**
|
||||
- **[Dependencies](Deps.md)**
|
||||
- **[CPM - CMake Package Manager](CPM.md)**
|
||||
- **[CPM - CMake Package Manager](CPMUtil.md)**
|
||||
- **[Platform-Specific Caveats](Caveats.md)**
|
||||
- **[User Directory Handling](User.md)**
|
||||
- **[User Handbook](User.md)**
|
|
@ -27,6 +27,7 @@ The following are not valid reasons to sign up:
|
|||
* To download and use Eden, see our [Releases page](https://github.com/eden-emulator/Releases/releases)!
|
||||
- I want to see the source code.
|
||||
* To see Eden's source code, go [here](https://git.eden-emu.dev/eden-emu/eden).
|
||||
|
||||
## Other Information
|
||||
|
||||
Requests that appear suspicious, automated, OR blank will generally be automatically filtered. In cases of suspicion, or any of the invalid reasons listed above, you may receive an email back asking for clarification.
|
||||
|
|
15
docs/User.md
15
docs/User.md
|
@ -1,11 +1,10 @@
|
|||
# User configuration
|
||||
# User Handbook
|
||||
|
||||
## Configuration directories
|
||||
The "FAQ".
|
||||
|
||||
Eden will store configuration in the following directories:
|
||||
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
|
||||
|
||||
- **Windows**: `%AppData%\Roaming`.
|
||||
- **Android**: Data is stored internally.
|
||||
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
||||
|
||||
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.
|
||||
- **[The Basics](user/Basics.md)**
|
||||
- **[Audio](user/Audio.md)**
|
||||
- **[Graphics](user/Graphics.md)**
|
||||
- **[Platforms and Architectures](user/Architectures.md)**
|
||||
|
|
132
docs/user/Architectures.md
Normal file
132
docs/user/Architectures.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# User Handbook - Architectures and Platforms
|
||||
|
||||
Notes and caveats for different architectures and platforms.
|
||||
|
||||
# Architectures
|
||||
|
||||
Eden is primarily designed to run on amd64 (x86_64--Intel/AMD 64-bit) and aarch64 (arm64--ARM 64-bit) CPUs. Each architecture tends to have their own quirks and fun stuff; this page serves as a reference for these quirks.
|
||||
|
||||
## amd64
|
||||
|
||||
AMD64, aka x86_64, is the most tested and supported architecture for desktop targets. Android is entirely unsupported.
|
||||
|
||||
### Caveats
|
||||
|
||||
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow!
|
||||
|
||||
Computers on Linux will almost always run Eden strictly better than an equivalent machine on Windows. This is largely due to the way the Linux kernel handles memory management (and the lack of Microsoft spyware).
|
||||
|
||||
Intel Macs are believed to be supported, but no CI is provided for them. Performance will likely be awful on all but the highest-end iMacs and Pro-level Macs, and the MoltenVK requirement generally means Vulkan compatibility will suffer.
|
||||
|
||||
## aarch64
|
||||
|
||||
ARM64, aka aarch64, is the only supported architecture for Android, with limited experimental support available on Linux, Windows, and macOS.
|
||||
|
||||
### Caveats
|
||||
|
||||
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it--submit patches!). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
|
||||
|
||||
When NCE is enabled, do note that the GPU will almost always be the limiting factor. This is especially the case for Android, as well as desktops that lack dedicated GPUs; Adreno, Mali, PowerVR, etc. GPUs are generally significantly weaker relative to their respective CPUs.
|
||||
|
||||
Windows/arm64 is *very* experimental and is unlikely to work at all. Support and testing is in the works.
|
||||
|
||||
## riscv64
|
||||
|
||||
RISC-V, aka riscv64, is sparsely tested, but preliminary tests from developers have reported at least partial support on Milk-V's Fedora/riscv64 Linux distribution. Performance, Vulkan support, compatibility, and build system caveats are largely unknown for the time being.
|
||||
|
||||
### Caveats
|
||||
|
||||
Windows/riscv64 doesn't exist, and may never (until corporate greed no longer consumes Microsoft).
|
||||
|
||||
Android/riscv64 is interesting. While support for it may be added if and when RISC-V phones/handhelds ever go mainstream, arm64 devices will always be preferred due to NCE.
|
||||
|
||||
Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution that has *at least* the standard build tools, Qt, FFmpeg, and SDL2 should work.
|
||||
|
||||
## Other
|
||||
|
||||
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it--submit patches!
|
||||
|
||||
IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not run on IA-64 (assuming you can even find a supported Windows/Linux distribution)
|
||||
|
||||
# Platforms
|
||||
|
||||
The vast majority of Eden's testing is done on Windows, Linux, and Android. However, first-class support is also provided for:
|
||||
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- OpenIndiana (Solaris)
|
||||
- macOS
|
||||
|
||||
## Linux
|
||||
|
||||
While all modern Linux distributions are supported (Fedora >40, Ubuntu >24.04, Debian >12, Arch, Gentoo, etc.), the vast majority of testing and development for Linux is on Arch and Gentoo. Most major build system changes are tested on Gentoo first and foremost, so if builds fail on any modern distribution no matter what you do, it's likely a bug and should be reported.
|
||||
|
||||
Intel and Nvidia GPU support is limited. AMD (RADV) drivers receive first-class testing and are known to provide the most stable Eden experience possible.
|
||||
|
||||
Wayland is not recommended. Testing has shown significantly worse performance on most Wayland compositors compared to X11, alongside mysterious bugs and compatibility errors. For now, set `QT_QPA_PLATFORM=xcb` when running Eden, or pass `-platform xcb` to the launch arguments.
|
||||
|
||||
## Windows
|
||||
|
||||
Windows 10 and 11 are supported. Support for Windows 8.x is unknown, and Windows 7 support is unlikely to ever be added.
|
||||
|
||||
In order to run Eden, you will probably need to install the [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
|
||||
|
||||
Neither AMD nor Nvidia drivers work nearly as well as Linux's RADV drivers. Compatibility is still largely the same, but performance and some hard-to-run games may suffer compared to Linux.
|
||||
|
||||
## Android
|
||||
|
||||
A cooler is always recommended. Phone SoCs tend to get very hot, especially those manufactured with the Samsung process or those lacking in power.
|
||||
|
||||
Adreno 6xx and 7xx GPUs with Turnip drivers will always have the best compatibility. "Stock" (system) drivers will have better performance on Adreno, but compatibility will suffer. Better support for stock drivers (including Adreno 8xx) is in the works.
|
||||
|
||||
Android 16 is always recommended, as it brought major improvements to Vulkan requirements and compatibility, *plus* significant performance gains. Some users reported an over 50% performance gain on some Pixel phones after updating.
|
||||
|
||||
Mali, PowerVR, Xclipse, and other GPU vendors generally lack in performance and compatibility. Notably:
|
||||
- No PowerVR GPUs *except* the DXT-48-1536 are known to work with Eden at all.
|
||||
- No Xclipse GPUs *except* the very latest (e.g. Xclipse 950) are known to work with Eden at all.
|
||||
- Mali has especially bad performance, though the Mali-G715 (Tensor G4) and Immortalis-G925 are known to generally run surprisingly well, especially on Android 16.
|
||||
- The status of all other GPU vendors is unknown. As long as they support Vulkan, they theoretically can run Eden.
|
||||
- Note that these GPUs generally don't play well with driver injection. If you choose to inject custom drivers via a rooted system (Panfrost, RADV, etc), you may see good results.
|
||||
|
||||
Qualcomm Snapdragon SoCs are generally the most well supported.
|
||||
- Google Tensor chips have pretty terrible performance, but even the G1 has been proven to be able to run some games well on the Pixel 6 Pro.
|
||||
* The Tensor G4 is the best-supported at the time. How the G5 currently fares is unknown, but on paper, it should do about as well as a Snapdragon 8 Gen 2 with stock drivers.
|
||||
- Samsung Exynos chips made before 2022 are not supported.
|
||||
- MediaTek Dimensity chips are extremely weak and most before mid-2023 don't work at all.
|
||||
* This means that most budget phones won't work, as they tend to use old MediaTek SoCs.
|
||||
* Generally, if your phone doesn't cost *at least* as much as a Switch itself, it will not *emulate* the Switch very well.
|
||||
- Snapdragon 865 and other old-ish SoCs may benefit from the Legacy build. These will reduce performance but *should* drastically improve compatibility.
|
||||
- If you're not sure how powerful your SoC is, check [NanoReview](https://nanoreview.net/en/soc-compare) - e.g. [Tensor G5](https://archive.is/ylC4Z).
|
||||
* A good base to compare to is the Snapdragon 865--e.g. [Tensor vs SD865](https://archive.is/M1P58)
|
||||
* Some benchmarks may be misleading due to thermal throttling OR RAM requirements.
|
||||
- For example, a Pixel 6a (Tensor G1) performs about 1/3 as well as an 865 due to its lack of RAM and poor thermals.
|
||||
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM!
|
||||
- If you're not sure what SoC you have, check [GSMArena](https://www.gsmarena.com) - e.g. [Pixel 9 Pro](https://archive.ph/91VhA)
|
||||
|
||||
Custom ROMs are recommended, *as long as* you know what you're doing.
|
||||
- For most devices, [LineageOS](https://lineageos.org/) is preferred.
|
||||
- [CalyxOS](https://calyxos.org/) is available as well.
|
||||
- For Google Pixel devices ONLY... and [soon another OEM](https://archive.ph/cPpMd)... [GrapheneOS](https://grapheneos.org/) is highly recommended.
|
||||
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future!
|
||||
* Keep checking the [FAQ page](https://grapheneos.org/faq#supported-devices) for news.
|
||||
- Custom ROMs will likely be exclusively recommended in the future due to Google's upcoming [draconian](https://archive.is/hGIjZ), [anti-privacy, anti-user](https://archive.is/mc1CJ) verification requirements.
|
||||
|
||||
Eden is currently unavailable on F-Droid or the Play Store. Check back occasionally.
|
||||
|
||||
## macOS
|
||||
|
||||
macOS is relatively stable, with only the occasional crash and bug. Compatibility may suffer due to the MoltenVK layer, however.
|
||||
|
||||
Do note that building the GUI version with Qt versions higher than 6.7.3 will cause mysterious bugs, Vulkan errors, and crashes, alongside the cool feature of freezing the entire system UI randomly; we recommend you build with 6.7.3 (via aqtinstall) or earlier as the CI does.
|
||||
|
||||
## *BSD, Solaris
|
||||
|
||||
BSD and Solaris distributions tend to lag behind Linux in terms of Vulkan and other library compatibility. For example, OpenIndiana (Solaris) does not properly package Qt, meaning the recommended method of usage is to use `eden-cli` only for now. Solaris also generally works better with OpenGL.
|
||||
|
||||
AMD GPU support on these platforms is limited or nonexistent.
|
||||
|
||||
## VMs
|
||||
|
||||
Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60fps.
|
||||
|
||||
Some users and developers have had success using a pure OpenGL-accelerated KVM on Linux with a Windows VM, but this is ridiculously tedious to set up. You're probably better off dual-booting.
|
3
docs/user/Audio.md
Normal file
3
docs/user/Audio.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# User Handbook - Audio
|
||||
|
||||
`PULSE_SERVER=none` forces cubeb to use ALSA.
|
57
docs/user/Basics.md
Normal file
57
docs/user/Basics.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# User Handbook - The Basics
|
||||
|
||||
## Introduction
|
||||
|
||||
Eden is a very complicated piece of software, and as such there are many knobs and toggles that can be configured. Most of these are invisible to normal users, however power users may be able to leverage them to their advantage.
|
||||
|
||||
This handbook primarily describes such knobs and toggles. Normal configuration options are described within the emulator itself and will not be covered in detail.
|
||||
|
||||
## Requirements
|
||||
|
||||
The emulator is very demanding on hardware, and as such requires a decent mid-range computer/cellphone.
|
||||
|
||||
See [the requirements page](https://archive.is/sv83h) for recommended and minimum specs.
|
||||
|
||||
The CPU must support FMA for an optimal gameplay experience. The GPU needs to support OpenGL 4.6 ([compatibility list](https://opengl.gpuinfo.org/)), or Vulkan 1.1 ([compatibility list](https://vulkan.gpuinfo.org/)).
|
||||
|
||||
If your GPU doesn't support or is just behind by a minor version, see Mesa environment variables below (*nix only).
|
||||
|
||||
## User configuration
|
||||
|
||||
### Configuration directories
|
||||
|
||||
Eden will store configuration files in the following directories:
|
||||
|
||||
- **Windows**: `%AppData%\Roaming`.
|
||||
- **Android**: Data is stored internally.
|
||||
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
||||
|
||||
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.
|
||||
|
||||
### Environment variables
|
||||
|
||||
Throughout the handbook, environment variables are mentioned. These are often either global (system wide) or local (set in a script, bound only to the current session). It's heavily recommended to use them in a local context only, as this allows you to rollback changes easily (if for example, there are regressions setting them).
|
||||
|
||||
The recommended way is to create a `.bat` file alongside the emulator `.exe`; contents of which could resemble something like:
|
||||
|
||||
```bat
|
||||
set "__GL_THREADED_OPTIMIZATIONS=1"
|
||||
set "SOME_OTHER_VAR=1"
|
||||
eden.exe
|
||||
```
|
||||
|
||||
Android doesn't have a convenient way to set environment variables.
|
||||
|
||||
For other platforms, the recommended method is using a shell script:
|
||||
|
||||
```sh
|
||||
export __GL_THREADED_OPTIMIZATIONS=1
|
||||
export SOME_OTHER_VAR=1
|
||||
./eden
|
||||
```
|
||||
|
||||
Then just running `chmod +x script.sh && source script.sh`.
|
||||
|
||||
## Compatibility list
|
||||
|
||||
Eden doesn't mantain a compatibility list. However, [EmuReady](https://www.emuready.com/) has a more fine-grained compatibility information for multiple emulators/forks as well.
|
62
docs/user/Graphics.md
Normal file
62
docs/user/Graphics.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
# User Handbook - Graphics
|
||||
|
||||
## Visual Enhancements
|
||||
|
||||
### Anti-aliasing
|
||||
|
||||
Enhancements aimed at removing jagged lines/sharp edges and/or masking artifacts.
|
||||
|
||||
- **No AA**: Default, provides no anti-aliasing.
|
||||
- **FXAA**: Fast Anti-Aliasing, an implementation as described on [this blog post](https://web.archive.org/web/20110831051323/http://timothylottes.blogspot.com/2011/03/nvidia-fxaa.html). Generally fast but with some innocuos artifacts.
|
||||
- **SMAA**: Subpixel Morphological Anti-Aliasing, an implementation as described on [this article](https://web.archive.org/web/20250000000000*/https://www.iryoku.com/smaa/).
|
||||
|
||||
### Filters
|
||||
|
||||
Various graphical filters exist - each of them aimed at a specific target/image quality preset.
|
||||
|
||||
- **Nearest**: Provides no filtering - useful for debugging.
|
||||
- **Pros**: Fast, works in any hardware.
|
||||
- **Cons**: Less image quality.
|
||||
- **Bilinear**: Provides the hardware default filtering of the Tegra X1.
|
||||
- **Pros**: Fast with acceptable image quality.
|
||||
- **Bicubic**: Provides a bicubic interpolation using a Catmull-Rom (or hardware-accelerated) implementation.
|
||||
- **Pros**: Better image quality with more rounded edges.
|
||||
- **Zero-Tangent, B-Spline, Mitchell**: Provides bicubic interpolation using the respective matrix weights. They're normally not hardware accelerated unless the device supports the `VK_QCOM_filter_cubic_weights` extension. The matrix weights are those matching [the specification itself](https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#VkSamplerCubicWeightsCreateInfoQCOM).
|
||||
- **Pros/Cons**: Each of them is a variation of the Bicubic interpolation model with different weights, they offer different methods to fix some artifacts present in Catmull-Rom.
|
||||
- **Spline-1**: Bicubic interpolation (similar to Mitchell) but with a faster texel fetch method. Generally less blurry than bicubic.
|
||||
- **Pros**: Faster than bicubic even without hardware accelerated bicubic.
|
||||
- **Gaussian**: Whole-area blur, an applied gaussian blur is done to the entire frame.
|
||||
- **Pros**: Less edge artifacts.
|
||||
- **Cons**: Slow and sometimes blurry.
|
||||
- **Lanczos**: An implementation using `a = 3` (49 texel fetches). Provides sharper edges but blurrier artifacts.
|
||||
- **Pros**: Less edge artifacts and less blurry than gaussian.
|
||||
- **Cons**: Slow.
|
||||
- **ScaleForce**: Experimental texture upscale method, see [ScaleFish](https://github.com/BreadFish64/ScaleFish).
|
||||
- **Pros**: Relatively fast.
|
||||
- **FSR**: Uses AMD FidelityFX Super Resolution to enhance image quality.
|
||||
- **Pros**: Great for upscaling, and offers sharper visual quality.
|
||||
- **Cons**: Somewhat slow, and may be offputtingly sharp.
|
||||
- **Area**: Area interpolation (high kernel count).
|
||||
- **Pros**: Best for downscaling (internal resolution > display resolution).
|
||||
- **Cons**: Costly and slow.
|
||||
- **MMPX**: Nearest-neighbour filter aimed at providing higher pixel-art quality.
|
||||
- **Pros**: Offers decent pixel-art upscaling.
|
||||
- **Cons**: Only works for pixel-art.
|
||||
|
||||
### External
|
||||
|
||||
While stock shaders offer a basic subset of options for most users, programs such as [ReShade](https://github.com/crosire/reshade) offer a more flexible experience. In addition to that users can also seek out modifications (mods) for enhancing visual experience (60 FPS mods, HDR, etc).
|
||||
|
||||
## Driver specifics
|
||||
|
||||
### Mesa environment variable hacks
|
||||
|
||||
The software requires a certain version of Vulkan and a certain version of OpenGL to work - otherwise it will refuse to load, this can be easily bypassed by setting an environment variable: `MESA_GL_VERSION_OVERRIDE=4.6 MESA_GLSL_VERSION_OVERRIDE=460` (OpenGL) and `MESA_VK_VERSION_OVERRIDE=1.3` (Vulkan), for more information see [Environment variables for Mesa](https://web.archive.org/web/20250000000000*/https://docs.mesa3d.org/envvars.html).
|
||||
|
||||
### NVIDIA OpenGL environment variables
|
||||
|
||||
Unstable multithreaded optimisations are offered by the stock proprietary NVIDIA driver on X11 platforms. Setting `__GL_THREADED_OPTIMIZATIONS` to `1` would enable such optimisations. This mainly benefits the OpenGL backend. For more information see [Environment Variables for X11 NVIDIA](https://web.archive.org/web/20250115162518/https://download.nvidia.com/XFree86/Linux-x86_64/435.17/README/openglenvvariables.html).
|
||||
|
||||
### swrast/LLVMpipe crashes under high load
|
||||
|
||||
The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe writing an invalid SSA IR (on old versions of Mesa), and then proceeding to crash. The solution is using a script found in [tools/llvmpipe-run.sh](../../tools/llvmpipe-run.sh).
|
146
externals/CMakeLists.txt
vendored
146
externals/CMakeLists.txt
vendored
|
@ -39,6 +39,140 @@ if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS)
|
|||
AddJsonPackage(oaknut)
|
||||
endif()
|
||||
|
||||
# enet
|
||||
AddJsonPackage(enet)
|
||||
|
||||
if (enet_ADDED)
|
||||
target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET enet::enet)
|
||||
add_library(enet::enet ALIAS enet)
|
||||
endif()
|
||||
|
||||
# mbedtls
|
||||
AddJsonPackage(mbedtls)
|
||||
|
||||
# VulkanUtilityHeaders - pulls in headers and utility libs
|
||||
AddJsonPackage(vulkan-utility-headers)
|
||||
|
||||
# small hack
|
||||
if (NOT VulkanUtilityLibraries_ADDED)
|
||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
||||
endif()
|
||||
|
||||
# DiscordRPC
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
if (ARCHITECTURE_arm64)
|
||||
add_compile_definitions(RAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(discord-rpc)
|
||||
|
||||
if (DiscordRPC_ADDED)
|
||||
target_include_directories(discord-rpc INTERFACE ${DiscordRPC_SOURCE_DIR}/include)
|
||||
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# SimpleIni
|
||||
AddJsonPackage(simpleini)
|
||||
|
||||
# Most linux distros don't package cubeb, so enable regardless of cpm settings
|
||||
if(ENABLE_CUBEB)
|
||||
AddJsonPackage(cubeb)
|
||||
|
||||
if (cubeb_ADDED)
|
||||
if (NOT MSVC)
|
||||
if (TARGET speex)
|
||||
target_compile_options(speex PRIVATE -Wno-sign-compare)
|
||||
endif()
|
||||
|
||||
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
|
||||
target_compile_options(cubeb INTERFACE
|
||||
-Wno-implicit-const-int-float-conversion
|
||||
-Wno-shadow
|
||||
-Wno-missing-declarations
|
||||
-Wno-return-type
|
||||
-Wno-uninitialized
|
||||
)
|
||||
else()
|
||||
target_compile_options(cubeb PRIVATE
|
||||
/wd4456
|
||||
/wd4458
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT TARGET cubeb::cubeb)
|
||||
add_library(cubeb::cubeb ALIAS cubeb)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# find SDL3 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
|
||||
if (ENABLE_SDL3)
|
||||
if (YUZU_USE_EXTERNAL_SDL3)
|
||||
message(STATUS "Using SDL3 from externals.")
|
||||
if (NOT WIN32)
|
||||
# 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)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(SDL_FILE ON)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(sdl3)
|
||||
elseif (YUZU_USE_BUNDLED_SDL3)
|
||||
message(STATUS "Using bundled SDL3")
|
||||
AddJsonPackage(sdl3-ci)
|
||||
endif()
|
||||
|
||||
find_package(SDL3 3.2.12 REQUIRED)
|
||||
endif()
|
||||
|
||||
# SPIRV Headers
|
||||
AddJsonPackage(spirv-headers)
|
||||
|
||||
# Sirit
|
||||
if (YUZU_USE_BUNDLED_SIRIT)
|
||||
AddJsonPackage(sirit-ci)
|
||||
else()
|
||||
AddJsonPackage(sirit)
|
||||
if(MSVC AND USE_CCACHE AND sirit_ADDED)
|
||||
get_target_property(_opts sirit COMPILE_OPTIONS)
|
||||
list(FILTER _opts EXCLUDE REGEX "/Zi")
|
||||
list(APPEND _opts "/Z7")
|
||||
set_target_properties(siritobj PROPERTIES COMPILE_OPTIONS "${_opts}")
|
||||
elseif(MSVC AND CXX_CLANG)
|
||||
target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# SPIRV Tools
|
||||
AddJsonPackage(spirv-tools)
|
||||
|
||||
if (SPIRV-Tools_ADDED)
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static)
|
||||
target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link)
|
||||
endif()
|
||||
|
||||
# Catch2
|
||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||
AddJsonPackage(catch2)
|
||||
endif()
|
||||
|
||||
# getopt
|
||||
if (MSVC)
|
||||
add_subdirectory(getopt)
|
||||
|
@ -67,18 +201,6 @@ if (VulkanMemoryAllocator_ADDED)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# Sirit
|
||||
AddJsonPackage(sirit)
|
||||
|
||||
if(MSVC AND USE_CCACHE AND sirit_ADDED)
|
||||
get_target_property(_opts sirit COMPILE_OPTIONS)
|
||||
list(FILTER _opts EXCLUDE REGEX "/Zi")
|
||||
list(APPEND _opts "/Z7")
|
||||
set_target_properties(sirit PROPERTIES COMPILE_OPTIONS "${_opts}")
|
||||
elseif(MSVC AND CXX_CLANG)
|
||||
target_compile_options(sirit PRIVATE -Wno-error=unused-command-line-argument)
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
|
||||
AddJsonPackage(httplib)
|
||||
|
|
157
externals/cpmfile.json
vendored
157
externals/cpmfile.json
vendored
|
@ -2,23 +2,34 @@
|
|||
"vulkan-memory-allocator": {
|
||||
"package": "VulkanMemoryAllocator",
|
||||
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
||||
"sha": "1076b348ab",
|
||||
"hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772",
|
||||
"find_args": "CONFIG"
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
||||
"find_args": "CONFIG",
|
||||
"git_version": "3.3.0"
|
||||
},
|
||||
"sirit": {
|
||||
"repo": "eden-emulator/sirit",
|
||||
"sha": "db1f1e8ab5",
|
||||
"hash": "73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05",
|
||||
"git_version": "1.0.2",
|
||||
"tag": "v%VERSION%",
|
||||
"artifact": "sirit-source-%VERSION%.tar.zst",
|
||||
"hash_suffix": "sha512sum",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"SIRIT_USE_SYSTEM_SPIRV_HEADERS ON"
|
||||
]
|
||||
},
|
||||
"sirit-ci": {
|
||||
"ci": true,
|
||||
"package": "sirit",
|
||||
"name": "sirit",
|
||||
"repo": "eden-emulator/sirit",
|
||||
"version": "1.0.2"
|
||||
},
|
||||
"httplib": {
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
"sha": "a609330e4c",
|
||||
"hash": "dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2"
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "b364500f76e2ecb0fe21b032d831272e3f1dfeea71af74e325f8fc4ce9dcdb3c941b97a5b422bdeafb9facd058597b90f8bfc284fb9afe3c33fefa15dd5a010b",
|
||||
"git_version": "0.26.0"
|
||||
},
|
||||
"cpp-jwt": {
|
||||
"version": "1.4",
|
||||
|
@ -33,22 +44,26 @@
|
|||
"xbyak_sun": {
|
||||
"package": "xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"sha": "9bb219333a",
|
||||
"hash": "303165d45c8c19387ec49d9fda7d7a4e0d86d4c0153898c23f25ce2d58ece567f44c0bbbfe348239b933edb6e1a1e34f4bc1c0ab3a285bee5da0e548879387b0",
|
||||
"bundled": true
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "e84992c65ad62c577e2746ec5180132fd2875166d1e6b1521a0ff619787e1645792fe5f6a858fe94ed66f297912b6a6b89a509b5d5f5e81a2db1dd7e6790b1f5",
|
||||
"bundled": true,
|
||||
"git_version": "7.30"
|
||||
},
|
||||
"xbyak": {
|
||||
"package": "xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"sha": "4e44f4614d",
|
||||
"hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70",
|
||||
"bundled": true
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "1042090405c426e339506c179d53e91d4d545ce9c9f53d8f797caa092d589f913a9bcb9c8f31c4c60870acb954c556e305fb6732c66bc3c8f1cd924f9172def9",
|
||||
"git_version": "7.22",
|
||||
"bundled": true,
|
||||
"skip_updates": true
|
||||
},
|
||||
"oaknut": {
|
||||
"repo": "eden-emulator/oaknut",
|
||||
"version": "2.0.1",
|
||||
"repo": "merryhime/oaknut",
|
||||
"sha": "94c726ce03",
|
||||
"hash": "d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac"
|
||||
"git_version": "2.0.3",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "9697e80a7d5d9bcb3ce51051a9a24962fb90ca79d215f1f03ae6b58da8ba13a63b5dda1b4dde3d26ac6445029696b8ef2883f4e5a777b342bba01283ed293856"
|
||||
},
|
||||
"libadrenotools": {
|
||||
"repo": "bylaws/libadrenotools",
|
||||
|
@ -60,15 +75,115 @@
|
|||
},
|
||||
"oboe": {
|
||||
"repo": "google/oboe",
|
||||
"sha": "2bc873e53c",
|
||||
"hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
|
||||
"git_version": "1.10.0",
|
||||
"bundled": true
|
||||
},
|
||||
"unordered-dense": {
|
||||
"package": "unordered_dense",
|
||||
"repo": "martinus/unordered_dense",
|
||||
"sha": "73f3cbb237",
|
||||
"hash": "c08c03063938339d61392b687562909c1a92615b6ef39ec8df19ea472aa6b6478e70d7d5e33d4a27b5d23f7806daf57fe1bacb8124c8a945c918c7663a9e8532",
|
||||
"find_args": "CONFIG"
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "f9c819e28e1c1a387acfee09277d6af5e366597a0d39acf1c687acf0608a941ba966af8aaebdb8fba0126c7360269c4a51754ef4cab17c35c01a30215f953368",
|
||||
"find_args": "CONFIG",
|
||||
"git_version": "4.5.0"
|
||||
},
|
||||
"mbedtls": {
|
||||
"package": "MbedTLS",
|
||||
"repo": "Mbed-TLS/mbedtls",
|
||||
"tag": "mbedtls-%VERSION%",
|
||||
"hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da",
|
||||
"version": "3",
|
||||
"git_version": "3.6.4",
|
||||
"artifact": "%TAG%.tar.bz2",
|
||||
"skip_updates": true
|
||||
},
|
||||
"enet": {
|
||||
"repo": "lsalzman/enet",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||
"version": "1.3",
|
||||
"git_version": "1.3.18",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"vulkan-utility-headers": {
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"repo": "scripts/VulkanUtilityHeaders",
|
||||
"tag": "%VERSION%",
|
||||
"git_version": "1.4.328",
|
||||
"artifact": "VulkanUtilityHeaders.tar.zst",
|
||||
"git_host": "git.crueter.xyz",
|
||||
"hash": "9922217b39faf73cd4fc1510f2fdba14a49aa5c0d77f9ee24ee0512cef16b234d0cabc83c1fec861fa5df1d43e7f086ca9b6501753899119f39c5ca530cb0dae"
|
||||
},
|
||||
"spirv-tools": {
|
||||
"package": "SPIRV-Tools",
|
||||
"repo": "crueter/SPIRV-Tools",
|
||||
"sha": "2fa2d44485",
|
||||
"hash": "45b198be1d09974ccb2438e8bfa5683f23a0421b058297c28eacfd77e454ec2cf87e77850eddd202efff34b004d8d6b4d12e9615e59bd72be904c196f5eb2169",
|
||||
"git_version": "2025.4",
|
||||
"options": [
|
||||
"SPIRV_SKIP_EXECUTABLES ON"
|
||||
]
|
||||
},
|
||||
"spirv-headers": {
|
||||
"package": "SPIRV-Headers",
|
||||
"repo": "KhronosGroup/SPIRV-Headers",
|
||||
"sha": "01e0577914",
|
||||
"hash": "d0f905311faf7d743de686fdf241dc4cb0a4f08e2184f5a3b3b2946e680db3cd89eeb72954eafe6fa457f93550e27d516575c8709cb134d8aecc0b43064636ce",
|
||||
"options": [
|
||||
"SPIRV_WERROR OFF"
|
||||
]
|
||||
},
|
||||
"cubeb": {
|
||||
"repo": "mozilla/cubeb",
|
||||
"sha": "fa02160712",
|
||||
"hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"USE_SANITIZERS OFF",
|
||||
"BUILD_TESTS OFF",
|
||||
"BUILD_TOOLS OFF",
|
||||
"BUNDLE_SPEEX ON"
|
||||
]
|
||||
},
|
||||
"sdl3": {
|
||||
"package": "SDL3",
|
||||
"repo": "libsdl-org/SDL",
|
||||
"tag": "release-%VERSION%",
|
||||
"hash": "93766ed1f2be0af75e82c05fcb1dc0aac29ded4d0ae9a98137edfc6a4ab85412ea51199d0469254e7e5751fb37d78daff8bc0cbbc20650972f182d976c6bcc61",
|
||||
"git_version": "3.2.24",
|
||||
"bundled": true
|
||||
},
|
||||
"sdl3-ci": {
|
||||
"ci": true,
|
||||
"package": "SDL3",
|
||||
"name": "SDL3",
|
||||
"repo": "libsdl-org/SDL3",
|
||||
"version": "3.2.22",
|
||||
"min_version": "3.2.12",
|
||||
"cmake_filename": "sdl3"
|
||||
},
|
||||
"catch2": {
|
||||
"package": "Catch2",
|
||||
"repo": "catchorg/Catch2",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
|
||||
"version": "3.0.1",
|
||||
"git_version": "3.11.0"
|
||||
},
|
||||
"discord-rpc": {
|
||||
"package": "DiscordRPC",
|
||||
"repo": "eden-emulator/discord-rpc",
|
||||
"sha": "1cf7772bb6",
|
||||
"hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"simpleini": {
|
||||
"package": "SimpleIni",
|
||||
"repo": "brofield/simpleini",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "6c198636816a0018adbf7f735d402c64245c6fcd540b7360d4388d46f007f3a520686cdaec4705cb8cb31401b2cb4797a80b42ea5d08a6a5807c0848386f7ca1",
|
||||
"find_args": "MODULE",
|
||||
"git_version": "4.22"
|
||||
}
|
||||
}
|
||||
|
|
11
externals/ffmpeg/cpmfile.json
vendored
11
externals/ffmpeg/cpmfile.json
vendored
|
@ -5,16 +5,17 @@
|
|||
"hash": "2a89d664119debbb3c006ab1c48d5d7f26e889f4a65ad2e25c8b0503308295123d5a9c5c78bf683aef5ff09acef8c3fc2837f22d3e8c611528b933bf03bcdd97",
|
||||
"bundled": true
|
||||
},
|
||||
"ffmpeg-ci": {
|
||||
"ffmpeg-ci": {
|
||||
"ci": true,
|
||||
"package": "FFmpeg",
|
||||
"name": "ffmpeg",
|
||||
"repo": "crueter-ci/FFmpeg",
|
||||
"version": "8.0",
|
||||
"min_version": "4.1",
|
||||
"disabled_platforms": [
|
||||
"freebsd",
|
||||
"solaris"
|
||||
]
|
||||
"disabled_platforms": [
|
||||
"freebsd-amd64",
|
||||
"solaris-amd64",
|
||||
"macos-universal"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
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
|
||||
|
@ -89,7 +91,7 @@ static char internal_gamemode_client_error_string[512] = { 0 };
|
|||
/**
|
||||
* Load libgamemode dynamically to dislodge us from most dependencies.
|
||||
* 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.
|
||||
*/
|
||||
static volatile int internal_libgamemode_loaded = 1;
|
||||
|
|
13
externals/libusb/CMakeLists.txt
vendored
13
externals/libusb/CMakeLists.txt
vendored
|
@ -6,18 +6,7 @@
|
|||
|
||||
include(CPMUtil)
|
||||
|
||||
# we love our libraries don't we folks
|
||||
if (PLATFORM_SUN)
|
||||
set(libusb_bundled ON)
|
||||
else()
|
||||
set(libusb_bundled OFF)
|
||||
endif()
|
||||
|
||||
# TODO(crueter): Fix on Solaris
|
||||
AddJsonPackage(
|
||||
NAME libusb
|
||||
BUNDLED_PACKAGE ${libusb_bundled}
|
||||
)
|
||||
AddJsonPackage(libusb)
|
||||
|
||||
if (NOT libusb_ADDED)
|
||||
return()
|
||||
|
|
15
externals/libusb/cpmfile.json
vendored
15
externals/libusb/cpmfile.json
vendored
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"libusb": {
|
||||
"repo": "libusb/libusb",
|
||||
"sha": "c060e9ce30",
|
||||
"hash": "44647357ba1179020cfa6674d809fc35cf6f89bff1c57252fe3a610110f5013ad678fc6eb5918e751d4384c30e2fe678868dbffc5f85736157e546cb9d10accc",
|
||||
"find_args": "MODULE"
|
||||
}
|
||||
}
|
||||
"libusb": {
|
||||
"repo": "libusb/libusb",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
|
||||
"find_args": "MODULE",
|
||||
"git_version": "1.0.29"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ if (YUZU_TESTS)
|
|||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2 AND YUZU_CMD)
|
||||
if (ENABLE_SDL3 AND YUZU_CMD)
|
||||
add_subdirectory(yuzu_cmd)
|
||||
set_target_properties(yuzu-cmd PROPERTIES OUTPUT_NAME "eden-cli")
|
||||
endif()
|
||||
|
|
|
@ -57,8 +57,8 @@ android {
|
|||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO If this is ever modified, change application_id in strings.xml
|
||||
applicationId = "dev.eden.eden_emulator"
|
||||
|
||||
minSdk = 28
|
||||
targetSdk = 36
|
||||
versionName = getGitVersion()
|
||||
|
@ -72,8 +72,30 @@ android {
|
|||
|
||||
buildConfigField("String", "GIT_HASH", "\"${getGitHash()}\"")
|
||||
buildConfigField("String", "BRANCH", "\"${getBranch()}\"")
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments.addAll(listOf(
|
||||
"-DENABLE_QT=0", // Don't use QT
|
||||
"-DENABLE_SDL3=0", // Don't use SDL
|
||||
"-DENABLE_WEB_SERVICE=1", // Enable web service
|
||||
"-DENABLE_OPENSSL=ON",
|
||||
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
||||
"-DYUZU_USE_CPM=ON",
|
||||
"-DCPMUTIL_FORCE_BUNDLED=ON",
|
||||
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
|
||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
||||
"-DBUILD_TESTING=OFF",
|
||||
"-DYUZU_TESTS=OFF",
|
||||
"-DDYNARMIC_TESTS=OFF"
|
||||
))
|
||||
|
||||
abiFilters("arm64-v8a")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
|
||||
signingConfigs {
|
||||
if (keystoreFile != null) {
|
||||
|
@ -94,7 +116,6 @@ android {
|
|||
|
||||
// Define build types, which are orthogonal to product flavors.
|
||||
buildTypes {
|
||||
|
||||
// Signed by release key, allowing for upload to Play Store.
|
||||
release {
|
||||
signingConfig = if (keystoreFile != null) {
|
||||
|
@ -103,7 +124,6 @@ android {
|
|||
signingConfigs.getByName("default")
|
||||
}
|
||||
|
||||
resValue("string", "app_name_suffixed", "Eden")
|
||||
isMinifyEnabled = true
|
||||
isDebuggable = false
|
||||
proguardFiles(
|
||||
|
@ -116,7 +136,6 @@ android {
|
|||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||
register("relWithDebInfo") {
|
||||
isDefault = true
|
||||
resValue("string", "app_name_suffixed", "Eden Debug Release")
|
||||
signingConfig = signingConfigs.getByName("default")
|
||||
isDebuggable = true
|
||||
proguardFiles(
|
||||
|
@ -132,7 +151,6 @@ android {
|
|||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||
debug {
|
||||
signingConfig = signingConfigs.getByName("default")
|
||||
resValue("string", "app_name_suffixed", "Eden Debug")
|
||||
isDebuggable = true
|
||||
isJniDebuggable = true
|
||||
versionNameSuffix = "-debug"
|
||||
|
@ -140,19 +158,62 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
// this is really annoying but idk any other ways to fix this behavior
|
||||
applicationVariants.all {
|
||||
val variant = this
|
||||
when {
|
||||
variant.flavorName == "legacy" && variant.buildType.name == "debug" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Legacy Debug")
|
||||
}
|
||||
variant.flavorName == "mainline" && variant.buildType.name == "debug" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Debug")
|
||||
}
|
||||
variant.flavorName == "genshinSpoof" && variant.buildType.name == "debug" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Optimized Debug")
|
||||
}
|
||||
variant.flavorName == "legacy" && variant.buildType.name == "relWithDebInfo" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Legacy Debug Release")
|
||||
}
|
||||
variant.flavorName == "mainline" && variant.buildType.name == "relWithDebInfo" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Debug Release")
|
||||
}
|
||||
variant.flavorName == "genshinSpoof" && variant.buildType.name == "relWithDebInfo" -> {
|
||||
variant.resValue("string", "app_name_suffixed", "Eden Optimized Debug Release")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
flavorDimensions.add("version")
|
||||
productFlavors {
|
||||
create("mainline") {
|
||||
dimension = "version"
|
||||
// No need to set applicationId here
|
||||
resValue("string", "app_name_suffixed", "Eden")
|
||||
}
|
||||
|
||||
create("genshinSpoof") {
|
||||
dimension = "version"
|
||||
resValue("string", "app_name_suffixed", "Eden Optimised")
|
||||
resValue("string", "app_name_suffixed", "Eden Optimized")
|
||||
applicationId = "com.miHoYo.Yuanshen"
|
||||
}
|
||||
|
||||
create("legacy") {
|
||||
dimension = "version"
|
||||
resValue("string", "app_name_suffixed", "Eden Legacy")
|
||||
applicationId = "dev.legacy.eden_emulator"
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments.add("-DYUZU_LEGACY=ON")
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("legacy") {
|
||||
res.srcDirs("src/main/legacy")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,29 +223,6 @@ android {
|
|||
path = file("../../../CMakeLists.txt")
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments(
|
||||
"-DENABLE_QT=0", // Don't use QT
|
||||
"-DENABLE_SDL2=0", // Don't use SDL
|
||||
"-DENABLE_WEB_SERVICE=1", // Enable web service
|
||||
"-DENABLE_OPENSSL=ON",
|
||||
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
||||
"-DYUZU_USE_CPM=ON",
|
||||
"-DCPMUTIL_FORCE_BUNDLED=ON",
|
||||
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
|
||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
||||
"-DBUILD_TESTING=OFF",
|
||||
"-DYUZU_TESTS=OFF",
|
||||
"-DDYNARMIC_TESTS=OFF"
|
||||
)
|
||||
|
||||
abiFilters("arm64-v8a")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Delete>("ktlintReset", fun Delete.() {
|
||||
|
|
BIN
src/android/app/src/main/legacy/drawable/ic_icon_bg.png
Normal file
BIN
src/android/app/src/main/legacy/drawable/ic_icon_bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
src/android/app/src/main/legacy/drawable/ic_icon_bg_orig.png
Normal file
BIN
src/android/app/src/main/legacy/drawable/ic_icon_bg_orig.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 438 KiB |
|
@ -180,6 +180,7 @@
|
|||
<item>@string/resolution_half</item>
|
||||
<item>@string/resolution_three_quarter</item>
|
||||
<item>@string/resolution_one</item>
|
||||
<item>@string/resolution_five_quarter</item>
|
||||
<item>@string/resolution_three_half</item>
|
||||
<item>@string/resolution_two</item>
|
||||
<item>@string/resolution_three</item>
|
||||
|
@ -202,6 +203,7 @@
|
|||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<integer-array name="rendererVSyncValues">
|
||||
|
@ -251,12 +253,16 @@
|
|||
<item>@string/scaling_filter_nearest_neighbor</item>
|
||||
<item>@string/scaling_filter_bilinear</item>
|
||||
<item>@string/scaling_filter_bicubic</item>
|
||||
<item>@string/scaling_filter_zero_tangent</item>
|
||||
<item>@string/scaling_filter_bspline</item>
|
||||
<item>@string/scaling_filter_mitchell</item>
|
||||
<item>@string/scaling_filter_spline1</item>
|
||||
<item>@string/scaling_filter_gaussian</item>
|
||||
<item>@string/scaling_filter_lanczos</item>
|
||||
<item>@string/scaling_filter_scale_force</item>
|
||||
<item>@string/scaling_filter_fsr</item>
|
||||
<item>@string/scaling_filter_area</item>
|
||||
<item>@string/scaling_filter_mmpx</item>
|
||||
</string-array>
|
||||
|
||||
<integer-array name="rendererScalingFilterValues">
|
||||
|
@ -269,6 +275,10 @@
|
|||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="rendererAntiAliasingNames">
|
||||
|
|
|
@ -996,6 +996,7 @@
|
|||
<string name="resolution_half">0.5X (360p/540p)</string>
|
||||
<string name="resolution_three_quarter">0.75X (540p/810p)</string>
|
||||
<string name="resolution_one">1X (720p/1080p)</string>
|
||||
<string name="resolution_five_quarter">1.25X (900p/1350p)</string>
|
||||
<string name="resolution_three_half">1.5X (1080p/1620p)</string>
|
||||
<string name="resolution_two">2X (1440p/2160p) (Slow)</string>
|
||||
<string name="resolution_three">3X (2160p/3240p) (Slow)</string>
|
||||
|
@ -1017,6 +1018,10 @@
|
|||
<string name="scaling_filter_scale_force">ScaleForce</string>
|
||||
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
|
||||
<string name="scaling_filter_area">Area</string>
|
||||
<string name="scaling_filter_zero_tangent">Zero-Tangent</string>
|
||||
<string name="scaling_filter_bspline">B-Spline</string>
|
||||
<string name="scaling_filter_mitchell">Mitchell</string>
|
||||
<string name="scaling_filter_mmpx">MMPX</string>
|
||||
|
||||
<!-- Anti-Aliasing -->
|
||||
<string name="anti_aliasing_none">None</string>
|
||||
|
|
|
@ -247,14 +247,14 @@ if (ENABLE_CUBEB)
|
|||
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
if (ENABLE_SDL3)
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/sdl2_sink.cpp
|
||||
sink/sdl2_sink.h
|
||||
sink/sdl3_sink.cpp
|
||||
sink/sdl3_sink.h
|
||||
)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <atomic>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL3/SDL.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 "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
|
@ -39,37 +39,53 @@ public:
|
|||
system_channels = system_channels_;
|
||||
device_channels = device_channels_;
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
SDL_AudioSpec spec{};
|
||||
spec.freq = TargetSampleRate;
|
||||
spec.channels = static_cast<u8>(device_channels);
|
||||
spec.format = AUDIO_S16SYS;
|
||||
spec.samples = TargetSampleCount * 2;
|
||||
spec.callback = &SDLSinkStream::DataCallback;
|
||||
spec.userdata = this;
|
||||
spec.channels = static_cast<int>(device_channels);
|
||||
spec.format = SDL_AUDIO_S16;
|
||||
|
||||
SDL_AudioDeviceID device_id = 0;
|
||||
std::string device_name{output_device};
|
||||
bool capture{false};
|
||||
bool is_capture{false};
|
||||
|
||||
if (type == StreamType::In) {
|
||||
device_name = input_device;
|
||||
capture = true;
|
||||
is_capture = true;
|
||||
}
|
||||
|
||||
SDL_AudioSpec obtained;
|
||||
if (device_name.empty()) {
|
||||
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
|
||||
} else {
|
||||
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
|
||||
if (!device_name.empty()) {
|
||||
int count = 0;
|
||||
SDL_AudioDeviceID* devices = is_capture ? SDL_GetAudioRecordingDevices(&count)
|
||||
: SDL_GetAudioPlaybackDevices(&count);
|
||||
|
||||
if (devices) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const char* name = SDL_GetAudioDeviceName(devices[i]);
|
||||
if (name && device_name == name) {
|
||||
device_id = devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_free(devices);
|
||||
}
|
||||
}
|
||||
|
||||
if (device == 0) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
|
||||
if (device_id == 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
LOG_INFO(Service_Audio,
|
||||
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
||||
" samples {}",
|
||||
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
|
||||
LOG_INFO(Service_Audio, "Opening SDL stream with: rate {} channels {} (system channels {})",
|
||||
spec.freq, spec.channels, system_channels);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,13 +100,14 @@ public:
|
|||
* Finalize the sink stream.
|
||||
*/
|
||||
void Finalize() override {
|
||||
if (device == 0) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stop();
|
||||
SDL_ClearQueuedAudio(device);
|
||||
SDL_CloseAudioDevice(device);
|
||||
SDL_ClearAudioStream(stream);
|
||||
SDL_DestroyAudioStream(stream);
|
||||
stream = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,62 +117,80 @@ public:
|
|||
* Default false.
|
||||
*/
|
||||
void Start(bool resume = false) override {
|
||||
if (device == 0 || !paused) {
|
||||
if (!stream || !paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
paused = false;
|
||||
SDL_PauseAudioDevice(device, 0);
|
||||
SDL_ResumeAudioStreamDevice(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the sink stream.
|
||||
*/
|
||||
void Stop() override {
|
||||
if (device == 0 || paused) {
|
||||
if (!stream || paused) {
|
||||
return;
|
||||
}
|
||||
SignalPause();
|
||||
SDL_PauseAudioDevice(device, 1);
|
||||
SDL_PauseAudioStreamDevice(stream);
|
||||
paused = true;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Main callback from SDL. Either expects samples from us (audio render/audio out), or will
|
||||
* 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) {
|
||||
static void PlaybackCallback(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 num_frames{len / num_channels / sizeof(s16)};
|
||||
const std::size_t num_frames = additional_amount / (sizeof(s16) * frame_size);
|
||||
|
||||
if (impl->type == StreamType::In) {
|
||||
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
|
||||
num_frames * frame_size};
|
||||
impl->ProcessAudioIn(input_buffer, num_frames);
|
||||
} else {
|
||||
std::span<s16> output_buffer{reinterpret_cast<s16*>(stream), num_frames * frame_size};
|
||||
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
|
||||
if (num_frames == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<s16> buffer(num_frames * frame_size);
|
||||
impl->ProcessAudioOutAndRender(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_AudioDeviceID device{};
|
||||
SDL_AudioStream* stream{nullptr};
|
||||
};
|
||||
|
||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||
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());
|
||||
return;
|
||||
}
|
||||
|
@ -218,66 +253,31 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
|||
std::vector<std::string> device_list;
|
||||
|
||||
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());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const int device_count = SDL_GetNumAudioDevices(capture);
|
||||
for (int i = 0; i < device_count; ++i) {
|
||||
if (const char* name = SDL_GetAudioDeviceName(i, capture)) {
|
||||
device_list.emplace_back(name);
|
||||
int count = 0;
|
||||
SDL_AudioDeviceID* devices =
|
||||
capture ? SDL_GetAudioRecordingDevices(&count) : SDL_GetAudioPlaybackDevices(&count);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* REVERSION to 3833 - function GetSDLLatency() REINTRODUCED FROM 3833 - DIABLO 3 FIX */
|
||||
u32 GetSDLLatency() {
|
||||
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
|
||||
#include "audio_core/sink/cubeb_sink.h"
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
#include "audio_core/sink/sdl2_sink.h"
|
||||
#ifdef HAVE_SDL3
|
||||
#include "audio_core/sink/sdl3_sink.h"
|
||||
#endif
|
||||
#include "audio_core/sink/null_sink.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -71,9 +71,9 @@ constexpr SinkDetails sink_details[] = {
|
|||
&GetCubebLatency,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
SinkDetails{
|
||||
Settings::AudioEngine::Sdl2,
|
||||
Settings::AudioEngine::Sdl3,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
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
|
||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||
// 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);
|
||||
if (iter->latency() > TargetSampleCount * 3) {
|
||||
iter = find_backend(Settings::AudioEngine::Sdl2);
|
||||
iter = find_backend(Settings::AudioEngine::Sdl3);
|
||||
}
|
||||
#else
|
||||
iter = std::begin(sink_details);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2012 Gekko Emulator
|
||||
// SPDX-FileContributor: ShizZy <shizzy247@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
@ -30,7 +33,6 @@
|
|||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
using u8 = std::uint8_t; ///< 8-bit unsigned byte
|
||||
using u16 = std::uint16_t; ///< 16-bit unsigned short
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
|
|
|
@ -301,6 +301,10 @@ void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info)
|
|||
info.up_scale = 3;
|
||||
info.down_shift = 1;
|
||||
break;
|
||||
case ResolutionSetup::Res5_4X:
|
||||
info.up_scale = 5;
|
||||
info.down_shift = 2;
|
||||
break;
|
||||
case ResolutionSetup::Res2X:
|
||||
info.up_scale = 2;
|
||||
info.down_shift = 0;
|
||||
|
|
|
@ -320,11 +320,19 @@ struct Values {
|
|||
linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
|
||||
|
||||
// Renderer
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{
|
||||
linkage, RendererBackend::Vulkan,
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
||||
#if defined(__sun__) || defined(__managarm__)
|
||||
RendererBackend::OpenGL,
|
||||
#else
|
||||
RendererBackend::Vulkan,
|
||||
#endif
|
||||
"backend", Category::Renderer};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{
|
||||
linkage, ShaderBackend::SpirV,
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{linkage,
|
||||
#if defined(__sun__) || defined(__managarm__)
|
||||
ShaderBackend::Glsl,
|
||||
#else
|
||||
ShaderBackend::SpirV,
|
||||
#endif
|
||||
"shader_backend", Category::Renderer, Specialization::RuntimeList};
|
||||
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
|
||||
Specialization::RuntimeList};
|
||||
|
|
|
@ -92,11 +92,11 @@ struct EnumMetadata {
|
|||
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||
// canonicalizations
|
||||
// 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<>
|
||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||
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},
|
||||
};
|
||||
}
|
||||
|
@ -142,8 +142,8 @@ ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb, Memory_10Gb, Memory_12Gb)
|
|||
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||
ENUM(FullscreenMode, Borderless, Exclusive);
|
||||
ENUM(NvdecEmulation, Off, Cpu, Gpu);
|
||||
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Spline1, Gaussian, Lanczos, ScaleForce, Fsr, Area, MaxEnum);
|
||||
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res5_4X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, ZeroTangent, BSpline, Mitchell, Spline1, Gaussian, Lanczos, ScaleForce, Fsr, Area, Mmpx, MaxEnum);
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
ENUM(ConsoleMode, Handheld, Docked);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
@ -18,9 +17,8 @@
|
|||
#else
|
||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
|
@ -93,33 +91,35 @@ void SetCurrentThreadName(const char* name) {
|
|||
#else // !MSVC_VER, so must be POSIX threads
|
||||
|
||||
// MinGW with the POSIX threading model does not support pthread_setname_np
|
||||
#if !defined(_WIN32) || defined(_MSC_VER)
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
// See for reference
|
||||
// https://gitlab.freedesktop.org/mesa/mesa/-/blame/main/src/util/u_thread.c?ref_type=heads#L75
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np(name);
|
||||
#elif defined(__HAIKU__)
|
||||
rename_thread(find_thread(NULL), name);
|
||||
#elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif defined(__NetBSD__)
|
||||
pthread_setname_np(pthread_self(), "%s", (void*)name);
|
||||
#elif defined(__linux__)
|
||||
// Linux limits thread names to 15 characters and will outright reject any
|
||||
// attempt to set a longer name with ERANGE.
|
||||
std::string truncated(name, (std::min)(strlen(name), static_cast<size_t>(15)));
|
||||
if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
|
||||
errno = e;
|
||||
LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());
|
||||
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun__) || defined(__glibc__) || defined(__managarm__)
|
||||
int ret = pthread_setname_np(pthread_self(), name);
|
||||
if (ret == ERANGE) {
|
||||
// Linux limits thread names to 15 characters and will outright reject any
|
||||
// attempt to set a longer name with ERANGE.
|
||||
char buf[16];
|
||||
size_t const len = std::min<size_t>(std::strlen(name), sizeof(buf) - 1);
|
||||
std::memcpy(buf, name, len);
|
||||
buf[len] = '\0';
|
||||
pthread_setname_np(pthread_self(), buf);
|
||||
}
|
||||
#elif !defined(_WIN32) || defined(_MSC_VER)
|
||||
// mingw stub
|
||||
(void)name;
|
||||
#else
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
// Do Nothing on MingW
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) {
|
|||
if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) {
|
||||
hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second);
|
||||
} else {
|
||||
hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params);
|
||||
hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging
|
||||
}
|
||||
|
||||
// Critical section for thread cleanup
|
||||
|
|
|
@ -38,9 +38,6 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca)
|
|||
|
||||
reader = std::make_shared<NcaReader>();
|
||||
if (Result rc = reader->Initialize(file, GetCryptoConfiguration(), GetNcaCompressionConfiguration()); R_FAILED(rc)) {
|
||||
if (rc != ResultInvalidNcaSignature) {
|
||||
LOG_ERROR(Loader, "File reader errored out during header read: {:#x}", rc.GetInnerValue());
|
||||
}
|
||||
status = Loader::ResultStatus::ErrorBadNCAHeader;
|
||||
return;
|
||||
}
|
||||
|
@ -85,7 +82,6 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca)
|
|||
for (s32 i = 0; i < fs_count; i++) {
|
||||
NcaFsHeaderReader header_reader;
|
||||
if (Result rc = fs.OpenStorage(&filesystems[i], &header_reader, i); R_FAILED(rc)) {
|
||||
LOG_DEBUG(Loader, "File reader errored out during read of section {}: {:#x}", i, rc.GetInnerValue());
|
||||
status = Loader::ResultStatus::ErrorBadNCAHeader;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
|
@ -1049,13 +1049,11 @@ Result NcaFileSystemDriver::CreatePatchMetaStorage(
|
|||
ASSERT(out_aes_ctr_ex_meta != nullptr);
|
||||
ASSERT(out_indirect_meta != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
//ASSERT(patch_info.HasAesCtrExTable());
|
||||
//ASSERT(patch_info.HasIndirectTable());
|
||||
ASSERT(Common::IsAligned<s64>(patch_info.aes_ctr_ex_size, NcaHeader::XtsBlockSize));
|
||||
|
||||
// Validate patch info extents.
|
||||
R_UNLESS(patch_info.indirect_size > 0, ResultInvalidNcaPatchInfoIndirectSize);
|
||||
R_UNLESS(patch_info.aes_ctr_ex_size >= 0, ResultInvalidNcaPatchInfoAesCtrExSize);
|
||||
R_UNLESS(patch_info.aes_ctr_ex_size >= 0 && patch_info.HasAesCtrExTable(), ResultInvalidNcaPatchInfoAesCtrExSize);
|
||||
R_UNLESS(patch_info.indirect_size > 0 && patch_info.HasIndirectTable(), ResultInvalidNcaPatchInfoIndirectSize);
|
||||
R_UNLESS(patch_info.indirect_size + patch_info.indirect_offset <= patch_info.aes_ctr_ex_offset,
|
||||
ResultInvalidNcaPatchInfoAesCtrExOffset);
|
||||
R_UNLESS(patch_info.aes_ctr_ex_offset + patch_info.aes_ctr_ex_size <=
|
||||
|
@ -1333,10 +1331,30 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl(
|
|||
R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset,
|
||||
ResultRomNcaInvalidIntegrityLayerInfoOffset);
|
||||
}
|
||||
storage_info[level_hash_info.max_layers - 1]
|
||||
= std::make_shared<OffsetVfsFile>(std::move(base_storage),
|
||||
layer_info.size,
|
||||
last_layer_info_offset);
|
||||
|
||||
switch (level_hash_info.max_layers - 1) {
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::MasterStorage:
|
||||
storage_info.SetMasterHashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::Layer1Storage:
|
||||
storage_info.SetLayer1HashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::Layer2Storage:
|
||||
storage_info.SetLayer2HashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::Layer3Storage:
|
||||
storage_info.SetLayer3HashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::Layer4Storage:
|
||||
storage_info.SetLayer4HashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::Layer5Storage:
|
||||
storage_info.SetLayer5HashStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
case FileSys::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation::DataStorage:
|
||||
storage_info.SetDataStorage(std::make_shared<OffsetVfsFile>(std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
break;
|
||||
}
|
||||
|
||||
// Make the integrity romfs storage.
|
||||
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -129,10 +128,6 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
|
|||
|
||||
std::string out = GetSaveDataSpaceIdPath(space);
|
||||
|
||||
LOG_INFO(Common_Filesystem, "Save ID: {:016X}", save_id);
|
||||
LOG_INFO(Common_Filesystem, "User ID[1]: {:016X}", user_id[1]);
|
||||
LOG_INFO(Common_Filesystem, "User ID[0]: {:016X}", user_id[0]);
|
||||
|
||||
switch (type) {
|
||||
case SaveDataType::System:
|
||||
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "core/frontend/applets/applet.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
|
||||
|
|
|
@ -4,13 +4,17 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/fs_types.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include <ranges>
|
||||
#include "common/settings.h"
|
||||
|
@ -90,6 +94,11 @@ bool ProfileManager::RemoveProfileAtIndex(std::size_t index) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ProfileManager::RemoveAllProfiles()
|
||||
{
|
||||
profiles = {};
|
||||
}
|
||||
|
||||
/// Helper function to register a user to the system
|
||||
Result ProfileManager::AddUser(const ProfileInfo& user) {
|
||||
if (!AddToProfiles(user)) {
|
||||
|
@ -259,8 +268,9 @@ void ProfileManager::CloseUser(UUID uuid) {
|
|||
/// Gets all valid user ids on the system
|
||||
UserIDArray ProfileManager::GetAllUsers() const {
|
||||
UserIDArray output{};
|
||||
std::ranges::transform(profiles, output.begin(),
|
||||
[](const ProfileInfo& p) { return p.user_uuid; });
|
||||
std::ranges::transform(profiles, output.begin(), [](const ProfileInfo& p) {
|
||||
return p.user_uuid;
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -387,18 +397,19 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase&
|
|||
void ProfileManager::ParseUserSaveFile() {
|
||||
const auto save_path(FS::GetEdenPath(FS::EdenPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH /
|
||||
"profiles.dat");
|
||||
|
||||
const FS::IOFile save(save_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile);
|
||||
|
||||
if (!save.IsOpen()) {
|
||||
LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new "
|
||||
"user 'eden' with random UUID.");
|
||||
"user 'Eden' with random UUID.");
|
||||
return;
|
||||
}
|
||||
|
||||
ProfileDataRaw data;
|
||||
if (!save.ReadObject(data)) {
|
||||
LOG_WARNING(Service_ACC, "profiles.dat is smaller than expected... Generating new user "
|
||||
"'eden' with random UUID.");
|
||||
"'Eden' with random UUID.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -471,6 +482,79 @@ void ProfileManager::WriteUserSaveFile() {
|
|||
is_save_needed = false;
|
||||
}
|
||||
|
||||
void ProfileManager::ResetUserSaveFile()
|
||||
{
|
||||
RemoveAllProfiles();
|
||||
ParseUserSaveFile();
|
||||
}
|
||||
|
||||
std::vector<std::string> ProfileManager::FindOrphanedProfiles()
|
||||
{
|
||||
std::vector<std::string> good_uuids;
|
||||
|
||||
for (const ProfileInfo& p : profiles) {
|
||||
std::string uuid_string = [p]() -> std::string {
|
||||
auto uuid = p.user_uuid;
|
||||
|
||||
// "ignore" invalid uuids
|
||||
if (uuid.IsInvalid()) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
auto user_id = uuid.AsU128();
|
||||
|
||||
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
|
||||
}();
|
||||
|
||||
good_uuids.emplace_back(uuid_string);
|
||||
}
|
||||
|
||||
// TODO: fetch save_id programmatically
|
||||
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
|
||||
/ "user/save/0000000000000000";
|
||||
|
||||
std::vector<std::string> orphaned_profiles;
|
||||
|
||||
Common::FS::IterateDirEntries(
|
||||
path,
|
||||
[&good_uuids, &orphaned_profiles](const std::filesystem::directory_entry& entry) -> bool {
|
||||
const std::string uuid = entry.path().stem().string();
|
||||
|
||||
// first off, we should always clear empty profiles
|
||||
// 99% of the time these are useless. If not, they are recreated anyways...
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
const auto is_empty = [&entry]() -> bool {
|
||||
try {
|
||||
for (const auto& file : fs::recursive_directory_iterator(entry.path())) {
|
||||
if (file.is_regular_file()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
// if we get an error--no worries, just pretend it's not empty
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (!is_empty) {
|
||||
fs::remove_all(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if profiles.dat contains the UUID--all good
|
||||
// if not--it's an orphaned profile and should be resolved by the user
|
||||
if (std::find(good_uuids.begin(), good_uuids.end(), uuid) == good_uuids.end()) {
|
||||
orphaned_profiles.emplace_back(uuid);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
Common::FS::DirEntryFilter::Directory);
|
||||
|
||||
return orphaned_profiles;
|
||||
}
|
||||
|
||||
void ProfileManager::SetUserPosition(u64 position, Common::UUID uuid) {
|
||||
auto idxOpt = GetUserIndex(uuid);
|
||||
if (!idxOpt)
|
||||
|
|
|
@ -103,10 +103,15 @@ public:
|
|||
|
||||
void WriteUserSaveFile();
|
||||
|
||||
void ResetUserSaveFile();
|
||||
|
||||
std::vector<std::string> FindOrphanedProfiles();
|
||||
|
||||
private:
|
||||
void ParseUserSaveFile();
|
||||
std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile);
|
||||
bool RemoveProfileAtIndex(std::size_t index);
|
||||
void RemoveAllProfiles();
|
||||
|
||||
bool is_save_needed{};
|
||||
std::array<ProfileInfo, MAX_USERS> profiles{};
|
||||
|
|
|
@ -53,6 +53,19 @@ enum class NetDbError : s32 {
|
|||
NoData = 4,
|
||||
};
|
||||
|
||||
static const constexpr std::array blockedDomains = {"srv.nintendo.net",
|
||||
"battle.net",
|
||||
"microsoft.com",
|
||||
"mojang.com",
|
||||
"xboxlive.com",
|
||||
"minecraftservices.com"};
|
||||
|
||||
static bool IsBlockedHost(const std::string& host) {
|
||||
return std::any_of(
|
||||
blockedDomains.begin(), blockedDomains.end(),
|
||||
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||
}
|
||||
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
|
@ -154,7 +167,7 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
|||
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
|
||||
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (host.find("srv.nintendo.net") != std::string::npos) {
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
@ -271,7 +284,7 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
|||
const std::string host = Common::StringFromBuffer(host_buffer);
|
||||
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (host.find("srv.nintendo.net") != std::string::npos) {
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
@ -359,5 +372,4 @@ void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) {
|
|||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(0); // bsd errno
|
||||
}
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -5,6 +8,8 @@
|
|||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <fmt/printf.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
|
|
7
src/dynarmic/externals/cpmfile.json
vendored
7
src/dynarmic/externals/cpmfile.json
vendored
|
@ -1,9 +1,10 @@
|
|||
{
|
||||
"biscuit": {
|
||||
"version": "0.9.1",
|
||||
"repo": "lioncash/biscuit",
|
||||
"sha": "76b0be8dae",
|
||||
"hash": "47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489"
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
||||
"version": "0.9.1",
|
||||
"git_version": "0.19.0"
|
||||
},
|
||||
"mcl": {
|
||||
"version": "0.1.12",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
include(TargetArchitectureSpecificSources)
|
||||
|
||||
add_library(dynarmic
|
||||
add_library(dynarmic STATIC
|
||||
backend/block_range_information.cpp
|
||||
backend/block_range_information.h
|
||||
backend/exception_handler.h
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// TODO(crueter): This is identical to root common_types.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <array>
|
||||
|
||||
using u8 = std::uint8_t; ///< 8-bit unsigned byte
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2020 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
|
@ -34,6 +37,8 @@ enum class OptimizationFlag : std::uint32_t {
|
|||
MiscIROpt = 0x00000020,
|
||||
/// Optimize for code speed rather than for code size (this serves well for tight loops)
|
||||
CodeSpeed = 0x00000040,
|
||||
/// Disable verification passes
|
||||
DisableVerification = 0x00000080,
|
||||
|
||||
/// This is an UNSAFE optimization that reduces accuracy of fused multiply-add operations.
|
||||
/// This unfuses fused instructions to improve performance on host CPUs without FMA support.
|
||||
|
|
|
@ -1491,9 +1491,9 @@ void Optimize(IR::Block& block, const A32::UserConfig& conf, const Optimization:
|
|||
Optimization::DeadCodeElimination(block);
|
||||
}
|
||||
Optimization::IdentityRemovalPass(block);
|
||||
//if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||
Optimization::VerificationPass(block);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
void Optimize(IR::Block& block, const A64::UserConfig& conf, const Optimization::PolyfillOptions& polyfill_options) {
|
||||
|
@ -1511,9 +1511,9 @@ void Optimize(IR::Block& block, const A64::UserConfig& conf, const Optimization:
|
|||
if (conf.HasOptimization(OptimizationFlag::MiscIROpt)) [[likely]] {
|
||||
Optimization::A64MergeInterpretBlocksPass(block, conf.callbacks);
|
||||
}
|
||||
//if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||
Optimization::VerificationPass(block);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Optimization
|
||||
|
|
|
@ -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-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) {
|
||||
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));
|
||||
void(FS::CreateParentDir(config_loc));
|
||||
SetUpIni();
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -5,6 +8,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
|
|
@ -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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -47,7 +49,7 @@ else()
|
|||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
if (ENABLE_SDL3)
|
||||
target_sources(input_common PRIVATE
|
||||
drivers/joycon.cpp
|
||||
drivers/joycon.h
|
||||
|
@ -73,8 +75,8 @@ if (ENABLE_SDL2)
|
|||
helpers/joycon_protocol/rumble.cpp
|
||||
helpers/joycon_protocol/rumble.h
|
||||
)
|
||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
target_link_libraries(input_common PRIVATE SDL3::SDL3)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL3)
|
||||
endif()
|
||||
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -6,7 +8,7 @@
|
|||
#include <array>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <SDL_hidapi.h>
|
||||
#include <SDL3/SDL_hidapi.h>
|
||||
|
||||
#include "input_common/input_engine.h"
|
||||
|
||||
|
|
|
@ -8,55 +8,50 @@
|
|||
#include "common/param_package.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "input_common/drivers/sdl_driver.h"
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
namespace {
|
||||
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::memcpy(data.data(), guid.data, sizeof(data));
|
||||
// Clear controller name crc
|
||||
std::memset(data.data() + 2, 0, sizeof(u16));
|
||||
return Common::UUID{data};
|
||||
}
|
||||
} // 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);
|
||||
|
||||
sdl_state->HandleGameControllerEvent(*event);
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
class SDLJoystick {
|
||||
public:
|
||||
SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick,
|
||||
SDL_GameController* game_controller)
|
||||
: guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
|
||||
sdl_controller{game_controller, &SDL_GameControllerClose} {
|
||||
SDLJoystick(Common::UUID guid_, int port_, SDL_Joystick* joystick, SDL_Gamepad* gamepad)
|
||||
: guid{guid_}, port{port_}, sdl_joystick{joystick, &SDL_CloseJoystick},
|
||||
sdl_gamepad{gamepad, &SDL_CloseGamepad} {
|
||||
EnableMotion();
|
||||
}
|
||||
|
||||
void EnableMotion() {
|
||||
if (!sdl_controller) {
|
||||
if (!sdl_gamepad) {
|
||||
return;
|
||||
}
|
||||
SDL_GameController* controller = sdl_controller.get();
|
||||
SDL_Gamepad* gamepad = sdl_gamepad.get();
|
||||
if (HasMotion()) {
|
||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_FALSE);
|
||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_FALSE);
|
||||
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, false);
|
||||
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_GYRO, false);
|
||||
}
|
||||
has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE;
|
||||
has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE;
|
||||
has_accel = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_ACCEL);
|
||||
has_gyro = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_GYRO);
|
||||
if (has_accel) {
|
||||
SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
|
||||
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, true);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool UpdateMotion(SDL_ControllerSensorEvent event) {
|
||||
bool UpdateMotion(SDL_GamepadSensorEvent event) {
|
||||
constexpr float gravity_constant = 9.80665f;
|
||||
std::scoped_lock lock{mutex};
|
||||
const u64 time_difference = event.timestamp - last_motion_update;
|
||||
|
@ -84,25 +79,22 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Ignore duplicated timestamps
|
||||
if (time_difference == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Motion data is invalid
|
||||
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) {
|
||||
if (motion_error_count++ < 200) {
|
||||
return false;
|
||||
}
|
||||
// Try restarting the sensor
|
||||
motion_error_count = 0;
|
||||
EnableMotion();
|
||||
return false;
|
||||
}
|
||||
|
||||
motion_error_count = 0;
|
||||
motion.delta_timestamp = time_difference * 1000;
|
||||
motion.delta_timestamp = time_difference;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -116,13 +108,13 @@ public:
|
|||
constexpr f32 low_width_sensitivity_limit = 400.0f;
|
||||
constexpr f32 high_start_sensitivity_limit = 200.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;
|
||||
if (vibration.low_frequency > low_start_sensitivity_limit) {
|
||||
low_frequency_scale =
|
||||
(std::max)(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
|
||||
low_width_sensitivity_limit,
|
||||
0.3f);
|
||||
low_width_sensitivity_limit,
|
||||
0.3f);
|
||||
}
|
||||
f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
|
||||
|
||||
|
@ -130,31 +122,29 @@ public:
|
|||
if (vibration.high_frequency > high_start_sensitivity_limit) {
|
||||
high_frequency_scale =
|
||||
(std::max)(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
|
||||
high_width_sensitivity_limit,
|
||||
0.3f);
|
||||
high_width_sensitivity_limit,
|
||||
0.3f);
|
||||
}
|
||||
f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
|
||||
|
||||
if (sdl_controller) {
|
||||
return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude),
|
||||
rumble_max_duration_ms) != -1;
|
||||
if (sdl_gamepad) {
|
||||
return SDL_RumbleGamepad(sdl_gamepad.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude), rumble_max_duration_ms);
|
||||
} else if (sdl_joystick) {
|
||||
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude),
|
||||
rumble_max_duration_ms) != -1;
|
||||
return SDL_RumbleJoystick(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
||||
static_cast<u16>(high_amplitude), rumble_max_duration_ms);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasHDRumble() const {
|
||||
if (sdl_controller) {
|
||||
const auto type = SDL_GameControllerGetType(sdl_controller.get());
|
||||
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
|
||||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
|
||||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
|
||||
(type == SDL_CONTROLLER_TYPE_PS5);
|
||||
if (sdl_gamepad) {
|
||||
const auto type = SDL_GetGamepadType(sdl_gamepad.get());
|
||||
return (type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO) ||
|
||||
(type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
|
||||
(type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
|
||||
(type == SDL_GAMEPAD_TYPE_PS5);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -172,9 +162,6 @@ public:
|
|||
return is_vibration_tested;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Pad identifier of the joystick
|
||||
*/
|
||||
const PadIdentifier GetPadIdentifier() const {
|
||||
return {
|
||||
.guid = guid,
|
||||
|
@ -183,16 +170,10 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The guid of the joystick
|
||||
*/
|
||||
const Common::UUID& GetGUID() const {
|
||||
return guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of joystick from the same type that were connected before this joystick
|
||||
*/
|
||||
int GetPort() const {
|
||||
return port;
|
||||
}
|
||||
|
@ -201,13 +182,13 @@ public:
|
|||
return sdl_joystick.get();
|
||||
}
|
||||
|
||||
SDL_GameController* GetSDLGameController() const {
|
||||
return sdl_controller.get();
|
||||
SDL_Gamepad* GetSDLGamepad() const {
|
||||
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_controller.reset(controller);
|
||||
sdl_gamepad.reset(gamepad);
|
||||
}
|
||||
|
||||
bool IsJoyconLeft() const {
|
||||
|
@ -232,49 +213,48 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) {
|
||||
Common::Input::BatteryLevel GetBatteryLevel(SDL_PowerState battery_level) {
|
||||
switch (battery_level) {
|
||||
case SDL_JOYSTICK_POWER_EMPTY:
|
||||
return Common::Input::BatteryLevel::Empty;
|
||||
case SDL_JOYSTICK_POWER_LOW:
|
||||
case SDL_POWERSTATE_ERROR:
|
||||
case SDL_POWERSTATE_UNKNOWN:
|
||||
return Common::Input::BatteryLevel::None;
|
||||
case SDL_POWERSTATE_ON_BATTERY:
|
||||
return Common::Input::BatteryLevel::Low;
|
||||
case SDL_JOYSTICK_POWER_MEDIUM:
|
||||
return Common::Input::BatteryLevel::Medium;
|
||||
case SDL_JOYSTICK_POWER_FULL:
|
||||
case SDL_JOYSTICK_POWER_MAX:
|
||||
return Common::Input::BatteryLevel::Full;
|
||||
case SDL_JOYSTICK_POWER_WIRED:
|
||||
case SDL_POWERSTATE_NO_BATTERY:
|
||||
return Common::Input::BatteryLevel::None;
|
||||
case SDL_POWERSTATE_CHARGING:
|
||||
return Common::Input::BatteryLevel::Charging;
|
||||
case SDL_JOYSTICK_POWER_UNKNOWN:
|
||||
case SDL_POWERSTATE_CHARGED:
|
||||
return Common::Input::BatteryLevel::Full;
|
||||
default:
|
||||
return Common::Input::BatteryLevel::None;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetControllerName() const {
|
||||
if (sdl_controller) {
|
||||
switch (SDL_GameControllerGetType(sdl_controller.get())) {
|
||||
case SDL_CONTROLLER_TYPE_XBOX360:
|
||||
if (sdl_gamepad) {
|
||||
switch (SDL_GetGamepadType(sdl_gamepad.get())) {
|
||||
case SDL_GAMEPAD_TYPE_XBOX360:
|
||||
return "Xbox 360 Controller";
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE:
|
||||
case SDL_GAMEPAD_TYPE_XBOXONE:
|
||||
return "Xbox One Controller";
|
||||
case SDL_CONTROLLER_TYPE_PS3:
|
||||
case SDL_GAMEPAD_TYPE_PS3:
|
||||
return "DualShock 3 Controller";
|
||||
case SDL_CONTROLLER_TYPE_PS4:
|
||||
case SDL_GAMEPAD_TYPE_PS4:
|
||||
return "DualShock 4 Controller";
|
||||
case SDL_CONTROLLER_TYPE_PS5:
|
||||
case SDL_GAMEPAD_TYPE_PS5:
|
||||
return "DualSense Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const auto name = SDL_GameControllerName(sdl_controller.get());
|
||||
const auto name = SDL_GetGamepadName(sdl_gamepad.get());
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdl_joystick) {
|
||||
const auto name = SDL_JoystickName(sdl_joystick.get());
|
||||
const auto name = SDL_GetJoystickName(sdl_joystick.get());
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
|
@ -286,8 +266,8 @@ public:
|
|||
private:
|
||||
Common::UUID guid;
|
||||
int port;
|
||||
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
|
||||
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
|
||||
std::unique_ptr<SDL_Joystick, decltype(&SDL_CloseJoystick)> sdl_joystick;
|
||||
std::unique_ptr<SDL_Gamepad, decltype(&SDL_CloseGamepad)> sdl_gamepad;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
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) {
|
||||
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
|
||||
auto sdl_joystick = SDL_GetJoystickFromID(sdl_id);
|
||||
const auto guid = GetGUID(sdl_joystick);
|
||||
|
||||
std::scoped_lock lock{joystick_map_mutex};
|
||||
|
@ -345,16 +325,16 @@ std::shared_ptr<SDLJoystick> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl
|
|||
return *vec_it;
|
||||
}
|
||||
|
||||
void SDLDriver::InitJoystick(int joystick_index) {
|
||||
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
|
||||
SDL_GameController* sdl_gamecontroller = nullptr;
|
||||
void SDLDriver::InitJoystick(SDL_JoystickID joystick_id) {
|
||||
SDL_Joystick* sdl_joystick = SDL_OpenJoystick(joystick_id);
|
||||
SDL_Gamepad* sdl_gamepad = nullptr;
|
||||
|
||||
if (SDL_IsGameController(joystick_index)) {
|
||||
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
|
||||
if (SDL_IsGamepad(joystick_id)) {
|
||||
sdl_gamepad = SDL_OpenGamepad(joystick_id);
|
||||
}
|
||||
|
||||
if (!sdl_joystick) {
|
||||
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
|
||||
LOG_ERROR(Input, "Failed to open joystick {}", joystick_id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -363,23 +343,23 @@ void SDLDriver::InitJoystick(int joystick_index) {
|
|||
if (Settings::values.enable_joycon_driver) {
|
||||
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e &&
|
||||
(guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) {
|
||||
LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
|
||||
SDL_JoystickClose(sdl_joystick);
|
||||
LOG_WARNING(Input, "Preferring joycon driver for device ID {}", joystick_id);
|
||||
SDL_CloseJoystick(sdl_joystick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings::values.enable_procon_driver) {
|
||||
if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && guid.uuid[8] == 0x09) {
|
||||
LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index);
|
||||
SDL_JoystickClose(sdl_joystick);
|
||||
LOG_WARNING(Input, "Preferring joycon driver for device ID {}", joystick_id);
|
||||
SDL_CloseJoystick(sdl_joystick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::scoped_lock lock{joystick_map_mutex};
|
||||
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());
|
||||
joystick->EnableMotion();
|
||||
joystick_map[guid].emplace_back(std::move(joystick));
|
||||
|
@ -392,13 +372,13 @@ void SDLDriver::InitJoystick(int joystick_index) {
|
|||
[](const auto& joystick) { return !joystick->GetSDLJoystick(); });
|
||||
|
||||
if (joystick_it != joystick_guid_list.end()) {
|
||||
(*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
|
||||
(*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamepad);
|
||||
(*joystick_it)->EnableMotion();
|
||||
return;
|
||||
}
|
||||
|
||||
const int port = static_cast<int>(joystick_guid_list.size());
|
||||
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
|
||||
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamepad);
|
||||
PreSetController(joystick->GetPadIdentifier());
|
||||
joystick->EnableMotion();
|
||||
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);
|
||||
|
||||
std::scoped_lock lock{joystick_map_mutex};
|
||||
// This call to guid is safe since the joystick is guaranteed to be in the map
|
||||
const auto& joystick_guid_list = joystick_map[guid];
|
||||
const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
|
||||
[&sdl_joystick](const auto& joystick) {
|
||||
|
@ -428,56 +407,85 @@ void SDLDriver::PumpEvents() const {
|
|||
|
||||
void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
|
||||
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)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetButton(identifier, event.jbutton.button, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYBUTTONDOWN: {
|
||||
case SDL_EVENT_JOYSTICK_BUTTON_DOWN: {
|
||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetButton(identifier, event.jbutton.button, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYHATMOTION: {
|
||||
case SDL_EVENT_JOYSTICK_HAT_MOTION: {
|
||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetHatButton(identifier, event.jhat.hat, event.jhat.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYAXISMOTION: {
|
||||
case SDL_EVENT_JOYSTICK_AXIS_MOTION: {
|
||||
if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_CONTROLLERSENSORUPDATE: {
|
||||
if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
|
||||
if (joystick->UpdateMotion(event.csensor)) {
|
||||
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: {
|
||||
if (auto joystick = GetSDLJoystickBySDLID(event.gsensor.which)) {
|
||||
if (joystick->UpdateMotion(event.gsensor)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetMotion(identifier, 0, joystick->GetMotion());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYBATTERYUPDATED: {
|
||||
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED: {
|
||||
if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level));
|
||||
SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.state));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
|
||||
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
LOG_DEBUG(Input, "Gamepad removed with Instance_ID {}", event.gdevice.which);
|
||||
CloseJoystick(SDL_GetJoystickFromID(event.gdevice.which));
|
||||
break;
|
||||
case SDL_JOYDEVICEADDED:
|
||||
LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
|
||||
case SDL_EVENT_GAMEPAD_ADDED:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -489,24 +497,17 @@ void SDLDriver::CloseJoysticks() {
|
|||
}
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// Prevent SDL from adding undesired axis
|
||||
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
|
||||
|
||||
// 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_HINT_ACCELEROMETER_AS_JOYSTICK was removed in SDL3
|
||||
// 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
|
||||
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) {
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
|
||||
} 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");
|
||||
}
|
||||
|
||||
// Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
|
||||
if (Settings::values.enable_procon_driver) {
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
|
||||
} 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");
|
||||
// Share the same button mapping with non-Nintendo controllers
|
||||
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_HINT_GAMECONTROLLER_USE_BUTTON_LABELS was removed in SDL3
|
||||
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_GAMECONTROLLER) == 0;
|
||||
if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);
|
||||
if (start_thread && !SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) {
|
||||
LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError());
|
||||
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
|
||||
for (int i = 0; i < SDL_NumJoysticks(); ++i) {
|
||||
InitJoystick(i);
|
||||
|
||||
int num_joysticks;
|
||||
SDL_JoystickID* joysticks = SDL_GetJoysticks(&num_joysticks);
|
||||
if (joysticks) {
|
||||
for (int i = 0; i < num_joysticks; ++i) {
|
||||
InitJoystick(joysticks[i]);
|
||||
}
|
||||
SDL_free(joysticks);
|
||||
}
|
||||
}
|
||||
|
||||
SDLDriver::~SDLDriver() {
|
||||
CloseJoysticks();
|
||||
SDL_DelEventWatch(&SDLEventWatcher, this);
|
||||
SDL_RemoveEventWatch(&SDLEventWatcher, this);
|
||||
|
||||
initialized = false;
|
||||
if (start_thread) {
|
||||
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& joystick : value) {
|
||||
if (joystick->IsJoyconRight()) {
|
||||
|
@ -624,15 +622,12 @@ Common::Input::DriverResult SDLDriver::SetVibration(
|
|||
return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF;
|
||||
};
|
||||
|
||||
// Default exponential curve for rumble
|
||||
f32 factor = 0.35f;
|
||||
|
||||
// If vibration is set as a linear output use a flatter value
|
||||
if (vibration.type == Common::Input::VibrationAmplificationType::Linear) {
|
||||
factor = 0.5f;
|
||||
}
|
||||
|
||||
// Amplitude for HD rumble needs no modification
|
||||
if (joystick->HasHDRumble()) {
|
||||
factor = 1.0f;
|
||||
}
|
||||
|
@ -677,10 +672,7 @@ bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) {
|
|||
return joystick->HasVibration();
|
||||
}
|
||||
|
||||
// First vibration might fail
|
||||
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));
|
||||
|
||||
if (!joystick->RumblePlay(zero_vibration)) {
|
||||
|
@ -760,17 +752,17 @@ Common::ParamPackage SDLDriver::BuildMotionParam(int port, const Common::UUID& g
|
|||
}
|
||||
|
||||
Common::ParamPackage SDLDriver::BuildParamPackageForBinding(
|
||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const {
|
||||
switch (binding.bindType) {
|
||||
case SDL_CONTROLLER_BINDTYPE_NONE:
|
||||
int port, const Common::UUID& guid, const SDL_GamepadBinding& binding) const {
|
||||
switch (binding.input_type) {
|
||||
case SDL_GAMEPAD_BINDTYPE_NONE:
|
||||
break;
|
||||
case SDL_CONTROLLER_BINDTYPE_AXIS:
|
||||
return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
|
||||
case SDL_CONTROLLER_BINDTYPE_BUTTON:
|
||||
return BuildButtonParamPackageForButton(port, guid, binding.value.button);
|
||||
case SDL_CONTROLLER_BINDTYPE_HAT:
|
||||
return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
|
||||
static_cast<u8>(binding.value.hat.hat_mask));
|
||||
case SDL_GAMEPAD_BINDTYPE_AXIS:
|
||||
return BuildAnalogParamPackageForButton(port, guid, binding.input.axis.axis);
|
||||
case SDL_GAMEPAD_BINDTYPE_BUTTON:
|
||||
return BuildButtonParamPackageForButton(port, guid, binding.input.button);
|
||||
case SDL_GAMEPAD_BINDTYPE_HAT:
|
||||
return BuildHatParamPackageForButton(port, guid, binding.input.hat.hat,
|
||||
static_cast<u8>(binding.input.hat.hat_mask));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -797,28 +789,23 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
|
|||
}
|
||||
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
|
||||
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
auto* gamepad = joystick->GetSDLGamepad();
|
||||
if (gamepad == nullptr) {
|
||||
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;
|
||||
|
||||
switch_to_sdl_button = GetDefaultButtonBinding(joystick);
|
||||
|
||||
// Add the missing bindings for ZL/ZR
|
||||
static constexpr ZButtonBindings switch_to_sdl_axis{{
|
||||
{Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
|
||||
{Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
|
||||
{Settings::NativeButton::ZL, SDL_GAMEPAD_AXIS_LEFT_TRIGGER},
|
||||
{Settings::NativeButton::ZR, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER},
|
||||
}};
|
||||
|
||||
// Parameters contain two joysticks return dual
|
||||
if (params.Has("guid2")) {
|
||||
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,
|
||||
switch_to_sdl_axis);
|
||||
}
|
||||
|
@ -829,42 +816,41 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
|
|||
|
||||
ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
||||
const std::shared_ptr<SDLJoystick>& joystick) const {
|
||||
// Default SL/SR mapping for other controllers
|
||||
auto sll_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto srl_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||
auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||
auto sll_button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
|
||||
auto srl_button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
|
||||
auto slr_button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
|
||||
auto srr_button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
|
||||
|
||||
if (joystick->IsJoyconLeft()) {
|
||||
sll_button = SDL_CONTROLLER_BUTTON_PADDLE2;
|
||||
srl_button = SDL_CONTROLLER_BUTTON_PADDLE4;
|
||||
sll_button = SDL_GAMEPAD_BUTTON_LEFT_PADDLE1;
|
||||
srl_button = SDL_GAMEPAD_BUTTON_LEFT_PADDLE2;
|
||||
}
|
||||
if (joystick->IsJoyconRight()) {
|
||||
slr_button = SDL_CONTROLLER_BUTTON_PADDLE3;
|
||||
srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
|
||||
slr_button = SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2;
|
||||
srr_button = SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1;
|
||||
}
|
||||
|
||||
return {
|
||||
std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
|
||||
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
|
||||
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
|
||||
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
|
||||
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
|
||||
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||
{Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||
{Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
|
||||
{Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
|
||||
{Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
|
||||
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
|
||||
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
||||
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
||||
std::pair{Settings::NativeButton::A, SDL_GAMEPAD_BUTTON_EAST},
|
||||
{Settings::NativeButton::B, SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{Settings::NativeButton::X, SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{Settings::NativeButton::Y, SDL_GAMEPAD_BUTTON_WEST},
|
||||
{Settings::NativeButton::LStick, SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{Settings::NativeButton::RStick, SDL_GAMEPAD_BUTTON_RIGHT_STICK},
|
||||
{Settings::NativeButton::L, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
||||
{Settings::NativeButton::R, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
||||
{Settings::NativeButton::Plus, SDL_GAMEPAD_BUTTON_START},
|
||||
{Settings::NativeButton::Minus, SDL_GAMEPAD_BUTTON_BACK},
|
||||
{Settings::NativeButton::DLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||
{Settings::NativeButton::DUp, SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||
{Settings::NativeButton::DRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||
{Settings::NativeButton::DDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||
{Settings::NativeButton::SLLeft, sll_button},
|
||||
{Settings::NativeButton::SRLeft, srl_button},
|
||||
{Settings::NativeButton::SLRight, slr_button},
|
||||
{Settings::NativeButton::SRRight, srr_button},
|
||||
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
|
||||
{Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
|
||||
{Settings::NativeButton::Home, SDL_GAMEPAD_BUTTON_GUIDE},
|
||||
{Settings::NativeButton::Screenshot, SDL_GAMEPAD_BUTTON_MISC1},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -873,16 +859,25 @@ ButtonMapping SDLDriver::GetSingleControllerMapping(
|
|||
const ZButtonBindings& switch_to_sdl_axis) const {
|
||||
ButtonMapping mapping;
|
||||
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) {
|
||||
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(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||
}
|
||||
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(
|
||||
switch_button,
|
||||
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 {
|
||||
ButtonMapping mapping;
|
||||
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) {
|
||||
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(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||
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(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||
}
|
||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||
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(
|
||||
switch_button,
|
||||
BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding));
|
||||
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(
|
||||
switch_button,
|
||||
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 joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
auto* gamepad = joystick->GetSDLGamepad();
|
||||
if (gamepad == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
AnalogMapping mapping = {};
|
||||
const auto& binding_left_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
const auto& binding_left_y =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||
// We need to work with the underlying joystick directly
|
||||
SDL_Joystick* sdl_joystick = SDL_GetGamepadJoystick(gamepad);
|
||||
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")) {
|
||||
const auto identifier = joystick2->GetPadIdentifier();
|
||||
PreSetController(identifier);
|
||||
PreSetAxis(identifier, binding_left_x.value.axis);
|
||||
PreSetAxis(identifier, binding_left_y.value.axis);
|
||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
|
||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
|
||||
PreSetAxis(identifier, binding_left_x.input.axis.axis);
|
||||
PreSetAxis(identifier, binding_left_y.input.axis.axis);
|
||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.input.axis.axis);
|
||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.input.axis.axis);
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
||||
binding_left_y.value.axis,
|
||||
left_offset_x, left_offset_y));
|
||||
BuildParamPackageForAnalog(
|
||||
identifier, binding_left_x.input.axis.axis,
|
||||
binding_left_y.input.axis.axis, left_offset_x, left_offset_y));
|
||||
} else {
|
||||
const auto identifier = joystick->GetPadIdentifier();
|
||||
PreSetController(identifier);
|
||||
PreSetAxis(identifier, binding_left_x.value.axis);
|
||||
PreSetAxis(identifier, binding_left_y.value.axis);
|
||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis);
|
||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.value.axis);
|
||||
PreSetAxis(identifier, binding_left_x.input.axis.axis);
|
||||
PreSetAxis(identifier, binding_left_y.input.axis.axis);
|
||||
const auto left_offset_x = -GetAxis(identifier, binding_left_x.input.axis.axis);
|
||||
const auto left_offset_y = GetAxis(identifier, binding_left_y.input.axis.axis);
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_left_x.value.axis,
|
||||
binding_left_y.value.axis,
|
||||
left_offset_x, left_offset_y));
|
||||
BuildParamPackageForAnalog(
|
||||
identifier, binding_left_x.input.axis.axis,
|
||||
binding_left_y.input.axis.axis, left_offset_x, left_offset_y));
|
||||
}
|
||||
const auto& binding_right_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
const auto& binding_right_y =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
|
||||
// For right stick
|
||||
SDL_GamepadBinding binding_right_x{};
|
||||
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();
|
||||
PreSetController(identifier);
|
||||
PreSetAxis(identifier, binding_right_x.value.axis);
|
||||
PreSetAxis(identifier, binding_right_y.value.axis);
|
||||
const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis);
|
||||
const auto right_offset_y = GetAxis(identifier, binding_right_y.value.axis);
|
||||
PreSetAxis(identifier, binding_right_x.input.axis.axis);
|
||||
PreSetAxis(identifier, binding_right_y.input.axis.axis);
|
||||
const auto right_offset_x = -GetAxis(identifier, binding_right_x.input.axis.axis);
|
||||
const auto right_offset_y = GetAxis(identifier, binding_right_y.input.axis.axis);
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::RStick,
|
||||
BuildParamPackageForAnalog(identifier, binding_right_x.value.axis,
|
||||
binding_right_y.value.axis, right_offset_x,
|
||||
right_offset_y));
|
||||
BuildParamPackageForAnalog(identifier, binding_right_x.input.axis.axis,
|
||||
binding_right_y.input.axis.axis,
|
||||
right_offset_x, right_offset_y));
|
||||
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 joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0));
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
auto* gamepad = joystick->GetSDLGamepad();
|
||||
if (gamepad == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1039,7 +1061,6 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p
|
|||
|
||||
Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const {
|
||||
if (params.Has("button")) {
|
||||
// TODO(German77): Find how to substitute the values for real button names
|
||||
return Common::Input::ButtonNames::Value;
|
||||
}
|
||||
if (params.Has("hat")) {
|
||||
|
@ -1097,29 +1118,27 @@ bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
|
|||
if (joystick == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto* controller = joystick->GetSDLGameController();
|
||||
if (controller == nullptr) {
|
||||
auto* gamepad = joystick->GetSDLGamepad();
|
||||
if (gamepad == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& axis_x = params.Get("axis_x", 0);
|
||||
const auto& axis_y = params.Get("axis_y", 0);
|
||||
const auto& binding_left_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
const auto& binding_right_x =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
const auto& binding_left_y =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
const auto& binding_right_y =
|
||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
// SDL_GetGamepadBindForAxis was removed in SDL3
|
||||
// Use hardcoded axis mappings for now
|
||||
const int binding_left_x = 0; // Left stick X
|
||||
const int binding_right_x = 2; // Right stick X
|
||||
const int binding_left_y = 1; // Left stick Y
|
||||
const int binding_right_y = 3; // Right stick Y
|
||||
|
||||
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;
|
||||
}
|
||||
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 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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -8,46 +10,33 @@
|
|||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "input_common/input_engine.h"
|
||||
|
||||
union SDL_Event;
|
||||
using SDL_GameController = struct _SDL_GameController;
|
||||
using SDL_Joystick = struct _SDL_Joystick;
|
||||
using SDL_JoystickID = s32;
|
||||
using SDL_Gamepad = struct SDL_Gamepad;
|
||||
using SDL_Joystick = struct SDL_Joystick;
|
||||
using SDL_JoystickID = Uint32;
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
class SDLJoystick;
|
||||
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
|
||||
using ZButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
||||
using ButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadButton>, 20>;
|
||||
using ZButtonBindings = std::array<std::pair<Settings::NativeButton::Values, SDL_GamepadAxis>, 2>;
|
||||
|
||||
class SDLDriver : public InputEngine {
|
||||
public:
|
||||
/// Initializes and registers SDL device factories
|
||||
explicit SDLDriver(std::string input_engine_);
|
||||
|
||||
/// Unregisters SDL device factories and shut them down.
|
||||
~SDLDriver() override;
|
||||
|
||||
void PumpEvents() const;
|
||||
|
||||
/// Handle SDL_Events for joysticks from SDL_PollEvent
|
||||
void HandleGameControllerEvent(const SDL_Event& event);
|
||||
|
||||
/// Get the nth joystick with the corresponding GUID
|
||||
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 std::string& guid, int port);
|
||||
|
||||
|
@ -69,59 +58,40 @@ public:
|
|||
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
|
||||
|
||||
private:
|
||||
void InitJoystick(int joystick_index);
|
||||
void InitJoystick(SDL_JoystickID joystick_id);
|
||||
void CloseJoystick(SDL_Joystick* sdl_joystick);
|
||||
|
||||
/// Needs to be called before SDL_QuitSubSystem.
|
||||
void CloseJoysticks();
|
||||
|
||||
/// Takes all vibrations from the queue and sends the command to the controller
|
||||
void SendVibrations();
|
||||
|
||||
Common::ParamPackage BuildAnalogParamPackageForButton(int port, const Common::UUID& guid,
|
||||
s32 axis, float value = 0.1f) const;
|
||||
Common::ParamPackage BuildButtonParamPackageForButton(int port, const Common::UUID& guid,
|
||||
s32 button) const;
|
||||
|
||||
Common::ParamPackage BuildHatParamPackageForButton(int port, const Common::UUID& guid, s32 hat,
|
||||
u8 value) const;
|
||||
|
||||
Common::ParamPackage BuildMotionParam(int port, const Common::UUID& guid) const;
|
||||
|
||||
Common::ParamPackage BuildParamPackageForBinding(
|
||||
int port, const Common::UUID& guid, const SDL_GameControllerButtonBind& binding) const;
|
||||
|
||||
Common::ParamPackage BuildParamPackageForBinding(int port, const Common::UUID& guid,
|
||||
const SDL_GamepadBinding& binding) const;
|
||||
Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
|
||||
int axis_y, float offset_x,
|
||||
float offset_y) const;
|
||||
|
||||
/// Returns the default button bindings list
|
||||
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,
|
||||
const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||
|
||||
/// Returns the button mappings from two different controllers
|
||||
ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
|
||||
const std::shared_ptr<SDLJoystick>& joystick2,
|
||||
const ButtonBindings& switch_to_sdl_button,
|
||||
const ZButtonBindings& switch_to_sdl_axis) const;
|
||||
|
||||
/// Returns true if the button is on the left joycon
|
||||
bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;
|
||||
|
||||
/// Queue of vibration request to controllers
|
||||
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::mutex joystick_map_mutex;
|
||||
|
||||
bool start_thread = false;
|
||||
std::atomic<bool> initialized = false;
|
||||
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -10,7 +12,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <SDL_hidapi.h>
|
||||
#include <SDL3/SDL_hidapi.h>
|
||||
|
||||
#include "common/bit_field.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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -22,7 +24,7 @@
|
|||
#ifdef HAVE_LIBUSB
|
||||
#include "input_common/drivers/gc_adapter.h"
|
||||
#endif
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
#include "input_common/drivers/joycon.h"
|
||||
#include "input_common/drivers/sdl_driver.h"
|
||||
#endif
|
||||
|
@ -87,7 +89,7 @@ struct InputSubsystem::Impl {
|
|||
#endif
|
||||
RegisterEngine("virtual_amiibo", virtual_amiibo);
|
||||
RegisterEngine("virtual_gamepad", virtual_gamepad);
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
RegisterEngine("sdl", sdl);
|
||||
RegisterEngine("joycon", joycon);
|
||||
#endif
|
||||
|
@ -121,7 +123,7 @@ struct InputSubsystem::Impl {
|
|||
#endif
|
||||
UnregisterEngine(virtual_amiibo);
|
||||
UnregisterEngine(virtual_gamepad);
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
UnregisterEngine(sdl);
|
||||
UnregisterEngine(joycon);
|
||||
#endif
|
||||
|
@ -151,7 +153,7 @@ struct InputSubsystem::Impl {
|
|||
#endif
|
||||
auto udp_devices = udp_client->GetInputDevices();
|
||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
auto joycon_devices = joycon->GetInputDevices();
|
||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||
auto sdl_devices = sdl->GetInputDevices();
|
||||
|
@ -186,7 +188,7 @@ struct InputSubsystem::Impl {
|
|||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client;
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl;
|
||||
}
|
||||
|
@ -277,7 +279,7 @@ struct InputSubsystem::Impl {
|
|||
if (engine == virtual_gamepad->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -298,7 +300,7 @@ struct InputSubsystem::Impl {
|
|||
gcadapter->BeginConfiguration();
|
||||
#endif
|
||||
udp_client->BeginConfiguration();
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
sdl->BeginConfiguration();
|
||||
joycon->BeginConfiguration();
|
||||
#endif
|
||||
|
@ -314,7 +316,7 @@ struct InputSubsystem::Impl {
|
|||
gcadapter->EndConfiguration();
|
||||
#endif
|
||||
udp_client->EndConfiguration();
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
sdl->EndConfiguration();
|
||||
joycon->EndConfiguration();
|
||||
#endif
|
||||
|
@ -322,7 +324,7 @@ struct InputSubsystem::Impl {
|
|||
|
||||
void PumpEvents() const {
|
||||
update_engine->PumpEvents();
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
sdl->PumpEvents();
|
||||
#endif
|
||||
}
|
||||
|
@ -347,7 +349,7 @@ struct InputSubsystem::Impl {
|
|||
std::shared_ptr<GCAdapter> gcadapter;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
#ifdef HAVE_SDL3
|
||||
std::shared_ptr<SDLDriver> sdl;
|
||||
std::shared_ptr<Joycons> joycon;
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ endif()
|
|||
|
||||
add_subdirectory(externals)
|
||||
|
||||
target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen)
|
||||
target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip)
|
||||
|
||||
if (NOT APPLE AND ENABLE_OPENGL)
|
||||
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
||||
|
|
2
src/qt_common/externals/CMakeLists.txt
vendored
2
src/qt_common/externals/CMakeLists.txt
vendored
|
@ -17,4 +17,4 @@ AddJsonPackage(quazip)
|
|||
|
||||
# frozen
|
||||
# TODO(crueter): Qt String Lookup
|
||||
AddJsonPackage(frozen)
|
||||
# AddJsonPackage(frozen)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qt_common/qt_game_util.h"
|
||||
#include "qt_content_util.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "frontend_common/content_manager.h"
|
||||
#include "frontend_common/firmware_manager.h"
|
||||
#include "qt_common/qt_common.h"
|
||||
|
@ -310,4 +312,40 @@ void VerifyInstalledContents() {
|
|||
}
|
||||
}
|
||||
|
||||
void FixProfiles()
|
||||
{
|
||||
// Reset user save files after config is initialized and migration is done.
|
||||
// Doing it at init time causes profiles to read from the wrong place entirely if NAND dir is not default
|
||||
// TODO: better solution
|
||||
system->GetProfileManager().ResetUserSaveFile();
|
||||
std::vector<std::string> orphaned = system->GetProfileManager().FindOrphanedProfiles();
|
||||
|
||||
// no orphaned dirs--all good :)
|
||||
if (orphaned.empty())
|
||||
return;
|
||||
|
||||
// otherwise, let the user know
|
||||
QString qorphaned;
|
||||
|
||||
// max. of 8 orphaned profiles is fair, I think
|
||||
// 33 = 32 (UUID) + 1 (\n)
|
||||
qorphaned.reserve(8 * 33);
|
||||
|
||||
for (const std::string& s : orphaned) {
|
||||
qorphaned += "\n" + QString::fromStdString(s);
|
||||
}
|
||||
|
||||
QtCommon::Frontend::Critical(
|
||||
tr("Orphaned Profiles Detected!"),
|
||||
tr("UNEXPECTED BAD THINGS MAY HAPPEN IF YOU DON'T READ THIS!\n"
|
||||
"Eden has detected the following save directories with no attached profile:\n"
|
||||
"%1\n\n"
|
||||
"Click \"OK\" to open your save folder and fix up your profiles.\n"
|
||||
"Hint: copy the contents of the largest or last-modified folder elsewhere, "
|
||||
"delete all orphaned profiles, and move your copied contents to the good profile.")
|
||||
.arg(qorphaned));
|
||||
|
||||
QtCommon::Game::OpenSaveFolder();
|
||||
}
|
||||
|
||||
} // namespace QtCommon::Content
|
||||
|
|
|
@ -45,5 +45,8 @@ void InstallKeys();
|
|||
// Content //
|
||||
void VerifyGameContents(const std::string &game_path);
|
||||
void VerifyInstalledContents();
|
||||
|
||||
// Profiles //
|
||||
void FixProfiles();
|
||||
}
|
||||
#endif // QT_CONTENT_UTIL_H
|
||||
|
|
|
@ -178,6 +178,12 @@ void OpenNANDFolder()
|
|||
OpenEdenFolder(Common::FS::EdenPath::NANDDir);
|
||||
}
|
||||
|
||||
void OpenSaveFolder()
|
||||
{
|
||||
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "user/save/0000000000000000";
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path.string())));
|
||||
}
|
||||
|
||||
void OpenSDMCFolder()
|
||||
{
|
||||
OpenEdenFolder(Common::FS::EdenPath::SDMCDir);
|
||||
|
@ -379,21 +385,21 @@ void RemoveCacheStorage(u64 program_id)
|
|||
}
|
||||
|
||||
// Metadata //
|
||||
void ResetMetadata()
|
||||
void ResetMetadata(bool show_message)
|
||||
{
|
||||
const QString title = tr("Reset Metadata Cache");
|
||||
|
||||
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
|
||||
/ "game_list/")) {
|
||||
QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty."));
|
||||
if (show_message) QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty."));
|
||||
} else if (Common::FS::RemoveDirRecursively(
|
||||
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) {
|
||||
QtCommon::Frontend::Information(rootObject,
|
||||
if (show_message) QtCommon::Frontend::Information(rootObject,
|
||||
title,
|
||||
tr("The operation completed successfully."));
|
||||
UISettings::values.is_game_list_reload_pending.exchange(true);
|
||||
} else {
|
||||
QtCommon::Frontend::Warning(
|
||||
if (show_message) QtCommon::Frontend::Warning(
|
||||
rootObject,
|
||||
title,
|
||||
tr("The metadata cache couldn't be deleted. It might be in use or non-existent."));
|
||||
|
@ -573,5 +579,4 @@ void CreateHomeMenuShortcut(ShortcutTarget target) {
|
|||
CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false);
|
||||
}
|
||||
|
||||
|
||||
} // namespace QtCommon::Game
|
||||
|
|
|
@ -52,6 +52,7 @@ bool MakeShortcutIcoPath(const u64 program_id,
|
|||
void OpenEdenFolder(const Common::FS::EdenPath &path);
|
||||
void OpenRootDataFolder();
|
||||
void OpenNANDFolder();
|
||||
void OpenSaveFolder();
|
||||
void OpenSDMCFolder();
|
||||
void OpenModFolder();
|
||||
void OpenLogFolder();
|
||||
|
@ -67,7 +68,7 @@ void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);
|
|||
void RemoveCacheStorage(u64 program_id);
|
||||
|
||||
// Metadata //
|
||||
void ResetMetadata();
|
||||
void ResetMetadata(bool show_message = true);
|
||||
|
||||
// Shortcuts //
|
||||
void CreateShortcut(const std::string& game_path,
|
||||
|
|
|
@ -540,6 +540,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
|||
PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")),
|
||||
PAIR(ResolutionSetup, Res5_4X, tr("1.25X (900p/1350p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")),
|
||||
PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")),
|
||||
PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")),
|
||||
|
@ -554,12 +555,16 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
|||
PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")),
|
||||
PAIR(ScalingFilter, Bilinear, tr("Bilinear")),
|
||||
PAIR(ScalingFilter, Bicubic, tr("Bicubic")),
|
||||
PAIR(ScalingFilter, ZeroTangent, tr("Zero-Tangent")),
|
||||
PAIR(ScalingFilter, BSpline, tr("B-Spline")),
|
||||
PAIR(ScalingFilter, Mitchell, tr("Mitchell")),
|
||||
PAIR(ScalingFilter, Spline1, tr("Spline-1")),
|
||||
PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
|
||||
PAIR(ScalingFilter, Lanczos, tr("Lanczos")),
|
||||
PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
|
||||
PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
|
||||
PAIR(ScalingFilter, Area, tr("Area")),
|
||||
PAIR(ScalingFilter, Mmpx, tr("MMPX")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
|
||||
{
|
||||
|
|
|
@ -38,6 +38,9 @@ static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map
|
|||
{Settings::ScalingFilter::Bilinear,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))},
|
||||
{Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))},
|
||||
{Settings::ScalingFilter::ZeroTangent, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Zero-Tangent"))},
|
||||
{Settings::ScalingFilter::BSpline, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "B-Spline"))},
|
||||
{Settings::ScalingFilter::Mitchell, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Mitchell"))},
|
||||
{Settings::ScalingFilter::Spline1,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Spline-1"))},
|
||||
{Settings::ScalingFilter::Gaussian,
|
||||
|
@ -48,6 +51,7 @@ static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map
|
|||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
|
||||
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
|
||||
{Settings::ScalingFilter::Area, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Area"))},
|
||||
{Settings::ScalingFilter::Mmpx, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "MMPX"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
|
||||
|
|
|
@ -246,7 +246,7 @@ add_library(shader_recompiler STATIC
|
|||
|
||||
)
|
||||
|
||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit SPIRV-Tools::SPIRV-Tools)
|
||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit SPIRV-Tools::SPIRV-Tools)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(shader_recompiler PRIVATE
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -21,7 +24,7 @@ add_executable(tests
|
|||
|
||||
create_target_directory_groups(tests)
|
||||
|
||||
target_link_libraries(tests PRIVATE common core input_common)
|
||||
target_link_libraries(tests PRIVATE common core input_common video_core)
|
||||
target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2WithMain Threads::Threads)
|
||||
|
||||
add_test(NAME tests COMMAND tests)
|
||||
|
|
|
@ -333,7 +333,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
|
|||
add_dependencies(video_core host_shaders)
|
||||
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
||||
|
||||
target_link_libraries(video_core PRIVATE sirit)
|
||||
target_link_libraries(video_core PRIVATE sirit::sirit)
|
||||
|
||||
# Header-only stuff needed by all dependent targets
|
||||
target_link_libraries(video_core PUBLIC Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
|
||||
|
|
|
@ -26,7 +26,9 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R
|
|||
void(slot_buffers.insert(runtime, NullBufferParams{}));
|
||||
gpu_modified_ranges.Clear();
|
||||
inline_buffer_id = NULL_BUFFER_ID;
|
||||
|
||||
#ifdef YUZU_LEGACY
|
||||
immediately_free = (Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive);
|
||||
#endif
|
||||
if (!runtime.CanReportMemoryUsage()) {
|
||||
minimum_memory = DEFAULT_EXPECTED_MEMORY;
|
||||
critical_memory = DEFAULT_CRITICAL_MEMORY;
|
||||
|
@ -1378,6 +1380,10 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
|||
});
|
||||
new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size);
|
||||
runtime.CopyBuffer(new_buffer, overlap, copies, true);
|
||||
#ifdef YUZU_LEGACY
|
||||
if (immediately_free)
|
||||
runtime.Finish();
|
||||
#endif
|
||||
DeleteBuffer(overlap_id, true);
|
||||
}
|
||||
|
||||
|
@ -1668,7 +1674,12 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
|
|||
}
|
||||
|
||||
Unregister(buffer_id);
|
||||
delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id]));
|
||||
|
||||
#ifdef YUZU_LEGACY
|
||||
if (!do_not_mark || !immediately_free)
|
||||
#endif
|
||||
delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id]));
|
||||
|
||||
slot_buffers.erase(buffer_id);
|
||||
|
||||
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
|
||||
|
|
|
@ -154,7 +154,11 @@ template <class P>
|
|||
class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInfo> {
|
||||
// Page size for caching purposes.
|
||||
// This is unrelated to the CPU page size and it can be changed as it seems optimal.
|
||||
#ifdef YUZU_LEGACY
|
||||
static constexpr u32 CACHING_PAGEBITS = 12;
|
||||
#else
|
||||
static constexpr u32 CACHING_PAGEBITS = 16;
|
||||
#endif
|
||||
static constexpr u64 CACHING_PAGESIZE = u64{1} << CACHING_PAGEBITS;
|
||||
|
||||
static constexpr bool IS_OPENGL = P::IS_OPENGL;
|
||||
|
@ -168,9 +172,14 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
|
|||
static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = P::USE_MEMORY_MAPS_FOR_UPLOADS;
|
||||
|
||||
#ifdef YUZU_LEGACY
|
||||
static constexpr s64 TARGET_THRESHOLD = 3_GiB;
|
||||
#else
|
||||
static constexpr s64 TARGET_THRESHOLD = 4_GiB;
|
||||
#endif
|
||||
|
||||
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
|
||||
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;
|
||||
static constexpr s64 TARGET_THRESHOLD = 4_GiB;
|
||||
|
||||
// Debug Flags.
|
||||
|
||||
|
@ -446,7 +455,12 @@ private:
|
|||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
|
||||
Common::SlotVector<Buffer> slot_buffers;
|
||||
DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
|
||||
#ifdef YUZU_LEGACY
|
||||
static constexpr size_t TICKS_TO_DESTROY = 6;
|
||||
#else
|
||||
static constexpr size_t TICKS_TO_DESTROY = 8;
|
||||
#endif
|
||||
DelayedDestructionRing<Buffer, TICKS_TO_DESTROY> delayed_destruction_ring;
|
||||
|
||||
const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
|
||||
|
||||
|
@ -478,6 +492,9 @@ private:
|
|||
u64 minimum_memory = 0;
|
||||
u64 critical_memory = 0;
|
||||
BufferId inline_buffer_id;
|
||||
#ifdef YUZU_LEGACY
|
||||
bool immediately_free = false;
|
||||
#endif
|
||||
|
||||
std::array<BufferId, ((1ULL << 34) >> CACHING_PAGEBITS)> page_table;
|
||||
Common::ScratchBuffer<u8> tmp_buffer;
|
||||
|
|
|
@ -64,7 +64,6 @@ void MaxwellDMA::Launch() {
|
|||
// TODO(Subv): Perform more research and implement all features of this engine.
|
||||
const LaunchDMA& launch = regs.launch_dma;
|
||||
ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE);
|
||||
ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED);
|
||||
|
||||
if (launch.multi_line_enable) {
|
||||
const bool is_src_pitch = launch.src_memory_layout == LaunchDMA::MemoryLayout::PITCH;
|
||||
|
@ -157,7 +156,7 @@ void MaxwellDMA::Launch() {
|
|||
}
|
||||
|
||||
void MaxwellDMA::CopyBlockLinearToPitch() {
|
||||
UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
|
||||
|
||||
|
||||
u32 bytes_per_pixel = 1;
|
||||
DMA::ImageOperand src_operand;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -18,9 +21,15 @@ Host1x::~Host1x() = default;
|
|||
void Host1x::StartDevice(s32 fd, ChannelType type, u32 syncpt) {
|
||||
switch (type) {
|
||||
case ChannelType::NvDec:
|
||||
#ifdef YUZU_LEGACY
|
||||
std::call_once(nvdec_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer
|
||||
#endif
|
||||
devices[fd] = std::make_unique<Tegra::Host1x::Nvdec>(*this, fd, syncpt, frame_queue);
|
||||
break;
|
||||
case ChannelType::VIC:
|
||||
#ifdef YUZU_LEGACY
|
||||
std::call_once(vic_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer
|
||||
#endif
|
||||
devices[fd] = std::make_unique<Tegra::Host1x::Vic>(*this, fd, syncpt, frame_queue);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -201,6 +204,10 @@ private:
|
|||
std::unique_ptr<Common::FlatAllocator<u32, 0, 32>> allocator;
|
||||
FrameQueue frame_queue;
|
||||
std::unordered_map<s32, std::unique_ptr<CDmaPusher>> devices;
|
||||
#ifdef YUZU_LEGACY
|
||||
std::once_flag nvdec_first_init;
|
||||
std::once_flag vic_first_init;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Tegra::Host1x
|
||||
|
|
|
@ -44,9 +44,13 @@ set(SHADER_FILES
|
|||
pitch_unswizzle.comp
|
||||
present_area.frag
|
||||
present_bicubic.frag
|
||||
present_zero_tangent.frag
|
||||
present_bspline.frag
|
||||
present_mitchell.frag
|
||||
present_gaussian.frag
|
||||
present_lanczos.frag
|
||||
present_spline1.frag
|
||||
present_mmpx.frag
|
||||
queries_prefix_scan_sum.comp
|
||||
queries_prefix_scan_sum_nosubgroups.comp
|
||||
resolve_conditional_render.comp
|
||||
|
|
|
@ -1,56 +1,37 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#version 460 core
|
||||
|
||||
|
||||
layout (location = 0) in vec2 frag_tex_coord;
|
||||
|
||||
layout (location = 0) out vec4 color;
|
||||
|
||||
layout (binding = 0) uniform sampler2D color_texture;
|
||||
|
||||
vec4 cubic(float v) {
|
||||
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
|
||||
vec4 s = n * n * n;
|
||||
float x = s.x;
|
||||
float y = s.y - 4.0 * s.x;
|
||||
float z = s.z - 4.0 * s.y + 6.0 * s.x;
|
||||
float w = 6.0 - x - y - z;
|
||||
return vec4(x, y, z, w) * (1.0 / 6.0);
|
||||
vec4 cubic(float x) {
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
return vec4(1.0, x, x2, x3) * transpose(mat4x4(
|
||||
0.0, 2.0, 0.0, 0.0,
|
||||
-1.0, 0.0, 1.0, 0.0,
|
||||
2.0, -5.0, 4.0, -1.0,
|
||||
-1.0, 3.0, -3.0, 1.0
|
||||
) * (1.0 / 2.0));
|
||||
}
|
||||
|
||||
vec4 textureBicubic( sampler2D textureSampler, vec2 texCoords ) {
|
||||
|
||||
vec2 texSize = textureSize(textureSampler, 0);
|
||||
vec2 invTexSize = 1.0 / texSize;
|
||||
|
||||
texCoords = texCoords * texSize - 0.5;
|
||||
|
||||
vec2 fxy = fract(texCoords);
|
||||
texCoords -= fxy;
|
||||
|
||||
vec4 xcubic = cubic(fxy.x);
|
||||
vec4 ycubic = cubic(fxy.y);
|
||||
|
||||
vec4 c = texCoords.xxyy + vec2(-0.5, +1.5).xyxy;
|
||||
|
||||
vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
||||
vec4 offset = c + vec4(xcubic.yw, ycubic.yw) / s;
|
||||
|
||||
offset *= invTexSize.xxyy;
|
||||
|
||||
vec4 sample0 = texture(textureSampler, offset.xz);
|
||||
vec4 sample1 = texture(textureSampler, offset.yz);
|
||||
vec4 sample2 = texture(textureSampler, offset.xw);
|
||||
vec4 sample3 = texture(textureSampler, offset.yw);
|
||||
|
||||
float sx = s.x / (s.x + s.y);
|
||||
float sy = s.z / (s.z + s.w);
|
||||
|
||||
return mix(mix(sample3, sample2, sx), mix(sample1, sample0, sx), sy);
|
||||
vec4 textureBicubic(sampler2D samp, vec2 uv) {
|
||||
vec2 tex_size = vec2(textureSize(samp, 0));
|
||||
vec2 cc_tex = uv * tex_size - 0.5f;
|
||||
vec2 fex = cc_tex - floor(cc_tex);
|
||||
vec4 xcubic = cubic(fex.x);
|
||||
vec4 ycubic = cubic(fex.y);
|
||||
vec4 c = floor(cc_tex).xxyy + vec2(-0.5f, 1.5f).xyxy;
|
||||
vec4 z = vec4(xcubic.yw, ycubic.yw);
|
||||
vec4 s = vec4(xcubic.xz, ycubic.xz) + z;
|
||||
vec4 offset = (c + z / s) * (1.0f / tex_size).xxyy;
|
||||
vec2 n = vec2(s.x / (s.x + s.y), s.z / (s.z + s.w));
|
||||
return mix(
|
||||
mix(texture(samp, offset.yw), texture(samp, offset.xw), n.x),
|
||||
mix(texture(samp, offset.yz), texture(samp, offset.xz), n.x),
|
||||
n.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
color = textureBicubic(color_texture, frag_tex_coord);
|
||||
}
|
||||
|
|
35
src/video_core/host_shaders/present_bspline.frag
Normal file
35
src/video_core/host_shaders/present_bspline.frag
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#version 460 core
|
||||
layout (location = 0) in vec2 frag_tex_coord;
|
||||
layout (location = 0) out vec4 color;
|
||||
layout (binding = 0) uniform sampler2D color_texture;
|
||||
vec4 cubic(float x) {
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
return vec4(1.0, x, x2, x3) * transpose(mat4x4(
|
||||
1.0, 4.0, 1.0, 0.0,
|
||||
-3.0, 0.0, 3.0, 0.0,
|
||||
3.0, -6.0, 3.0, 0.0,
|
||||
-1.0, 3.0, -3.0, 1.0
|
||||
) * (1.0 / 6.0));
|
||||
}
|
||||
vec4 textureBicubic(sampler2D samp, vec2 uv) {
|
||||
vec2 tex_size = vec2(textureSize(samp, 0));
|
||||
vec2 cc_tex = uv * tex_size - 0.5f;
|
||||
vec2 fex = cc_tex - floor(cc_tex);
|
||||
vec4 xcubic = cubic(fex.x);
|
||||
vec4 ycubic = cubic(fex.y);
|
||||
vec4 c = floor(cc_tex).xxyy + vec2(-0.5f, 1.5f).xyxy;
|
||||
vec4 z = vec4(xcubic.yw, ycubic.yw);
|
||||
vec4 s = vec4(xcubic.xz, ycubic.xz) + z;
|
||||
vec4 offset = (c + z / s) * (1.0f / tex_size).xxyy;
|
||||
vec2 n = vec2(s.x / (s.x + s.y), s.z / (s.z + s.w));
|
||||
return mix(
|
||||
mix(texture(samp, offset.yw), texture(samp, offset.xw), n.x),
|
||||
mix(texture(samp, offset.yz), texture(samp, offset.xz), n.x),
|
||||
n.y);
|
||||
}
|
||||
void main() {
|
||||
color = textureBicubic(color_texture, frag_tex_coord);
|
||||
}
|
35
src/video_core/host_shaders/present_mitchell.frag
Normal file
35
src/video_core/host_shaders/present_mitchell.frag
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#version 460 core
|
||||
layout (location = 0) in vec2 frag_tex_coord;
|
||||
layout (location = 0) out vec4 color;
|
||||
layout (binding = 0) uniform sampler2D color_texture;
|
||||
vec4 cubic(float x) {
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
return vec4(1.0, x, x2, x3) * transpose(mat4x4(
|
||||
1.0, 16.0, 1.0, 0.0,
|
||||
-9.0, 0.0, 9.0, 0.0,
|
||||
15.0, -36.0, 27.0, -6.0,
|
||||
-7.0, 21.0, -21.0, 7.0
|
||||
) * (1.0 / 18.0));
|
||||
}
|
||||
vec4 textureBicubic(sampler2D samp, vec2 uv) {
|
||||
vec2 tex_size = vec2(textureSize(samp, 0));
|
||||
vec2 cc_tex = uv * tex_size - 0.5f;
|
||||
vec2 fex = cc_tex - floor(cc_tex);
|
||||
vec4 xcubic = cubic(fex.x);
|
||||
vec4 ycubic = cubic(fex.y);
|
||||
vec4 c = floor(cc_tex).xxyy + vec2(-0.5f, 1.5f).xyxy;
|
||||
vec4 z = vec4(xcubic.yw, ycubic.yw);
|
||||
vec4 s = vec4(xcubic.xz, ycubic.xz) + z;
|
||||
vec4 offset = (c + z / s) * (1.0f / tex_size).xxyy;
|
||||
vec2 n = vec2(s.x / (s.x + s.y), s.z / (s.z + s.w));
|
||||
return mix(
|
||||
mix(texture(samp, offset.yw), texture(samp, offset.xw), n.x),
|
||||
mix(texture(samp, offset.yz), texture(samp, offset.xz), n.x),
|
||||
n.y);
|
||||
}
|
||||
void main() {
|
||||
color = textureBicubic(color_texture, frag_tex_coord);
|
||||
}
|
131
src/video_core/host_shaders/present_mmpx.frag
Normal file
131
src/video_core/host_shaders/present_mmpx.frag
Normal file
|
@ -0,0 +1,131 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#version 460 core
|
||||
layout(location = 0) in vec2 tex_coord;
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
layout(binding = 0) uniform sampler2D tex;
|
||||
|
||||
#define src(x, y) texture(tex, coord + vec2(x, y) * 1.0 / source_size)
|
||||
|
||||
float luma(vec4 col) {
|
||||
return dot(col.rgb, vec3(0.2126, 0.7152, 0.0722)) * (1.0 - col.a);
|
||||
}
|
||||
|
||||
bool same(vec4 B, vec4 A0) {
|
||||
return all(equal(B, A0));
|
||||
}
|
||||
|
||||
bool notsame(vec4 B, vec4 A0) {
|
||||
return any(notEqual(B, A0));
|
||||
}
|
||||
|
||||
bool all_eq2(vec4 B, vec4 A0, vec4 A1) {
|
||||
return (same(B,A0) && same(B,A1));
|
||||
}
|
||||
|
||||
bool all_eq3(vec4 B, vec4 A0, vec4 A1, vec4 A2) {
|
||||
return (same(B,A0) && same(B,A1) && same(B,A2));
|
||||
}
|
||||
|
||||
bool all_eq4(vec4 B, vec4 A0, vec4 A1, vec4 A2, vec4 A3) {
|
||||
return (same(B,A0) && same(B,A1) && same(B,A2) && same(B,A3));
|
||||
}
|
||||
|
||||
bool any_eq3(vec4 B, vec4 A0, vec4 A1, vec4 A2) {
|
||||
return (same(B,A0) || same(B,A1) || same(B,A2));
|
||||
}
|
||||
|
||||
bool none_eq2(vec4 B, vec4 A0, vec4 A1) {
|
||||
return (notsame(B,A0) && notsame(B,A1));
|
||||
}
|
||||
|
||||
bool none_eq4(vec4 B, vec4 A0, vec4 A1, vec4 A2, vec4 A3) {
|
||||
return (notsame(B,A0) && notsame(B,A1) && notsame(B,A2) && notsame(B,A3));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 source_size = vec2(textureSize(tex, 0));
|
||||
vec2 pos = fract(tex_coord * source_size) - vec2(0.5, 0.5);
|
||||
vec2 coord = tex_coord - pos / source_size;
|
||||
|
||||
vec4 E = src(0.0,0.0);
|
||||
|
||||
vec4 A = src(-1.0,-1.0);
|
||||
vec4 B = src(0.0,-1.0);
|
||||
vec4 C = src(1.0,-1.0);
|
||||
|
||||
vec4 D = src(-1.0,0.0);
|
||||
vec4 F = src(1.0,0.0);
|
||||
|
||||
vec4 G = src(-1.0,1.0);
|
||||
vec4 H = src(0.0,1.0);
|
||||
vec4 I = src(1.0,1.0);
|
||||
|
||||
vec4 J = E;
|
||||
vec4 K = E;
|
||||
vec4 L = E;
|
||||
vec4 M = E;
|
||||
|
||||
frag_color = E;
|
||||
|
||||
if(same(E,A) && same(E,B) && same(E,C) && same(E,D) && same(E,F) && same(E,G) && same(E,H) && same(E,I)) return;
|
||||
|
||||
vec4 P = src(0.0,2.0);
|
||||
vec4 Q = src(-2.0,0.0);
|
||||
vec4 R = src(2.0,0.0);
|
||||
vec4 S = src(0.0,2.0);
|
||||
|
||||
float Bl = luma(B);
|
||||
float Dl = luma(D);
|
||||
float El = luma(E);
|
||||
float Fl = luma(F);
|
||||
float Hl = luma(H);
|
||||
|
||||
if (((same(D,B) && notsame(D,H) && notsame(D,F))) && ((El>=Dl) || same(E,A)) && any_eq3(E,A,C,G) && ((El<Dl) || notsame(A,D) || notsame(E,P) || notsame(E,Q))) J=mix(D, J, 0.5);
|
||||
if (((same(B,F) && notsame(B,D) && notsame(B,H))) && ((El>=Bl) || same(E,C)) && any_eq3(E,A,C,I) && ((El<Bl) || notsame(C,B) || notsame(E,P) || notsame(E,R))) K=mix(B, K, 0.5);
|
||||
if (((same(H,D) && notsame(H,F) && notsame(H,B))) && ((El>=Hl) || same(E,G)) && any_eq3(E,A,G,I) && ((El<Hl) || notsame(G,H) || notsame(E,S) || notsame(E,Q))) L=mix(H, L, 0.5);
|
||||
if (((same(F,H) && notsame(F,B) && notsame(F,D))) && ((El>=Fl) || same(E,I)) && any_eq3(E,C,G,I) && ((El<Fl) || notsame(I,H) || notsame(E,R) || notsame(E,S))) M=mix(F, M, 0.5);
|
||||
|
||||
if ((notsame(E,F) && all_eq4(E,C,I,D,Q) && all_eq2(F,B,H)) && notsame(F,src(3.0,0.0))) {M=mix(M, F, 0.5); K=mix(K, M, 0.5);};
|
||||
if ((notsame(E,D) && all_eq4(E,A,G,F,R) && all_eq2(D,B,H)) && notsame(D,src(-3.0,0.0))) {L=mix(L, D, 0.5); J=mix(J, L, 0.5);};
|
||||
if ((notsame(E,H) && all_eq4(E,G,I,B,P) && all_eq2(H,D,F)) && notsame(H,src(0.0,3.0))) {M=mix(M, H, 0.5); L=mix(L, M, 0.5);};
|
||||
if ((notsame(E,B) && all_eq4(E,A,C,H,S) && all_eq2(B,D,F)) && notsame(B,src(0.0,-3.0))) {K=mix(K, B, 0.5); J=mix(J, K, 0.5);};
|
||||
|
||||
if ((Bl<El) && all_eq4(E,G,H,I,S) && none_eq4(E,A,D,C,F)) {K=mix(K, B, 0.5); J=mix(J, K, 0.5);}
|
||||
if ((Hl<El) && all_eq4(E,A,B,C,P) && none_eq4(E,D,G,I,F)) {M=mix(M, H, 0.5); L=mix(L, M, 0.5);}
|
||||
if ((Fl<El) && all_eq4(E,A,D,G,Q) && none_eq4(E,B,C,I,H)) {M=mix(M, F, 0.5); K=mix(K, M, 0.5);}
|
||||
if ((Dl<El) && all_eq4(E,C,F,I,R) && none_eq4(E,B,A,G,H)) {L=mix(L, D, 0.5); J=mix(J, L, 0.5);}
|
||||
|
||||
if (notsame(H,B)) {
|
||||
if (notsame(H,A) && notsame(H,E) && notsame(H,C)) {
|
||||
if (all_eq3(H,G,F,R) && none_eq2(H,D,src(2.0,-1.0))) L=mix(M, L, 0.5);
|
||||
if (all_eq3(H,I,D,Q) && none_eq2(H,F,src(-2.0,-1.0))) M=mix(L, M, 0.5);
|
||||
}
|
||||
|
||||
if (notsame(B,I) && notsame(B,G) && notsame(B,E)) {
|
||||
if (all_eq3(B,A,F,R) && none_eq2(B,D,src(2.0,1.0))) J=mix(K, L, 0.5);
|
||||
if (all_eq3(B,C,D,Q) && none_eq2(B,F,src(-2.0,1.0))) K=mix(J, K, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
if (notsame(F,D)) {
|
||||
if (notsame(D,I) && notsame(D,E) && notsame(D,C)) {
|
||||
if (all_eq3(D,A,H,S) && none_eq2(D,B,src(1.0,2.0))) J=mix(L, J, 0.5);
|
||||
if (all_eq3(D,G,B,P) && none_eq2(D,H,src(1.0,2.0))) L=mix(J, L, 0.5);
|
||||
}
|
||||
|
||||
if (notsame(F,E) && notsame(F,A) && notsame(F,G)) {
|
||||
if (all_eq3(F,C,H,S) && none_eq2(F,B,src(-1.0,2.0))) K=mix(M, K, 0.5);
|
||||
if (all_eq3(F,I,B,P) && none_eq2(F,H,src(-1.0,-2.0))) M=mix(K, M, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
vec2 a = fract(tex_coord * source_size);
|
||||
vec4 colour = (a.x < 0.5) ? (a.y < 0.5 ? J : L) : (a.y < 0.5 ? K : M);
|
||||
frag_color = colour;
|
||||
}
|
35
src/video_core/host_shaders/present_zero_tangent.frag
Normal file
35
src/video_core/host_shaders/present_zero_tangent.frag
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#version 460 core
|
||||
layout (location = 0) in vec2 frag_tex_coord;
|
||||
layout (location = 0) out vec4 color;
|
||||
layout (binding = 0) uniform sampler2D color_texture;
|
||||
vec4 cubic(float x) {
|
||||
float x2 = x * x;
|
||||
float x3 = x2 * x;
|
||||
return vec4(1.0, x, x2, x3) * transpose(mat4x4(
|
||||
0.0, 2.0, 0.0, 0.0,
|
||||
-2.0, 0.0, 2.0, 0.0,
|
||||
4.0, -4.0, 2.0, -2.0,
|
||||
-2.0, 2.0, -2.0, 1.0
|
||||
) * (1.0 / 2.0));
|
||||
}
|
||||
vec4 textureBicubic(sampler2D samp, vec2 uv) {
|
||||
vec2 tex_size = vec2(textureSize(samp, 0));
|
||||
vec2 cc_tex = uv * tex_size - 0.5f;
|
||||
vec2 fex = cc_tex - floor(cc_tex);
|
||||
vec4 xcubic = cubic(fex.x);
|
||||
vec4 ycubic = cubic(fex.y);
|
||||
vec4 c = floor(cc_tex).xxyy + vec2(-0.5f, 1.5f).xyxy;
|
||||
vec4 z = vec4(xcubic.yw, ycubic.yw);
|
||||
vec4 s = vec4(xcubic.xz, ycubic.xz) + z;
|
||||
vec4 offset = (c + z / s) * (1.0f / tex_size).xxyy;
|
||||
vec2 n = vec2(s.x / (s.x + s.y), s.z / (s.z + s.w));
|
||||
return mix(
|
||||
mix(texture(samp, offset.yw), texture(samp, offset.xw), n.x),
|
||||
mix(texture(samp, offset.yz), texture(samp, offset.xz), n.x),
|
||||
n.y);
|
||||
}
|
||||
void main() {
|
||||
color = textureBicubic(color_texture, frag_tex_coord);
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_opengl/gl_blit_screen.h"
|
||||
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
||||
|
@ -86,6 +87,15 @@ void BlitScreen::CreateWindowAdapt() {
|
|||
case Settings::ScalingFilter::Bicubic:
|
||||
window_adapt = MakeBicubic(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::ZeroTangent:
|
||||
window_adapt = MakeZeroTangent(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::BSpline:
|
||||
window_adapt = MakeBSpline(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Mitchell:
|
||||
window_adapt = MakeMitchell(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
window_adapt = MakeGaussian(device);
|
||||
break;
|
||||
|
@ -101,6 +111,9 @@ void BlitScreen::CreateWindowAdapt() {
|
|||
case Settings::ScalingFilter::Area:
|
||||
window_adapt = MakeArea(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Mmpx:
|
||||
window_adapt = MakeMmpx(device);
|
||||
break;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
default:
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
#include "video_core/host_shaders/present_gaussian_frag.h"
|
||||
#include "video_core/host_shaders/present_lanczos_frag.h"
|
||||
#include "video_core/host_shaders/present_spline1_frag.h"
|
||||
#include "video_core/host_shaders/present_mitchell_frag.h"
|
||||
#include "video_core/host_shaders/present_bspline_frag.h"
|
||||
#include "video_core/host_shaders/present_zero_tangent_frag.h"
|
||||
#include "video_core/host_shaders/present_mmpx_frag.h"
|
||||
#include "video_core/renderer_opengl/present/filters.h"
|
||||
#include "video_core/renderer_opengl/present/util.h"
|
||||
|
||||
|
@ -39,6 +43,21 @@ std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device) {
|
|||
HostShaders::PRESENT_BICUBIC_FRAG);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeMitchell(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(),
|
||||
HostShaders::PRESENT_MITCHELL_FRAG);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeZeroTangent(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(),
|
||||
HostShaders::PRESENT_ZERO_TANGENT_FRAG);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeBSpline(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(),
|
||||
HostShaders::PRESENT_BSPLINE_FRAG);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(),
|
||||
HostShaders::PRESENT_GAUSSIAN_FRAG);
|
||||
|
@ -60,4 +79,9 @@ std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device) {
|
|||
HostShaders::PRESENT_AREA_FRAG);
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowAdaptPass> MakeMmpx(const Device& device) {
|
||||
return std::make_unique<WindowAdaptPass>(device, CreateNearestNeighborSampler(),
|
||||
HostShaders::PRESENT_MMPX_FRAG);
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
|
|
@ -17,10 +17,14 @@ namespace OpenGL {
|
|||
std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeZeroTangent(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeMitchell(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeBSpline(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeSpline1(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeLanczos(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeArea(const Device& device);
|
||||
std::unique_ptr<WindowAdaptPass> MakeMmpx(const Device& device);
|
||||
|
||||
} // namespace OpenGL
|
||||
|
|
|
@ -46,6 +46,38 @@ namespace Vulkan {
|
|||
using VideoCommon::ImageViewType;
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] VkImageAspectFlags AspectMaskFromFormat(VideoCore::Surface::PixelFormat format) {
|
||||
using VideoCore::Surface::SurfaceType;
|
||||
switch (VideoCore::Surface::GetFormatType(format)) {
|
||||
case SurfaceType::ColorTexture:
|
||||
return VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
case SurfaceType::Depth:
|
||||
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
case SurfaceType::Stencil:
|
||||
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
case SurfaceType::DepthStencil:
|
||||
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
default:
|
||||
return VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] VkImageSubresourceRange SubresourceRangeFromView(const ImageView& image_view) {
|
||||
auto range = image_view.range;
|
||||
if ((image_view.flags & VideoCommon::ImageViewFlagBits::Slice) != VideoCommon::ImageViewFlagBits{}) {
|
||||
range.base.layer = 0;
|
||||
range.extent.layers = 1;
|
||||
}
|
||||
return VkImageSubresourceRange{
|
||||
.aspectMask = AspectMaskFromFormat(image_view.format),
|
||||
.baseMipLevel = static_cast<u32>(range.base.level),
|
||||
.levelCount = static_cast<u32>(range.extent.levels),
|
||||
.baseArrayLayer = static_cast<u32>(range.base.layer),
|
||||
.layerCount = static_cast<u32>(range.extent.layers),
|
||||
};
|
||||
}
|
||||
|
||||
struct PushConstants {
|
||||
std::array<float, 2> tex_scale;
|
||||
std::array<float, 2> tex_offset;
|
||||
|
@ -417,6 +449,40 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
|
|||
0, barrier);
|
||||
}
|
||||
|
||||
void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) {
|
||||
const VkImage image = image_view.ImageHandle();
|
||||
const VkImageSubresourceRange subresource_range = SubresourceRangeFromView(image_view);
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([image, subresource_range](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange = subresource_range,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
barrier);
|
||||
});
|
||||
}
|
||||
|
||||
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||
const VkRenderPass render_pass = framebuffer->RenderPass();
|
||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||
|
@ -484,7 +550,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
|||
|
||||
BlitImageHelper::~BlitImageHelper() = default;
|
||||
|
||||
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_view,
|
||||
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
const Region2D& dst_region, const Region2D& src_region,
|
||||
Tegra::Engines::Fermi2D::Filter filter,
|
||||
Tegra::Engines::Fermi2D::Operation operation) {
|
||||
|
@ -496,10 +562,12 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||
|
||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler,
|
||||
src_view](vk::CommandBuffer cmdbuf) {
|
||||
// TODO: Barriers
|
||||
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
@ -538,7 +606,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||
}
|
||||
|
||||
void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
||||
VkImageView src_depth_view, VkImageView src_stencil_view,
|
||||
ImageView& src_image_view,
|
||||
const Region2D& dst_region, const Region2D& src_region,
|
||||
Tegra::Engines::Fermi2D::Filter filter,
|
||||
Tegra::Engines::Fermi2D::Operation operation) {
|
||||
|
@ -554,10 +622,13 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
||||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
|
||||
const VkImageView src_depth_view = src_image_view.DepthView();
|
||||
const VkImageView src_stencil_view = src_image_view.StencilView();
|
||||
|
||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([dst_region, src_region, pipeline, layout, sampler, src_depth_view,
|
||||
src_stencil_view, this](vk::CommandBuffer cmdbuf) {
|
||||
// TODO: Barriers
|
||||
const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
|
||||
UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
|
||||
src_stencil_view);
|
||||
|
@ -692,6 +763,7 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
|
|||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkExtent2D extent = GetConversionExtent(src_image_view);
|
||||
|
||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
|
||||
const VkOffset2D offset{
|
||||
|
@ -717,7 +789,6 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
|
|||
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
|
||||
|
||||
// TODO: Barriers
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||
nullptr);
|
||||
|
@ -737,6 +808,7 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer
|
|||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkExtent2D extent = GetConversionExtent(src_image_view);
|
||||
|
||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
|
||||
this](vk::CommandBuffer cmdbuf) {
|
||||
|
@ -763,7 +835,6 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer
|
|||
const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
|
||||
UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
|
||||
src_stencil_view);
|
||||
// TODO: Barriers
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||
nullptr);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
@ -43,7 +46,7 @@ public:
|
|||
StateTracker& state_tracker, DescriptorPool& descriptor_pool);
|
||||
~BlitImageHelper();
|
||||
|
||||
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||
void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
const Region2D& dst_region, const Region2D& src_region,
|
||||
Tegra::Engines::Fermi2D::Filter filter,
|
||||
Tegra::Engines::Fermi2D::Operation operation);
|
||||
|
@ -52,9 +55,9 @@ public:
|
|||
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
||||
const Region2D& src_region, const Extent3D& src_size);
|
||||
|
||||
void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
|
||||
VkImageView src_stencil_view, const Region2D& dst_region,
|
||||
const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
|
||||
void BlitDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
||||
const Region2D& dst_region, const Region2D& src_region,
|
||||
Tegra::Engines::Fermi2D::Filter filter,
|
||||
Tegra::Engines::Fermi2D::Operation operation);
|
||||
|
||||
void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue