Compare commits
109 Commits
vulkan-thi
...
showcase
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c99f0c166 | ||
|
|
520e07e756 | ||
|
|
674f552ff1 | ||
|
|
75d9236520 | ||
|
|
89926bce0b | ||
|
|
6c1fc4b4ed | ||
|
|
311f06047b | ||
|
|
46df717f7c | ||
|
|
dcf9483b0b | ||
|
|
2b828a9fee | ||
|
|
6fe1f86984 | ||
|
|
af073f13cf | ||
|
|
aea945b671 | ||
|
|
c52fda760a | ||
|
|
c168755c65 | ||
|
|
8a83cf0271 | ||
|
|
3db41fbce6 | ||
|
|
5e7fb6eead | ||
|
|
bcc5390943 | ||
|
|
a51d875d91 | ||
|
|
6134a57367 | ||
|
|
c845b6086f | ||
|
|
31c168efe1 | ||
|
|
8bd87204f5 | ||
|
|
e72a206aee | ||
|
|
6a62fa7ee3 | ||
|
|
52b630dfdc | ||
|
|
4860050358 | ||
|
|
47f0563c1b | ||
|
|
b1208f03ee | ||
|
|
0fd603c094 | ||
|
|
1ca19af7fb | ||
|
|
ddd78c3b37 | ||
|
|
2e68f8795d | ||
|
|
d3595fd2b1 | ||
|
|
033531509b | ||
|
|
b9954de1ca | ||
|
|
5f88deeebf | ||
|
|
d25da944ed | ||
|
|
ec274a855e | ||
|
|
8133d4a8b4 | ||
|
|
4f3e4bf9cb | ||
|
|
ec9e0f37ea | ||
|
|
b5f7735dba | ||
|
|
5f501d6ec0 | ||
|
|
e820f304a5 | ||
|
|
3527a33430 | ||
|
|
3f226678dd | ||
|
|
e9d84d098d | ||
|
|
ee5565077c | ||
|
|
9085ff1229 | ||
|
|
6eff1779a2 | ||
|
|
3228cffd23 | ||
|
|
9d9530efe0 | ||
|
|
aaaa7c7601 | ||
|
|
7f8a507b79 | ||
|
|
c28ae059e8 | ||
|
|
7f1369f9a8 | ||
|
|
6b05c164a1 | ||
|
|
a3f9d3b59c | ||
|
|
b066a6ffa0 | ||
|
|
a14cba7f11 | ||
|
|
2d85b70373 | ||
|
|
aa8cc4da38 | ||
|
|
baddaf0040 | ||
|
|
35b4e34e09 | ||
|
|
b574e9c334 | ||
|
|
d6b5a3e181 | ||
|
|
a65a35432e | ||
|
|
6e575364eb | ||
|
|
71a1442ab6 | ||
|
|
32db6c1877 | ||
|
|
8eaa7c28ce | ||
|
|
3edfcabdea | ||
|
|
450c483de0 | ||
|
|
66db2613b5 | ||
|
|
9a046190c7 | ||
|
|
cfbef5c487 | ||
|
|
f51d61e4a4 | ||
|
|
ba9e03a612 | ||
|
|
7832afc5dd | ||
|
|
028765867f | ||
|
|
d89df63a28 | ||
|
|
87c4f658ce | ||
|
|
b7584cb2c3 | ||
|
|
f32f356c40 | ||
|
|
7ca657d22f | ||
|
|
7764cdd57e | ||
|
|
4a17762ed7 | ||
|
|
447c4de73d | ||
|
|
cd2c4d8caf | ||
|
|
ee64c945fb | ||
|
|
eec5d48220 | ||
|
|
75cc43a57a | ||
|
|
0078094b86 | ||
|
|
3cd33fce44 | ||
|
|
ccafe0ed91 | ||
|
|
94af9ff51f | ||
|
|
d229fdca32 | ||
|
|
e636e940ed | ||
|
|
2798174b00 | ||
|
|
46f2084114 | ||
|
|
42863027e2 | ||
|
|
08f3639c80 | ||
|
|
e13c7ef3f8 | ||
|
|
89dd133a2f | ||
|
|
86e9c32800 | ||
|
|
f1cf30bc2a | ||
|
|
5af5214451 |
19
.github/workflows/sources.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: tx-src
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
sources:
|
||||
runs-on: source
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Push New Sources
|
||||
run: |
|
||||
export PATH=/usr/lib/qt6/bin:$PATH
|
||||
./tools/translations/qt-source.sh
|
||||
tx-cli push -s
|
||||
61
.github/workflows/translations.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: tx-pull
|
||||
|
||||
on:
|
||||
# monday, wednesday, saturday at 2pm
|
||||
schedule:
|
||||
cron:
|
||||
- '0 14 * * 1,3,6'
|
||||
|
||||
jobs:
|
||||
tx-update:
|
||||
runs-on: source
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get New Translations
|
||||
run: tx-cli pull -t -f
|
||||
|
||||
- name: Push branch
|
||||
run: |
|
||||
git config --local user.name "Eden CI"
|
||||
git config --local user.email "ci@eden-emu.dev"
|
||||
git config --local user.signingkey "D57652791BB25D2A"
|
||||
git config --local push.autoSetupRemote true
|
||||
|
||||
git remote set-url origin ci:eden-emu/eden.git
|
||||
|
||||
TIMESTAMP=$(date +"%s")
|
||||
echo "TIMESTAMP=$TIMESTAMP" >> "$GITHUB_ENV"
|
||||
|
||||
git switch -c update-translations-$TIMESTAMP
|
||||
git add dist src/android/app/src/main/res
|
||||
|
||||
git commit -sS -m "[dist, android] Update translations from Transifex"
|
||||
git push
|
||||
|
||||
- name: Create PR
|
||||
run: |
|
||||
DATE=$(date +"%b %d")
|
||||
TITLE="[dist, android] Update translations from Transifex for $DATE"
|
||||
BODY="Automatic translation update for $DATE"
|
||||
BASE=master
|
||||
HEAD=update-translations-$TIMESTAMP
|
||||
|
||||
cat << EOF > data.json
|
||||
{
|
||||
"base": "$BASE",
|
||||
"body": "$BODY",
|
||||
"head": "$HEAD",
|
||||
"title": "$TITLE"
|
||||
}
|
||||
EOF
|
||||
|
||||
curl -X 'POST' \
|
||||
'https://git.eden-emu.dev/api/v1/repos/eden-emu/eden/pulls' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Authorization: Bearer ${{ secrets.CI_FJ_TOKEN }}' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "@data.json" --fail
|
||||
|
||||
135
CMakeLists.txt
@@ -21,6 +21,11 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(PLATFORM_LINUX ON)
|
||||
endif()
|
||||
|
||||
# dumb heuristic to detect msys2
|
||||
if (CMAKE_COMMAND MATCHES "msys64")
|
||||
set(PLATFORM_MSYS ON)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CXX_CLANG ON)
|
||||
if (MSVC)
|
||||
@@ -85,6 +90,89 @@ if (PLATFORM_NETBSD)
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
endif()
|
||||
|
||||
# MSYS2 utilities
|
||||
if (PLATFORM_MSYS)
|
||||
include(FixMsysPaths)
|
||||
# really, really dumb heuristic to detect what environment we are in
|
||||
macro(system var)
|
||||
if (CMAKE_COMMAND MATCHES ${var})
|
||||
set(MSYSTEM ${var})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
system(mingw64)
|
||||
system(clang64)
|
||||
system(clangarm64)
|
||||
system(ucrt64)
|
||||
|
||||
if (NOT DEFINED MSYSTEM)
|
||||
set(MSYSTEM msys2)
|
||||
endif()
|
||||
|
||||
# we (generally) want to prioritize environment-specific binaries if possible
|
||||
# some, like autoconf, are not present on environments besides msys2 though
|
||||
set(CMAKE_PROGRAM_PATH C:/msys64/${MSYSTEM}/bin C:/msys64/usr/bin)
|
||||
set(ENV{PKG_CONFIG_PATH} C:/msys64/${MSYSTEM}/lib/pkgconfig)
|
||||
endif()
|
||||
|
||||
# static stuff
|
||||
option(YUZU_STATIC_BUILD "Use static libraries and executables if available" OFF)
|
||||
|
||||
if (YUZU_STATIC_BUILD)
|
||||
# lol
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
## find .a libs first (static, usually)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
|
||||
## some libraries define a Library::Name_static alternative ##
|
||||
set(YUZU_STATIC_SUFFIX _static)
|
||||
|
||||
## some libraries use CMAKE_IMPORT_LIBRARY_SUFFIX e.g. Harfbuzz ##
|
||||
set(CMAKE_IMPORT_LIBRARY_SUFFIX ".a")
|
||||
|
||||
if (MINGW)
|
||||
# simple hook to reject dynamic libs
|
||||
function(find_library var)
|
||||
# also skip previously-found libraries cuz... yaknow
|
||||
if (${var})
|
||||
return()
|
||||
endif()
|
||||
|
||||
_find_library(${var} ${ARGN})
|
||||
if (${var})
|
||||
get_filename_component(lib_name "${${var}}" NAME)
|
||||
if (lib_name MATCHES "dll\\.a$")
|
||||
unset(${var} CACHE)
|
||||
set(${var} "${var}-NOTFOUND" CACHE INTERNAL "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# msys2 quazip does not build a static lib
|
||||
set(QuaZip-Qt6_FORCE_BUNDLED ON)
|
||||
|
||||
set(YUZU_USE_BUNDLED_FFMPEG ON)
|
||||
set(YUZU_USE_BUNDLED_SDL2 ON)
|
||||
|
||||
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
|
||||
elseif(APPLE)
|
||||
# these libs do not properly provide static libs/let you do it with cmake
|
||||
set(YUZU_USE_CPM ON)
|
||||
|
||||
# IMPORTED_IMPLIB not set for imported target
|
||||
# TODO(crueter): wtf
|
||||
set(YUZU_USE_BUNDLED_FFMPEG ON)
|
||||
set(YUZU_USE_EXTERNAL_SDL2 ON)
|
||||
|
||||
set(fmt_FORCE_BUNDLED ON)
|
||||
set(SPIRV-Tools_FORCE_BUNDLED ON)
|
||||
set(SPIRV-Headers_FORCE_BUNDLED ON)
|
||||
set(zstd_FORCE_BUNDLED ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Detect current compilation architecture and create standard definitions
|
||||
# =======================================================================
|
||||
|
||||
@@ -219,11 +307,9 @@ endif()
|
||||
# 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)
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
# 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}")
|
||||
endif()
|
||||
# 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 "Build SDL2 from external source" OFF "ENABLE_SDL2;NOT MSVC" OFF)
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "ENABLE_SDL2" OFF)
|
||||
|
||||
# qt stuff
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
@@ -244,10 +330,14 @@ option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if n
|
||||
|
||||
# ffmpeg
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
# sirit
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT})
|
||||
set(BUNDLED_SIRIT_DEFAULT OFF)
|
||||
if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Debug|RelWithDebInfo") OR ANDROID))
|
||||
set(BUNDLED_SIRIT_DEFAULT ON)
|
||||
endif()
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
||||
|
||||
# Re-allow on FreeBSD once its on mainline ports
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR APPLE" OFF)
|
||||
@@ -284,6 +374,17 @@ if(USE_CCACHE)
|
||||
else()
|
||||
message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
|
||||
endif()
|
||||
# Follow SCCache recommendations:
|
||||
# <https://github.com/mozilla/sccache/blob/main/README.md?plain=1#L144>
|
||||
if(WIN32)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TODO(crueter): CI this?
|
||||
@@ -355,13 +456,6 @@ if (ANDROID)
|
||||
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe
|
||||
endif()
|
||||
|
||||
# We need to downgrade debug info (/Zi -> /Z7) to use an older but more cacheable format
|
||||
# See https://github.com/nanoant/CMakePCHCompiler/issues/21
|
||||
if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
endif()
|
||||
|
||||
# Default to a Release build
|
||||
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
|
||||
@@ -582,11 +676,12 @@ else()
|
||||
find_package(stb MODULE)
|
||||
|
||||
find_package(Opus 1.3 MODULE REQUIRED)
|
||||
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED MODULE)
|
||||
|
||||
# wow
|
||||
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber)
|
||||
find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber filesystem)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
|
||||
find_package(gamemode 1.7 MODULE)
|
||||
@@ -634,15 +729,15 @@ if (APPLE)
|
||||
# Umbrella framework for everything GUI-related
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
|
||||
find_library(ICONV_LIBRARY iconv REQUIRED)
|
||||
list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY})
|
||||
# find_library(ICONV_LIBRARY iconv REQUIRED)
|
||||
# list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY})
|
||||
elseif (WIN32)
|
||||
# Target Windows 10
|
||||
add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00)
|
||||
set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi)
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} winmm iphlpapi ws2_32 wlanapi)
|
||||
if (MINGW)
|
||||
# PSAPI is the Process Status API
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version crypt32 rpcrt4 gdi32 wldap32 mswsock)
|
||||
endif()
|
||||
elseif (PLATFORM_HAIKU)
|
||||
# Haiku is so special :)
|
||||
@@ -655,6 +750,8 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
||||
set(PLATFORM_LIBRARIES rt)
|
||||
endif()
|
||||
|
||||
message(STATUS "Platform Libraries: ${PLATFORM_LIBRARIES}")
|
||||
|
||||
add_subdirectory(externals)
|
||||
|
||||
# pass targets from externals
|
||||
|
||||
@@ -542,10 +542,11 @@ function(AddCIPackage)
|
||||
PACKAGE
|
||||
EXTENSION
|
||||
MIN_VERSION
|
||||
DISABLED_PLATFORMS
|
||||
)
|
||||
|
||||
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN})
|
||||
set(multiValueArgs DISABLED_PLATFORMS)
|
||||
|
||||
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_VERSION)
|
||||
message(FATAL_ERROR "[CPMUtil] VERSION is required")
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 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-2.0-or-later
|
||||
|
||||
@@ -10,6 +13,10 @@ find_package_handle_standard_args(Opus
|
||||
VERSION_VAR OPUS_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::OPUS)
|
||||
endif()
|
||||
|
||||
if (Opus_FOUND AND NOT TARGET Opus::opus)
|
||||
add_library(Opus::opus ALIAS PkgConfig::OPUS)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 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-2.0-or-later
|
||||
|
||||
@@ -10,6 +13,10 @@ find_package_handle_standard_args(SPIRV-Tools
|
||||
VERSION_VAR SPIRV-Tools_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::SPIRV-Tools)
|
||||
endif()
|
||||
|
||||
if (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools)
|
||||
if (TARGET SPIRV-Tools)
|
||||
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
@@ -11,6 +14,10 @@ find_package_handle_standard_args(enet
|
||||
VERSION_VAR ENET_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::ENET)
|
||||
endif()
|
||||
|
||||
if (enet_FOUND AND NOT TARGET enet::enet)
|
||||
add_library(enet::enet ALIAS PkgConfig::ENET)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
@@ -11,6 +14,10 @@ find_package_handle_standard_args(libusb
|
||||
VERSION_VAR LIBUSB_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::LIBUSB)
|
||||
endif()
|
||||
|
||||
if (libusb_FOUND AND NOT TARGET libusb::usb)
|
||||
add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 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-2.0-or-later
|
||||
|
||||
@@ -9,6 +12,11 @@ if (lz4_CONSIDERED_CONFIGS)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
FixMsysPath(PkgConfig::LZ4)
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(lz4
|
||||
REQUIRED_VARS LZ4_LINK_LIBRARIES
|
||||
VERSION_VAR LZ4_VERSION
|
||||
|
||||
@@ -6,22 +6,34 @@
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)
|
||||
find_package_handle_standard_args(zstd
|
||||
REQUIRED_VARS ZSTD_LINK_LIBRARIES
|
||||
VERSION_VAR ZSTD_VERSION
|
||||
)
|
||||
find_package(zstd QUIET CONFIG)
|
||||
if (zstd_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(zstd CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)
|
||||
find_package_handle_standard_args(zstd
|
||||
REQUIRED_VARS ZSTD_LINK_LIBRARIES
|
||||
VERSION_VAR ZSTD_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
if (zstd_FOUND AND NOT TARGET zstd::zstd)
|
||||
if (TARGET zstd::libzstd_shared)
|
||||
if (TARGET zstd::libzstd_shared AND NOT YUZU_STATIC_BUILD)
|
||||
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()
|
||||
|
||||
get_target_property(ZSTD_TARGET zstd::zstd ALIASED_TARGET)
|
||||
|
||||
if (NOT TARGET zstd::libzstd)
|
||||
if (ZSTD_TARGET)
|
||||
add_library(zstd::libzstd ALIAS ${ZSTD_TARGET})
|
||||
else()
|
||||
add_library(zstd::libzstd ALIAS zstd::zstd)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
21
CMakeModules/FixMsysPaths.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
function(FixMsysPath target)
|
||||
get_target_property(include_dir ${target} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
|
||||
if (NOT (include_dir MATCHES "^/"))
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(root_default $ENV{MSYS2_LOCATION})
|
||||
if (root_default STREQUAL "")
|
||||
set(root_default "C:/msys64")
|
||||
endif()
|
||||
|
||||
set(MSYS_ROOT_PATH ${root_default} CACHE STRING "Location of the MSYS2 root")
|
||||
|
||||
set(include_dir "C:/msys64${include_dir}")
|
||||
set_target_properties(${target} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${include_dir})
|
||||
endfunction()
|
||||
@@ -1,58 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
set(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||
set(SDL2_PATH ${MINGW_PREFIX})
|
||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||
|
||||
# Specify the cross compiler
|
||||
set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}clang)
|
||||
set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}clang++)
|
||||
set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
|
||||
set(CMAKE_C_COMPILER_AR ${MINGW_TOOL_PREFIX}ar)
|
||||
set(CMAKE_CXX_COMPILER_AR ${MINGW_TOOL_PREFIX}ar)
|
||||
set(CMAKE_C_COMPILER_RANLIB ${MINGW_TOOL_PREFIX}ranlib)
|
||||
set(CMAKE_CXX_COMPILER_RANLIB ${MINGW_TOOL_PREFIX}ranlib)
|
||||
|
||||
# Mingw tools
|
||||
set(STRIP ${MINGW_TOOL_PREFIX}strip)
|
||||
set(WINDRES ${MINGW_TOOL_PREFIX}windres)
|
||||
set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
|
||||
|
||||
# ccache wrapper
|
||||
option(USE_CCACHE "Use ccache for compilation" OFF)
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE)
|
||||
message(STATUS "Using ccache found in PATH")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
else(CCACHE)
|
||||
message(WARNING "USE_CCACHE enabled, but no ccache found")
|
||||
endif(CCACHE)
|
||||
endif(USE_CCACHE)
|
||||
|
||||
# Search for programs in the build host directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
|
||||
# Echo modified cmake vars to screen for debugging purposes
|
||||
if(NOT DEFINED ENV{MINGW_DEBUG_INFO})
|
||||
message("")
|
||||
message("Custom cmake vars: (blank = system default)")
|
||||
message("-----------------------------------------")
|
||||
message("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
|
||||
message("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
|
||||
message("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
|
||||
message("* WINDRES : ${WINDRES}")
|
||||
message("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
|
||||
message("* STRIP : ${STRIP}")
|
||||
message("* USE_CCACHE : ${USE_CCACHE}")
|
||||
message("")
|
||||
# So that the debug info only appears once
|
||||
set(ENV{MINGW_DEBUG_INFO} SHOWN)
|
||||
endif()
|
||||
@@ -1,57 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2018 tech4me <guiwanglong@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
# Actually a hack, w/o this will cause some strange errors
|
||||
set(CMAKE_HOST_WIN32 TRUE)
|
||||
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
|
||||
set(SDL2_PATH ${MINGW_PREFIX})
|
||||
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
|
||||
|
||||
# Specify the cross compiler
|
||||
set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc)
|
||||
set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++)
|
||||
set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
|
||||
|
||||
# Mingw tools
|
||||
set(STRIP ${MINGW_TOOL_PREFIX}strip)
|
||||
set(WINDRES ${MINGW_TOOL_PREFIX}windres)
|
||||
set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
|
||||
|
||||
# ccache wrapper
|
||||
option(USE_CCACHE "Use ccache for compilation" OFF)
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE)
|
||||
message(STATUS "Using ccache found in PATH")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
else(CCACHE)
|
||||
message(WARNING "USE_CCACHE enabled, but no ccache found")
|
||||
endif(CCACHE)
|
||||
endif(USE_CCACHE)
|
||||
|
||||
# Search for programs in the build host directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
|
||||
# Echo modified cmake vars to screen for debugging purposes
|
||||
if(NOT DEFINED ENV{MINGW_DEBUG_INFO})
|
||||
message("")
|
||||
message("Custom cmake vars: (blank = system default)")
|
||||
message("-----------------------------------------")
|
||||
message("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
|
||||
message("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
|
||||
message("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
|
||||
message("* WINDRES : ${WINDRES}")
|
||||
message("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
|
||||
message("* STRIP : ${STRIP}")
|
||||
message("* USE_CCACHE : ${USE_CCACHE}")
|
||||
message("")
|
||||
# So that the debug info only appears once
|
||||
set(ENV{MINGW_DEBUG_INFO} SHOWN)
|
||||
endif()
|
||||
@@ -20,7 +20,7 @@
|
||||
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
|
||||
"git_version": "1.89.0",
|
||||
"version": "1.57",
|
||||
"find_args": "CONFIG",
|
||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch",
|
||||
"0002-use-marmasm.patch",
|
||||
|
||||
0
dist/dev.eden_emu.eden.desktop
vendored
Normal file → Executable file
107
dist/dev.eden_emu.eden.svg
vendored
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 9.2 KiB |
BIN
dist/eden.icns
vendored
BIN
dist/eden.ico
vendored
|
Before Width: | Height: | Size: 403 KiB After Width: | Height: | Size: 386 KiB |
83
dist/eden_named.svg
vendored
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 37 KiB |
9
dist/icon_variations/README.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Icon variations
|
||||
|
||||
These icons are licensed under GPLv3. Please see the [script for generating icons](../../tools/README.md) and appropriatedly redirect for seasonal icons.
|
||||
|
||||
- `base_named.svg` - Named variant.
|
||||
- `base_small.svg`: Variant used for tiny icons (16x16, 64x64, etc).
|
||||
- `base.svg`: Variant without branding/naming.
|
||||
|
||||
Try to keep the icons simple. And preferably automatically be able to be generated (to reduce maintanaince burden). Additionally keep the files small (use `svgo` and `optipng`) to not clutter the git.
|
||||
80
dist/icon_variations/base_small.svg
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
fill="none"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg7"
|
||||
sodipodi:docname="base_small.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs7">
|
||||
<linearGradient
|
||||
id="linearGradient10"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#f977d9;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
<stop
|
||||
style="stop-color:#a655d5;stop-opacity:1;"
|
||||
offset="0.54051435"
|
||||
id="stop13" />
|
||||
<stop
|
||||
style="stop-color:#984fd5;stop-opacity:1;"
|
||||
offset="0.5714342"
|
||||
id="stop12" />
|
||||
<stop
|
||||
style="stop-color:#8c4ad4;stop-opacity:1;"
|
||||
offset="0.59666741"
|
||||
id="stop14" />
|
||||
<stop
|
||||
style="stop-color:#3928d2;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop11" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient10"
|
||||
id="linearGradient11"
|
||||
x1="264.17508"
|
||||
y1="28.385544"
|
||||
x2="264.17508"
|
||||
y2="488.65109"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.97815818,0,0,0.97880258,4.570042,5.8799159)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.88388348"
|
||||
inkscape:cx="153.30075"
|
||||
inkscape:cy="243.24473"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="849"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg7"
|
||||
showguides="false" />
|
||||
<path
|
||||
id="path9"
|
||||
style="fill:url(#linearGradient11);fill-opacity:1;stroke:none;stroke-width:13.3314;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 262.97461 33.6875 A 218.44267 225.23091 0 0 0 138.83789 73.589844 L 141.13867 72.265625 L 161.2207 65.195312 L 181.01953 61.517578 L 204.35352 64.205078 L 228.96094 76.650391 L 265.80078 115 L 283 99.400391 L 304.59961 85.800781 L 331 76.400391 L 360.59961 69.599609 L 379.95508 69.208984 A 218.44267 225.23091 0 0 0 262.97461 33.6875 z M 380.07617 69.291016 L 350.19922 77.800781 L 329.19922 89.199219 L 307.40039 108 L 288.80078 129.80078 L 287.40039 135 L 302.40039 129.59961 L 319 127.80078 L 348.80078 131.80078 L 370.19922 141.40039 L 393 161.40039 L 399.59961 171.59961 L 374.80078 160.80078 L 338.40039 150.80078 L 309.19922 150 L 288.80078 154.40039 L 293.19922 155.19922 L 319.19922 168.80078 L 338 187.19922 L 350.80078 224 L 349.19922 260 L 326 222.80078 L 302.80078 194 L 277.59961 172.40039 L 269.19922 187.59961 L 256.80078 281.59961 L 258 364 L 278.40039 452.80078 L 297.19531 481.36914 A 218.44267 225.23091 0 0 0 481.41797 258.91797 A 218.44267 225.23091 0 0 0 380.07617 69.291016 z M 133.07422 77.839844 A 218.44267 225.23091 0 0 0 44.533203 258.91797 A 218.44267 225.23091 0 0 0 257.04102 484.06641 L 247.3457 458.62891 L 237.87109 418.18359 L 233.0625 380.42383 L 230.375 354.9668 L 229.95117 321.30859 L 232.35547 291.32812 L 237.44727 254.98242 L 254.55859 191.9082 L 261.62891 172.5332 L 255.54883 174.08984 L 240.98242 180.87695 L 229.59961 190.19922 L 210.59961 208.19922 L 197.40039 229.40039 L 186.40039 252.59961 L 173.40039 269 L 171.40039 253.19922 L 173.59961 229.40039 L 183 202.40039 L 199.40039 178 L 221.04102 153.44141 L 209.02148 155.70508 L 177.05859 162.77539 L 148.06836 171.40234 L 119.92578 183 L 120.63281 180.16992 L 129.82422 165.88672 L 151.17969 147.50195 L 172.95898 135.48242 L 190.07031 129.54102 L 209.02148 127.98633 L 227.6875 128.69336 L 247.76953 128.41016 L 246.49805 125.1582 L 226.69922 105.92383 L 219.62695 97.439453 L 221.4668 90.085938 L 206.75781 94.044922 L 195.86914 95.458984 L 179.46289 88.671875 L 156.12891 81.458984 L 133.07422 77.839844 z " />
|
||||
<path
|
||||
style="fill:#1b1b1b;fill-opacity:0.12492698;stroke:none;stroke-width:13.374;stroke-opacity:0.415999;paint-order:stroke fill markers"
|
||||
d="m 259.36665,490.16617 39.03323,-6.96642 -20,-30.4 -20.4,-88.8 -1.2,-82.4 12.4,-94 8.4,-15.2 25.2,21.6 23.2,28.8 23.2,37.2 1.6,-36 -12.8,-36.8 -18.8,-18.4 -26,-13.6 -4.4,-0.8 20.4,-4.4 29.2,0.8 36.4,10 24.8,10.8 -6.6,-10.2 -22.8,-20 -21.4,-9.6 -29.8,-4 -16.6,1.8 -15,5.4 1.4,-5.2 18.6,-21.8 21.8,-18.800003 21,-11.4 30.2,-8.6 -19.8,0.4 -29.6,6.8 -26.4,9.4 -21.6,13.6 -17.2,15.600003 -36.83882,-38.349628 -24.60732,-12.445079 -23.33452,-2.687006 -19.79899,3.676955 -20.08184,7.071068 -9.33381,5.374012 24.32448,3.818376 23.33452,7.212489 16.40488,6.788226 10.88944,-1.414214 14.70782,-3.959798 -1.83847,7.353911 7.07106,8.485288 19.79899,19.2333 1.2728,3.25269 -20.08184,0.28284 -18.66762,-0.7071 -18.95046,1.55563 -17.11198,5.9397 -21.77889,12.02081 -21.35462,18.38478 -9.19239,14.28356 -0.70711,2.82843 28.14285,-11.59656 28.99138,-8.6267 31.96122,-7.07107 12.02082,-2.26274 -21.64158,24.55783 -16.4,24.4 -9.4,27 -2.2,23.8 2,15.8 13,-16.4 11,-23.2 13.2,-21.2 19,-18 11.38199,-9.32209 14.5664,-6.78822 6.08112,-1.55564 -7.07107,19.37473 -17.11198,63.07393 -5.09117,36.34528 -2.40416,29.98133 0.42426,33.65828 2.68701,25.45585 4.80832,37.7595 9.47523,40.44651 z"
|
||||
id="path8-4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
BIN
dist/qt_themes/default/icons/256x256/eden.png
vendored
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 17 KiB |
BIN
dist/qt_themes/default/icons/256x256/eden_named.png
vendored
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 29 KiB |
25
dist/qt_themes/qdarkstyle/style.qss
vendored
@@ -821,31 +821,6 @@ QTabBar QToolButton::left-arrow:disabled {
|
||||
image: url(:/qss_icons/rc/left_arrow_disabled.png);
|
||||
}
|
||||
|
||||
QDockWidget {
|
||||
background: #31363b;
|
||||
border: 1px solid #403F3F;
|
||||
titlebar-close-icon: url(:/qss_icons/rc/close.png);
|
||||
titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
|
||||
}
|
||||
|
||||
QDockWidget::close-button,
|
||||
QDockWidget::float-button {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QDockWidget::close-button:hover,
|
||||
QDockWidget::float-button:hover {
|
||||
background: rgba(255, 255, 255, 10);
|
||||
}
|
||||
|
||||
QDockWidget::close-button:pressed,
|
||||
QDockWidget::float-button:pressed {
|
||||
padding: 1px -1px -1px 1px;
|
||||
background: rgba(255, 255, 255, 10);
|
||||
}
|
||||
|
||||
QTreeView,
|
||||
QListView {
|
||||
border: 1px solid #54575B;
|
||||
|
||||
@@ -1685,54 +1685,6 @@ QTabBar QToolButton::right-arrow:disabled {
|
||||
image: url(":/qss_icons/rc/arrow_right_disabled.png");
|
||||
}
|
||||
|
||||
/* QDockWiget -------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
QDockWidget {
|
||||
outline: 1px solid #32414B;
|
||||
background-color: #19232D;
|
||||
border: 1px solid #32414B;
|
||||
border-radius: 4px;
|
||||
titlebar-close-icon: url(":/qss_icons/rc/window_close.png");
|
||||
titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png");
|
||||
}
|
||||
|
||||
QDockWidget::title {
|
||||
/* Better size for title bar */
|
||||
padding: 6px;
|
||||
spacing: 4px;
|
||||
border: none;
|
||||
background-color: #32414B;
|
||||
}
|
||||
|
||||
QDockWidget::close-button {
|
||||
background-color: #32414B;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QDockWidget::close-button:hover {
|
||||
image: url(":/qss_icons/rc/window_close_focus.png");
|
||||
}
|
||||
|
||||
QDockWidget::close-button:pressed {
|
||||
image: url(":/qss_icons/rc/window_close_pressed.png");
|
||||
}
|
||||
|
||||
QDockWidget::float-button {
|
||||
background-color: #32414B;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
QDockWidget::float-button:hover {
|
||||
image: url(":/qss_icons/rc/window_undock_focus.png");
|
||||
}
|
||||
|
||||
QDockWidget::float-button:pressed {
|
||||
image: url(":/qss_icons/rc/window_undock_pressed.png");
|
||||
}
|
||||
|
||||
/* QTreeView QListView QTableView -----------------------------------------
|
||||
|
||||
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview
|
||||
|
||||
BIN
dist/yuzu.bmp
vendored
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
BIN
dist/yuzu.icns
vendored
7
externals/CMakeLists.txt
vendored
@@ -160,13 +160,6 @@ if (YUZU_USE_BUNDLED_SIRIT)
|
||||
AddJsonPackage(sirit-ci)
|
||||
else()
|
||||
AddJsonPackage(sirit)
|
||||
# Change to old-but-more-cacheable debug info on Windows
|
||||
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||
get_target_property(sirit_opts sirit COMPILE_OPTIONS)
|
||||
list(FILTER sirit_opts EXCLUDE REGEX "/Zi")
|
||||
list(APPEND sirit_opts "/Z7")
|
||||
set_target_properties(sirit PROPERTIES COMPILE_OPTIONS "${sirit_opts}")
|
||||
endif()
|
||||
if(MSVC AND CXX_CLANG)
|
||||
target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument)
|
||||
endif()
|
||||
|
||||
30
externals/ffmpeg/CMakeLists.txt
vendored
@@ -25,18 +25,26 @@ if (UNIX AND NOT ANDROID)
|
||||
if (NOT APPLE)
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(PLATFORM_SUN)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"/usr/lib/xorg/amd64/libdrm.so")
|
||||
find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib)
|
||||
if(LIBDRM_LIB)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"${LIBDRM_LIB}")
|
||||
message(STATUS "Found libdrm at: ${LIBDRM_LIB}")
|
||||
else()
|
||||
message(WARNING "libdrm not found, disabling libdrm support")
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--disable-libdrm)
|
||||
endif()
|
||||
else()
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-libdrm)
|
||||
endif()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-libdrm)
|
||||
endif()
|
||||
|
||||
if(LIBVA_FOUND)
|
||||
@@ -89,7 +97,7 @@ if (UNIX AND NOT ANDROID)
|
||||
endif(CUDA_FOUND)
|
||||
endif()
|
||||
|
||||
if (VDPAU_FOUND)
|
||||
if (VDPAU_FOUND AND NOT APPLE)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-vdpau
|
||||
--enable-hwaccel=h264_vdpau
|
||||
@@ -247,11 +255,19 @@ else()
|
||||
SYSTEM_THREADS)
|
||||
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
|
||||
# BSD make or Solaris make don't support ffmpeg make-j8
|
||||
if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD)
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
make -j${SYSTEM_THREADS}
|
||||
make ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
3
externals/ffmpeg/cpmfile.json
vendored
@@ -15,8 +15,7 @@
|
||||
"disabled_platforms": [
|
||||
"freebsd-amd64",
|
||||
"solaris-amd64",
|
||||
"openbsd-amd64",
|
||||
"macos-universal"
|
||||
"openbsd-amd64"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
4
externals/nx_tzdb/cpmfile.json
vendored
@@ -5,7 +5,7 @@
|
||||
"git_host": "git.crueter.xyz",
|
||||
"artifact": "%VERSION%.tar.gz",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "87abb2aeca716d5d77b05317086dbc2f8acfc2f3f76ce4778345ee3df19973e6cd8ecbf16cfab5ad94c9636a6c44fd3588f9aadd3cba89403cfd56c8bec645c5",
|
||||
"version": "091025"
|
||||
"hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
|
||||
"version": "121125"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ if (MSVC AND NOT CXX_CLANG)
|
||||
|
||||
# /W4 - Level 4 warnings
|
||||
# /MP - Multi-threaded compilation
|
||||
# /Zi - Output debugging information
|
||||
# /Zm - Specifies the precompiled header memory allocation limit
|
||||
# /Zo - Enhanced debug info for optimized builds
|
||||
# /permissive- - Enables stricter C++ standards conformance checks
|
||||
@@ -98,11 +97,6 @@ if (MSVC AND NOT CXX_CLANG)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options(/QIntel-jcc-erratum)
|
||||
endif()
|
||||
@@ -127,7 +121,7 @@ else()
|
||||
-Werror=unused
|
||||
|
||||
-Wno-attributes
|
||||
-Wno-invalid-offsetof
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>
|
||||
-Wno-unused-parameter
|
||||
-Wno-missing-field-initializers
|
||||
)
|
||||
@@ -176,16 +170,28 @@ else()
|
||||
add_compile_definitions(_FILE_OFFSET_BITS=64)
|
||||
endif()
|
||||
|
||||
if (YUZU_STATIC_BUILD)
|
||||
add_compile_definitions(QT_STATICPLUGIN)
|
||||
|
||||
# macos doesn't even let you make static executables... wtf?
|
||||
if (NOT APPLE)
|
||||
add_compile_options(-static)
|
||||
if (YUZU_STATIC_BUILD)
|
||||
# yuzu-cmd requires us to explicitly link libpthread, libgcc, and libstdc++ as static
|
||||
# At a guess, it's probably because Qt handles the Qt executable for us, whereas this does not
|
||||
add_link_options(-static -lpthread)
|
||||
add_link_options(-static-libgcc -static-libstdc++)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
add_compile_definitions(MINGW_HAS_SECURE_API)
|
||||
|
||||
# Only windows has this requirement, thanks windows
|
||||
if (WIN32)
|
||||
if (WIN32 AND ARCHITECTURE_x86_64)
|
||||
add_compile_options("-msse4.1")
|
||||
endif()
|
||||
if (MINGW_STATIC_BUILD)
|
||||
add_compile_definitions(QT_STATICPLUGIN)
|
||||
add_compile_options("-static")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
|
||||
|
||||
@@ -16,11 +16,15 @@ import java.io.FileOutputStream
|
||||
import java.security.KeyStore
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import android.content.res.Configuration
|
||||
import android.os.LocaleList
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.DocumentsTree
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.PowerStateUpdater
|
||||
import java.util.Locale
|
||||
|
||||
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
||||
|
||||
@@ -73,5 +77,38 @@ class YuzuApplication : Application() {
|
||||
|
||||
val appContext: Context
|
||||
get() = application.applicationContext
|
||||
|
||||
private val LANGUAGE_CODES = arrayOf(
|
||||
"system", "en", "es", "fr", "de", "it", "pt", "pt-BR", "ru", "ja", "ko",
|
||||
"zh-CN", "zh-TW", "pl", "cs", "nb", "hu", "uk", "vi", "id", "ar", "ckb", "fa", "he", "sr"
|
||||
)
|
||||
|
||||
fun applyLanguage(context: Context): Context {
|
||||
val languageIndex = IntSetting.APP_LANGUAGE.getInt()
|
||||
val langCode = if (languageIndex in LANGUAGE_CODES.indices) {
|
||||
LANGUAGE_CODES[languageIndex]
|
||||
} else {
|
||||
"system"
|
||||
}
|
||||
|
||||
if (langCode == "system") {
|
||||
return context
|
||||
}
|
||||
|
||||
val locale = when {
|
||||
langCode.contains("-") -> {
|
||||
val parts = langCode.split("-")
|
||||
Locale.Builder().setLanguage(parts[0]).setRegion(parts[1]).build()
|
||||
}
|
||||
else -> Locale.Builder().setLanguage(langCode).build()
|
||||
}
|
||||
|
||||
Locale.setDefault(locale)
|
||||
|
||||
val config = Configuration(context.resources.configuration)
|
||||
config.setLocales(LocaleList(locale))
|
||||
|
||||
return context.createConfigurationContext(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||
|
||||
private var foregroundService: Intent? = null
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Log.gameLaunched = true
|
||||
ThemeHelper.setTheme(this)
|
||||
|
||||
@@ -32,6 +32,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
MAX_ANISOTROPY("max_anisotropy"),
|
||||
THEME("theme"),
|
||||
THEME_MODE("theme_mode"),
|
||||
APP_LANGUAGE("app_language"),
|
||||
OVERLAY_SCALE("control_scale"),
|
||||
OVERLAY_OPACITY("control_opacity"),
|
||||
LOCK_DRAWER("lock_drawer"),
|
||||
|
||||
@@ -667,10 +667,11 @@ abstract class SettingsItem(
|
||||
)
|
||||
)
|
||||
put(
|
||||
SliderSetting(
|
||||
SpinBoxSetting(
|
||||
IntSetting.CPU_TICKS,
|
||||
titleId = R.string.cpu_ticks,
|
||||
descriptionId = 0,
|
||||
valueHint = R.string.cpu_ticks,
|
||||
min = 77,
|
||||
max = 65535
|
||||
)
|
||||
@@ -756,6 +757,15 @@ abstract class SettingsItem(
|
||||
titleId = R.string.enable_update_checks,
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.APP_LANGUAGE,
|
||||
titleId = R.string.app_language,
|
||||
descriptionId = R.string.app_language_description,
|
||||
choicesId = R.array.appLanguageNames,
|
||||
valuesId = R.array.appLanguageValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_DEBUG,
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// 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
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
import android.content.Context
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
@@ -24,6 +29,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||
import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
import org.yuzu.yuzu_emu.utils.collect
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
@@ -32,6 +38,10 @@ class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ThemeHelper.setTheme(this)
|
||||
|
||||
@@ -125,6 +135,16 @@ class SettingsActivity : AppCompatActivity() {
|
||||
NativeConfig.savePerGameConfig()
|
||||
NativeConfig.unloadPerGameConfig()
|
||||
}
|
||||
|
||||
if (settingsViewModel.shouldRecreateForLanguageChange.value) {
|
||||
settingsViewModel.setShouldRecreateForLanguageChange(false)
|
||||
val relaunchIntent = packageManager?.getLaunchIntentForPackage(packageName)
|
||||
if (relaunchIntent != null) {
|
||||
relaunchIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK or android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(relaunchIntent)
|
||||
android.os.Process.killProcess(android.os.Process.myPid())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -425,6 +425,14 @@ class SettingsAdapter(
|
||||
position
|
||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||
|
||||
// reset language if detected
|
||||
if (item.setting.key == "app_language") {
|
||||
// recreate page apply language change instantly
|
||||
fragment.requireActivity().recreate()
|
||||
|
||||
settingsViewModel.setShouldRecreateForLanguageChange(true)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.MotionEvent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
@@ -197,6 +200,54 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||
updateValidity(newValue)
|
||||
}
|
||||
|
||||
fun attachRepeat(button: View, delta: Int) {
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
var runnable: Runnable? = null
|
||||
val initialDelay = 400L
|
||||
val minDelay = 40L
|
||||
val accelerationFactor = 0.75f
|
||||
|
||||
button.setOnTouchListener { v, event ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val newValue = (current + delta)
|
||||
spinboxBinding.editValue.setText(newValue.toString())
|
||||
updateValidity(newValue)
|
||||
|
||||
var delay = initialDelay
|
||||
runnable = object : Runnable {
|
||||
override fun run() {
|
||||
val curr = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val next = curr + delta
|
||||
spinboxBinding.editValue.setText(next.toString())
|
||||
updateValidity(next)
|
||||
// accelerate
|
||||
delay = (delay * accelerationFactor).toLong().coerceAtLeast(minDelay)
|
||||
handler.postDelayed(this, delay)
|
||||
}
|
||||
}
|
||||
handler.postDelayed(runnable!!, initialDelay)
|
||||
true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
if (runnable != null) {
|
||||
handler.removeCallbacks(runnable!!)
|
||||
runnable = null
|
||||
}
|
||||
v.performClick()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attachRepeat(spinboxBinding.buttonDecrement, -1)
|
||||
attachRepeat(spinboxBinding.buttonIncrement, 1)
|
||||
|
||||
spinboxBinding.editValue.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
@@ -336,6 +387,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||
.show()
|
||||
}
|
||||
scSetting.setSelectedValue(value)
|
||||
|
||||
if (scSetting.setting.key == "app_language") {
|
||||
settingsViewModel.setShouldRecreateForLanguageChange(true)
|
||||
// recreate page apply language change instantly
|
||||
requireActivity().recreate()
|
||||
}
|
||||
}
|
||||
|
||||
is StringSingleChoiceSetting -> {
|
||||
|
||||
@@ -1030,8 +1030,10 @@ class SettingsFragmentPresenter(
|
||||
override fun reset() = IntSetting.THEME.setInt(defaultValue)
|
||||
}
|
||||
|
||||
add(HeaderSetting(R.string.app_settings))
|
||||
add(IntSetting.APP_LANGUAGE.key)
|
||||
|
||||
if (NativeLibrary.isUpdateCheckerEnabled()) {
|
||||
add(HeaderSetting(R.string.app_settings))
|
||||
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -54,6 +57,8 @@ class SettingsViewModel : ViewModel() {
|
||||
private val _shouldShowResetInputDialog = MutableStateFlow(false)
|
||||
val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow()
|
||||
|
||||
private val _shouldRecreateForLanguageChange = MutableStateFlow(false)
|
||||
val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow()
|
||||
fun setShouldRecreate(value: Boolean) {
|
||||
_shouldRecreate.value = value
|
||||
}
|
||||
@@ -103,6 +108,10 @@ class SettingsViewModel : ViewModel() {
|
||||
_shouldShowResetInputDialog.value = value
|
||||
}
|
||||
|
||||
fun setShouldRecreateForLanguageChange(value: Boolean) {
|
||||
_shouldRecreateForLanguageChange.value = value
|
||||
}
|
||||
|
||||
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
|
||||
try {
|
||||
InputHandler.registeredControllers[currentDevice]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package org.yuzu.yuzu_emu.ui.main
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
@@ -53,6 +54,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import kotlin.text.compareTo
|
||||
import androidx.core.net.toUri
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
|
||||
class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
@@ -68,6 +70,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
||||
private var checkedDecryption = false
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(YuzuApplication.applyLanguage(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace AndroidSettings {
|
||||
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
||||
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
||||
Settings::Category::Android};
|
||||
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
|
||||
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
|
||||
Settings::Category::Android};
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "video_core/vulkan_common/vma.h"
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
|
||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 65 KiB |
@@ -391,6 +391,61 @@
|
||||
<item>2</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="appLanguageNames">
|
||||
<item>@string/app_language_system</item>
|
||||
<item>@string/app_language_english</item>
|
||||
<item>@string/app_language_spanish</item>
|
||||
<item>@string/app_language_french</item>
|
||||
<item>@string/app_language_german</item>
|
||||
<item>@string/app_language_italian</item>
|
||||
<item>@string/app_language_portuguese</item>
|
||||
<item>@string/app_language_brazilian_portuguese</item>
|
||||
<item>@string/app_language_russian</item>
|
||||
<item>@string/app_language_japanese</item>
|
||||
<item>@string/app_language_korean</item>
|
||||
<item>@string/app_language_simplified_chinese</item>
|
||||
<item>@string/app_language_traditional_chinese</item>
|
||||
<item>@string/app_language_polish</item>
|
||||
<item>@string/app_language_czech</item>
|
||||
<item>@string/app_language_norwegian</item>
|
||||
<item>@string/app_language_hungarian</item>
|
||||
<item>@string/app_language_ukrainian</item>
|
||||
<item>@string/app_language_vietnamese</item>
|
||||
<item>@string/app_language_indonesian</item>
|
||||
<item>@string/app_language_arabic</item>
|
||||
<item>@string/app_language_central_kurdish</item>
|
||||
<item>@string/app_language_persian</item>
|
||||
<item>@string/app_language_hebrew</item>
|
||||
<item>@string/app_language_serbian</item>
|
||||
</string-array>
|
||||
<integer-array name="appLanguageValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
<item>17</item>
|
||||
<item>18</item>
|
||||
<item>19</item>
|
||||
<item>20</item>
|
||||
<item>21</item>
|
||||
<item>22</item>
|
||||
<item>23</item>
|
||||
<item>24</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="outputEngineEntries">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/oboe</item>
|
||||
|
||||
@@ -1028,6 +1028,35 @@
|
||||
<string name="use_black_backgrounds">Black backgrounds</string>
|
||||
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
||||
|
||||
<!-- App Language -->
|
||||
<string name="app_language">App Language</string>
|
||||
<string name="app_language_description">Change the language of the app interface</string>
|
||||
<string name="app_language_system">Follow System</string>
|
||||
<string name="app_language_english">English</string>
|
||||
<string name="app_language_spanish">Español</string>
|
||||
<string name="app_language_french">Français</string>
|
||||
<string name="app_language_german">Deutsch</string>
|
||||
<string name="app_language_italian">Italiano</string>
|
||||
<string name="app_language_portuguese">Português</string>
|
||||
<string name="app_language_brazilian_portuguese">Português do Brasil</string>
|
||||
<string name="app_language_russian">Русский</string>
|
||||
<string name="app_language_japanese">日本語</string>
|
||||
<string name="app_language_korean">한국어</string>
|
||||
<string name="app_language_simplified_chinese">简体中文</string>
|
||||
<string name="app_language_traditional_chinese">繁體中文</string>
|
||||
<string name="app_language_polish">Polski</string>
|
||||
<string name="app_language_czech">Čeština</string>
|
||||
<string name="app_language_norwegian">Norsk bokmål</string>
|
||||
<string name="app_language_hungarian">Magyar</string>
|
||||
<string name="app_language_ukrainian">Українська</string>
|
||||
<string name="app_language_vietnamese">Tiếng Việt</string>
|
||||
<string name="app_language_indonesian">Bahasa Indonesia</string>
|
||||
<string name="app_language_arabic">العربية</string>
|
||||
<string name="app_language_central_kurdish">کوردیی ناوەندی</string>
|
||||
<string name="app_language_persian">فارسی</string>
|
||||
<string name="app_language_hebrew">עברית</string>
|
||||
<string name="app_language_serbian">Српски</string>
|
||||
|
||||
<!-- Static Themes -->
|
||||
<string name="static_theme_color">Theme Color</string>
|
||||
<string name="eden_theme">Eden (Default)</string>
|
||||
|
||||
@@ -257,6 +257,8 @@ else()
|
||||
target_link_libraries(common PUBLIC Boost::headers)
|
||||
endif()
|
||||
|
||||
target_link_libraries(common PUBLIC Boost::filesystem)
|
||||
|
||||
if (lz4_ADDED)
|
||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -103,46 +106,60 @@ template <>
|
||||
|
||||
#else
|
||||
|
||||
// Some architectures lack u128, there is no definitive way to check them all without even more macro magic
|
||||
// so let's just... do this; add your favourite arches once they get u128 support :)
|
||||
#if (defined(__clang__) || defined(__GNUC__)) && (defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64))
|
||||
using RealU128 = unsigned __int128;
|
||||
# define SYNC_VAL_COMPARE_AND_SWAP(p, e, v) __sync_val_compare_and_swap(p, e, v)
|
||||
# define SYNC_BOOL_COMPARE_AND_SWAP(p, e, v) __sync_bool_compare_and_swap(p, e, v)
|
||||
# define U128_ZERO_INIT 0
|
||||
#else
|
||||
using RealU128 = u128;
|
||||
# define SYNC_VAL_COMPARE_AND_SWAP(p, e, v) ((*p == e) ? *p = v : *p)
|
||||
# define SYNC_BOOL_COMPARE_AND_SWAP(p, e, v) ((*p == e) ? (void)(*p = v) : (void)0), true
|
||||
# define U128_ZERO_INIT {}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
return SYNC_BOOL_COMPARE_AND_SWAP(pointer, expected, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
RealU128 value_a;
|
||||
RealU128 expected_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||
return SYNC_BOOL_COMPARE_AND_SWAP((RealU128*)pointer, expected_a, value_a);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected, T& actual) {
|
||||
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||
actual = SYNC_VAL_COMPARE_AND_SWAP(pointer, expected, value);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected,
|
||||
u128& actual) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
unsigned __int128 actual_a;
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected, u128& actual) {
|
||||
RealU128 value_a;
|
||||
RealU128 expected_a;
|
||||
RealU128 actual_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||
actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||
actual_a = SYNC_VAL_COMPARE_AND_SWAP((RealU128*)pointer, expected_a, value_a);
|
||||
std::memcpy(actual.data(), &actual_a, sizeof(u128));
|
||||
return actual_a == expected_a;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u128 AtomicLoad128(u64* pointer) {
|
||||
unsigned __int128 zeros_a = 0;
|
||||
unsigned __int128 result_a =
|
||||
__sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
|
||||
|
||||
RealU128 zeros_a = U128_ZERO_INIT;
|
||||
RealU128 result_a = SYNC_VAL_COMPARE_AND_SWAP((RealU128*)pointer, zeros_a, zeros_a);
|
||||
u128 result;
|
||||
std::memcpy(result.data(), &result_a, sizeof(u128));
|
||||
return result;
|
||||
}
|
||||
#undef U128_ZERO_INIT
|
||||
#undef SYNC_VAL_COMPARE_AND_SWAP
|
||||
#undef SYNC_BOOL_COMPARE_AND_SWAP
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,16 +14,29 @@ namespace fs = std::filesystem;
|
||||
|
||||
fs::path GetKvdbPath()
|
||||
{
|
||||
return GetLegacyPath(EmuPath::RyujinxDir) / "bis" / "system" / "save" / "8000000000000000" / "0"
|
||||
return GetKvdbPath(GetLegacyPath(EmuPath::RyujinxDir));
|
||||
}
|
||||
|
||||
fs::path GetKvdbPath(const fs::path& path) {
|
||||
return path / "bis" / "system" / "save" / "8000000000000000" / "0"
|
||||
/ "imkvdb.arc";
|
||||
}
|
||||
|
||||
fs::path GetRyuPathFromSavePath(const fs::path& path) {
|
||||
// This is a horrible hack, but I cba to find something better
|
||||
return path.parent_path().parent_path().parent_path().parent_path().parent_path();
|
||||
}
|
||||
|
||||
fs::path GetRyuSavePath(const u64 &save_id)
|
||||
{
|
||||
return GetRyuSavePath(GetLegacyPath(EmuPath::RyujinxDir), save_id);
|
||||
}
|
||||
|
||||
std::filesystem::path GetRyuSavePath(const std::filesystem::path& path, const u64& save_id) {
|
||||
std::string hex = fmt::format("{:016x}", save_id);
|
||||
|
||||
// TODO: what's the difference between 0 and 1?
|
||||
return GetLegacyPath(EmuPath::RyujinxDir) / "bis" / "user" / "save" / hex / "0";
|
||||
// TODO: what's the difference between 0 and 1?
|
||||
return path / "bis" / "user" / "save" / hex / "0";
|
||||
}
|
||||
|
||||
IMENReadResult ReadKvdb(const fs::path &path, std::vector<IMEN> &imens)
|
||||
|
||||
@@ -7,16 +7,17 @@
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
constexpr const char IMEN_MAGIC[4] = {0x49, 0x4d, 0x45, 0x4e};
|
||||
constexpr const char IMKV_MAGIC[4] = {0x49, 0x4d, 0x4b, 0x56};
|
||||
constexpr const u8 IMEN_SIZE = 0x8c;
|
||||
|
||||
fs::path GetKvdbPath();
|
||||
fs::path GetRyuSavePath(const u64 &program_id);
|
||||
std::filesystem::path GetKvdbPath();
|
||||
std::filesystem::path GetKvdbPath(const std::filesystem::path &path);
|
||||
std::filesystem::path GetRyuPathFromSavePath(const std::filesystem::path &path);
|
||||
std::filesystem::path GetRyuSavePath(const u64 &save_id);
|
||||
std::filesystem::path GetRyuSavePath(const std::filesystem::path &path, const u64 &save_id);
|
||||
|
||||
enum class IMENReadResult {
|
||||
Nonexistent, // ryujinx not found
|
||||
@@ -35,6 +36,6 @@ struct IMEN
|
||||
|
||||
static_assert(sizeof(IMEN) == 0x10, "IMEN has incorrect size.");
|
||||
|
||||
IMENReadResult ReadKvdb(const fs::path &path, std::vector<IMEN> &imens);
|
||||
IMENReadResult ReadKvdb(const std::filesystem::path &path, std::vector<IMEN> &imens);
|
||||
|
||||
} // namespace Common::FS
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
#include "symlink.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <fmt/format.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// The sole purpose of this file is to treat symlinks like symlinks on POSIX,
|
||||
@@ -15,29 +17,40 @@ namespace fs = std::filesystem;
|
||||
// This is because, for some inexplicable reason, Microsoft has locked symbolic
|
||||
// links behind a "security policy", whereas directory junctions--functionally identical
|
||||
// for directories, by the way--are not. Why? I don't know.
|
||||
// And no, they do NOT provide a standard API for this (at least to my knowledge).
|
||||
// CreateSymbolicLink, even when EXPLICITLY TOLD to create a junction, still fails
|
||||
// because of their security policy.
|
||||
// I don't know what kind of drugs the Windows developers have been on since NT started.
|
||||
|
||||
// Microsoft still has not implemented any of this in their std::filesystem implemenation,
|
||||
// which ALSO means that it DOES NOT FOLLOW ANY DIRECTORY JUNCTIONS... AT ALL.
|
||||
// Nor does any of their command line utilities or APIs. So you're quite literally
|
||||
// on your own.
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
bool CreateSymlink(const fs::path &from, const fs::path &to)
|
||||
bool CreateSymlink(fs::path from, fs::path to)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::string command = fmt::format("mklink /J {} {}", to.string(), from.string());
|
||||
return system(command.c_str()) == 0;
|
||||
#else
|
||||
from.make_preferred();
|
||||
to.make_preferred();
|
||||
|
||||
std::error_code ec;
|
||||
fs::create_directory_symlink(from, to, ec);
|
||||
return !ec;
|
||||
#ifdef _WIN32
|
||||
if (ec) {
|
||||
const std::string command = fmt::format("mklink /J \"{}\" \"{}\"",
|
||||
to.string(),
|
||||
from.string());
|
||||
return system(command.c_str()) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return !ec;
|
||||
}
|
||||
|
||||
bool IsSymlink(const fs::path &path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
auto attributes = GetFileAttributesW(path.wstring().c_str());
|
||||
return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
#else
|
||||
return fs::is_symlink(path);
|
||||
#endif
|
||||
return boost::filesystem::is_symlink(boost::filesystem::path{path});
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <filesystem>
|
||||
namespace Common::FS {
|
||||
|
||||
bool CreateSymlink(const std::filesystem::path &from, const std::filesystem::path &to);
|
||||
bool CreateSymlink(std::filesystem::path from, std::filesystem::path to);
|
||||
bool IsSymlink(const std::filesystem::path &path);
|
||||
|
||||
} // namespace Common::FS
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// 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
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "common/heap_tracker.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/assert.h"
|
||||
@@ -37,8 +36,6 @@ HeapTracker::~HeapTracker() = default;
|
||||
|
||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
MemoryPermission perm, bool is_separate_heap) {
|
||||
bool rebuild_required = false;
|
||||
|
||||
// When mapping other memory, map pages immediately.
|
||||
if (!is_separate_heap) {
|
||||
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
|
||||
@@ -60,29 +57,11 @@ void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
|
||||
// Insert into mappings.
|
||||
m_map_count++;
|
||||
const auto it = m_mappings.insert(*map);
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count >= m_max_resident_map_count) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
m_mappings.insert(*map);
|
||||
}
|
||||
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
}
|
||||
// Finally, map.
|
||||
this->DeferredMapSeparateHeap(virtual_offset);
|
||||
}
|
||||
|
||||
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
||||
@@ -169,7 +148,6 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
||||
|
||||
// Clamp to end.
|
||||
next = (std::min)(next, end);
|
||||
|
||||
// Reprotect, if we need to.
|
||||
if (should_protect) {
|
||||
m_buffer.Protect(cur, next - cur, perm);
|
||||
@@ -180,6 +158,51 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
||||
}
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
||||
if (m_buffer.IsInVirtualRange(fault_address)) {
|
||||
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
bool rebuild_required = false;
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
// Check to ensure this was a non-resident separate heap mapping.
|
||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||
if (it == m_mappings.end() || it->is_resident) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count > m_max_resident_map_count) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||
|
||||
@@ -190,8 +213,8 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
// Despite being worse in theory, this has proven to be better in practice than more
|
||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||
// lock contention.
|
||||
const size_t desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
const size_t evict_count = m_resident_map_count - desired_count;
|
||||
std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
|
||||
@@ -730,7 +730,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(host_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
ASSERT(host_offset + length <= backing_size);
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
@@ -741,7 +743,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
}
|
||||
@@ -751,7 +755,9 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
||||
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
if (impl && virtual_base) {
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
}
|
||||
if (length == 0 || !virtual_base || !impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,11 +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 <type_traits>
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
#include "common/swap.h"
|
||||
|
||||
// adapted from https://github.com/fmtlib/fmt/issues/2704
|
||||
// a generic formatter for enum classes
|
||||
@@ -20,3 +23,14 @@ struct fmt::formatter<T, std::enable_if_t<std::is_enum_v<T>, char>>
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename U>
|
||||
struct fmt::formatter<SwapStructT<T, U>> {
|
||||
constexpr auto parse(format_parse_context& ctx) {
|
||||
return ctx.begin();
|
||||
}
|
||||
template <typename FormatContext>
|
||||
auto format(const SwapStructT<T, U>& reg, FormatContext& ctx) const {
|
||||
return fmt::format_to(ctx.out(), "{}", T(reg));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -359,6 +359,9 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
for (const auto& reset : values.linkage.restore_functions) {
|
||||
reset();
|
||||
}
|
||||
|
||||
// Reset per-game flags
|
||||
values.use_squashed_iterated_blend = false;
|
||||
}
|
||||
|
||||
static bool configuring_global = true;
|
||||
|
||||
@@ -560,6 +560,60 @@ struct Values {
|
||||
false,
|
||||
&sample_shading};
|
||||
|
||||
#ifdef ANDROID
|
||||
// Shader Float Controls (Android only) - Eden Veil / Extensions
|
||||
// Force enable VK_KHR_shader_float_controls even if driver has known issues
|
||||
// Allows fine-tuning float behavior to match Switch/Maxwell or optimize performance
|
||||
SwitchableSetting<bool> shader_float_controls_force_enable{linkage,
|
||||
false,
|
||||
"shader_float_controls_force_enable",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Paired};
|
||||
|
||||
// Individual float behavior controls (visible only when force_enable is true)
|
||||
// Multiple can be active simultaneously EXCEPT FTZ and DenormPreserve (mutually exclusive)
|
||||
//
|
||||
// Recommended configurations:
|
||||
// Switch-native: FTZ=ON, RTE=ON, SignedZero=ON (matches Maxwell behavior)
|
||||
// Performance: FTZ=ON only (fastest)
|
||||
// Accuracy: DenormPreserve=ON, RTE=ON, SignedZero=ON (slowest, highest precision)
|
||||
SwitchableSetting<bool> shader_float_ftz{linkage,
|
||||
false,
|
||||
"shader_float_ftz",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_denorm_preserve{linkage,
|
||||
false,
|
||||
"shader_float_denorm_preserve",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_rte{linkage,
|
||||
false,
|
||||
"shader_float_rte",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
|
||||
SwitchableSetting<bool> shader_float_signed_zero_inf_nan{linkage,
|
||||
false,
|
||||
"shader_float_signed_zero_inf_nan",
|
||||
Category::RendererExtensions,
|
||||
Specialization::Default,
|
||||
true,
|
||||
false,
|
||||
&shader_float_controls_force_enable};
|
||||
#endif
|
||||
|
||||
Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
|
||||
Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
|
||||
Category::RendererDebug};
|
||||
@@ -759,6 +813,9 @@ struct Values {
|
||||
|
||||
// Add-Ons
|
||||
std::map<u64, std::vector<std::string>> disabled_addons;
|
||||
|
||||
// Per-game overrides
|
||||
bool use_squashed_iterated_blend;
|
||||
};
|
||||
|
||||
extern Values values;
|
||||
|
||||
@@ -152,6 +152,16 @@ ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
|
||||
ENUM(GpuOverclock, Low, Medium, High)
|
||||
ENUM(TemperatureUnits, Celsius, Fahrenheit)
|
||||
|
||||
// Shader Float Controls behavior modes
|
||||
// These control how floating-point denormals and special values are handled in shaders
|
||||
ENUM(ShaderFloatBehavior,
|
||||
DriverDefault, // Let driver choose (safest, may not match Switch behavior)
|
||||
SwitchNative, // Emulate Switch/Maxwell behavior (FTZ + RTE + SignedZero)
|
||||
FlushToZero, // FTZ only - flush denorms to zero (fastest, some precision loss)
|
||||
PreserveDenorms, // Preserve denorms (slowest, highest precision)
|
||||
RoundToEven, // RTE rounding mode (IEEE 754 compliant)
|
||||
SignedZeroInfNan); // Preserve signed zero, inf, nan (accuracy for edge cases)
|
||||
|
||||
template <typename Type>
|
||||
inline std::string_view CanonicalizeEnum(Type id) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2012 PPSSPP Project
|
||||
// SPDX-FileCopyrightText: 2012 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -17,7 +20,17 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(__Bitrig__) || defined(__OpenBSD__)
|
||||
// We'll redefine swap16, swap32, swap64 as inline functions
|
||||
// but OpenBSD is like "wow I bring my own stuff"
|
||||
// It would be nice if we could use them without C++ namespace shenanigans
|
||||
// But alas :)
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return _byteswap_ushort(data);
|
||||
}
|
||||
@@ -28,12 +41,6 @@ namespace Common {
|
||||
return _byteswap_uint64(data);
|
||||
}
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
#if defined(__Bitrig__) || defined(__OpenBSD__)
|
||||
// redefine swap16, swap32, swap64 as inline functions
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
#endif
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return __builtin_bswap16(data);
|
||||
}
|
||||
@@ -44,7 +51,9 @@ namespace Common {
|
||||
return __builtin_bswap64(data);
|
||||
}
|
||||
#else
|
||||
// Generic implementation.
|
||||
// Generic implementation - compiler will optimise these into their respective
|
||||
// __builtin_byteswapXX() and such; if not, the compiler is stupid and we probably
|
||||
// have bigger problems to worry about :)
|
||||
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
||||
return (data >> 8) | (data << 8);
|
||||
}
|
||||
@@ -62,33 +71,27 @@ namespace Common {
|
||||
|
||||
[[nodiscard]] inline float swapf(float f) noexcept {
|
||||
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
|
||||
|
||||
u32 value;
|
||||
std::memcpy(&value, &f, sizeof(u32));
|
||||
|
||||
value = swap32(value);
|
||||
std::memcpy(&f, &value, sizeof(u32));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline double swapd(double f) noexcept {
|
||||
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
|
||||
|
||||
u64 value;
|
||||
std::memcpy(&value, &f, sizeof(u64));
|
||||
|
||||
value = swap64(value);
|
||||
std::memcpy(&f, &value, sizeof(u64));
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
template <typename T, typename F>
|
||||
struct swap_struct_t {
|
||||
using swapped_t = swap_struct_t;
|
||||
struct SwapStructT {
|
||||
using SwappedT = SwapStructT;
|
||||
|
||||
protected:
|
||||
T value;
|
||||
@@ -101,137 +104,137 @@ public:
|
||||
T swap() const {
|
||||
return swap(value);
|
||||
}
|
||||
swap_struct_t() = default;
|
||||
swap_struct_t(const T& v) : value(swap(v)) {}
|
||||
SwapStructT() = default;
|
||||
SwapStructT(const T& v) : value(swap(v)) {}
|
||||
|
||||
template <typename S>
|
||||
swapped_t& operator=(const S& source) {
|
||||
value = swap(static_cast<T>(source));
|
||||
SwappedT& operator=(const S& source) {
|
||||
value = swap(T(source));
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator s8() const {
|
||||
return static_cast<s8>(swap());
|
||||
return s8(swap());
|
||||
}
|
||||
operator u8() const {
|
||||
return static_cast<u8>(swap());
|
||||
return u8(swap());
|
||||
}
|
||||
operator s16() const {
|
||||
return static_cast<s16>(swap());
|
||||
return s16(swap());
|
||||
}
|
||||
operator u16() const {
|
||||
return static_cast<u16>(swap());
|
||||
return u16(swap());
|
||||
}
|
||||
operator s32() const {
|
||||
return static_cast<s32>(swap());
|
||||
return s32(swap());
|
||||
}
|
||||
operator u32() const {
|
||||
return static_cast<u32>(swap());
|
||||
return u32(swap());
|
||||
}
|
||||
operator s64() const {
|
||||
return static_cast<s64>(swap());
|
||||
return s64(swap());
|
||||
}
|
||||
operator u64() const {
|
||||
return static_cast<u64>(swap());
|
||||
return u64(swap());
|
||||
}
|
||||
operator float() const {
|
||||
return static_cast<float>(swap());
|
||||
return float(swap());
|
||||
}
|
||||
operator double() const {
|
||||
return static_cast<double>(swap());
|
||||
return double(swap());
|
||||
}
|
||||
|
||||
// +v
|
||||
swapped_t operator+() const {
|
||||
SwappedT operator+() const {
|
||||
return +swap();
|
||||
}
|
||||
// -v
|
||||
swapped_t operator-() const {
|
||||
SwappedT operator-() const {
|
||||
return -swap();
|
||||
}
|
||||
|
||||
// v / 5
|
||||
swapped_t operator/(const swapped_t& i) const {
|
||||
SwappedT operator/(const SwappedT& i) const {
|
||||
return swap() / i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator/(const S& i) const {
|
||||
SwappedT operator/(const S& i) const {
|
||||
return swap() / i;
|
||||
}
|
||||
|
||||
// v * 5
|
||||
swapped_t operator*(const swapped_t& i) const {
|
||||
SwappedT operator*(const SwappedT& i) const {
|
||||
return swap() * i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator*(const S& i) const {
|
||||
SwappedT operator*(const S& i) const {
|
||||
return swap() * i;
|
||||
}
|
||||
|
||||
// v + 5
|
||||
swapped_t operator+(const swapped_t& i) const {
|
||||
SwappedT operator+(const SwappedT& i) const {
|
||||
return swap() + i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator+(const S& i) const {
|
||||
return swap() + static_cast<T>(i);
|
||||
SwappedT operator+(const S& i) const {
|
||||
return swap() + T(i);
|
||||
}
|
||||
// v - 5
|
||||
swapped_t operator-(const swapped_t& i) const {
|
||||
SwappedT operator-(const SwappedT& i) const {
|
||||
return swap() - i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator-(const S& i) const {
|
||||
return swap() - static_cast<T>(i);
|
||||
SwappedT operator-(const S& i) const {
|
||||
return swap() - T(i);
|
||||
}
|
||||
|
||||
// v += 5
|
||||
swapped_t& operator+=(const swapped_t& i) {
|
||||
SwappedT& operator+=(const SwappedT& i) {
|
||||
value = swap(swap() + i.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator+=(const S& i) {
|
||||
value = swap(swap() + static_cast<T>(i));
|
||||
SwappedT& operator+=(const S& i) {
|
||||
value = swap(swap() + T(i));
|
||||
return *this;
|
||||
}
|
||||
// v -= 5
|
||||
swapped_t& operator-=(const swapped_t& i) {
|
||||
SwappedT& operator-=(const SwappedT& i) {
|
||||
value = swap(swap() - i.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator-=(const S& i) {
|
||||
value = swap(swap() - static_cast<T>(i));
|
||||
SwappedT& operator-=(const S& i) {
|
||||
value = swap(swap() - T(i));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ++v
|
||||
swapped_t& operator++() {
|
||||
SwappedT& operator++() {
|
||||
value = swap(swap() + 1);
|
||||
return *this;
|
||||
}
|
||||
// --v
|
||||
swapped_t& operator--() {
|
||||
SwappedT& operator--() {
|
||||
value = swap(swap() - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// v++
|
||||
swapped_t operator++(int) {
|
||||
swapped_t old = *this;
|
||||
SwappedT operator++(int) {
|
||||
SwappedT old = *this;
|
||||
value = swap(swap() + 1);
|
||||
return old;
|
||||
}
|
||||
// v--
|
||||
swapped_t operator--(int) {
|
||||
swapped_t old = *this;
|
||||
SwappedT operator--(int) {
|
||||
SwappedT old = *this;
|
||||
value = swap(swap() - 1);
|
||||
return old;
|
||||
}
|
||||
// Comparison
|
||||
// v == i
|
||||
bool operator==(const swapped_t& i) const {
|
||||
bool operator==(const SwappedT& i) const {
|
||||
return swap() == i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -240,7 +243,7 @@ public:
|
||||
}
|
||||
|
||||
// v != i
|
||||
bool operator!=(const swapped_t& i) const {
|
||||
bool operator!=(const SwappedT& i) const {
|
||||
return swap() != i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -249,7 +252,7 @@ public:
|
||||
}
|
||||
|
||||
// v > i
|
||||
bool operator>(const swapped_t& i) const {
|
||||
bool operator>(const SwappedT& i) const {
|
||||
return swap() > i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -258,7 +261,7 @@ public:
|
||||
}
|
||||
|
||||
// v < i
|
||||
bool operator<(const swapped_t& i) const {
|
||||
bool operator<(const SwappedT& i) const {
|
||||
return swap() < i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -267,7 +270,7 @@ public:
|
||||
}
|
||||
|
||||
// v >= i
|
||||
bool operator>=(const swapped_t& i) const {
|
||||
bool operator>=(const SwappedT& i) const {
|
||||
return swap() >= i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -276,7 +279,7 @@ public:
|
||||
}
|
||||
|
||||
// v <= i
|
||||
bool operator<=(const swapped_t& i) const {
|
||||
bool operator<=(const SwappedT& i) const {
|
||||
return swap() <= i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
@@ -285,82 +288,82 @@ public:
|
||||
}
|
||||
|
||||
// logical
|
||||
swapped_t operator!() const {
|
||||
SwappedT operator!() const {
|
||||
return !swap();
|
||||
}
|
||||
|
||||
// bitmath
|
||||
swapped_t operator~() const {
|
||||
SwappedT operator~() const {
|
||||
return ~swap();
|
||||
}
|
||||
|
||||
swapped_t operator&(const swapped_t& b) const {
|
||||
SwappedT operator&(const SwappedT& b) const {
|
||||
return swap() & b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator&(const S& b) const {
|
||||
SwappedT operator&(const S& b) const {
|
||||
return swap() & b;
|
||||
}
|
||||
swapped_t& operator&=(const swapped_t& b) {
|
||||
SwappedT& operator&=(const SwappedT& b) {
|
||||
value = swap(swap() & b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator&=(const S b) {
|
||||
SwappedT& operator&=(const S b) {
|
||||
value = swap(swap() & b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
swapped_t operator|(const swapped_t& b) const {
|
||||
SwappedT operator|(const SwappedT& b) const {
|
||||
return swap() | b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator|(const S& b) const {
|
||||
SwappedT operator|(const S& b) const {
|
||||
return swap() | b;
|
||||
}
|
||||
swapped_t& operator|=(const swapped_t& b) {
|
||||
SwappedT& operator|=(const SwappedT& b) {
|
||||
value = swap(swap() | b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator|=(const S& b) {
|
||||
SwappedT& operator|=(const S& b) {
|
||||
value = swap(swap() | b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
swapped_t operator^(const swapped_t& b) const {
|
||||
SwappedT operator^(const SwappedT& b) const {
|
||||
return swap() ^ b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator^(const S& b) const {
|
||||
SwappedT operator^(const S& b) const {
|
||||
return swap() ^ b;
|
||||
}
|
||||
swapped_t& operator^=(const swapped_t& b) {
|
||||
SwappedT& operator^=(const SwappedT& b) {
|
||||
value = swap(swap() ^ b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator^=(const S& b) {
|
||||
SwappedT& operator^=(const S& b) {
|
||||
value = swap(swap() ^ b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
swapped_t operator<<(const S& b) const {
|
||||
SwappedT operator<<(const S& b) const {
|
||||
return swap() << b;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator<<=(const S& b) const {
|
||||
SwappedT& operator<<=(const S& b) const {
|
||||
value = swap(swap() << b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
swapped_t operator>>(const S& b) const {
|
||||
SwappedT operator>>(const S& b) const {
|
||||
return swap() >> b;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator>>=(const S& b) const {
|
||||
SwappedT& operator>>=(const S& b) const {
|
||||
value = swap(swap() >> b);
|
||||
return *this;
|
||||
}
|
||||
@@ -370,167 +373,167 @@ public:
|
||||
|
||||
// Arithmetic
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator+(const S& p, const swapped_t v);
|
||||
friend S operator+(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator-(const S& p, const swapped_t v);
|
||||
friend S operator-(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator/(const S& p, const swapped_t v);
|
||||
friend S operator/(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator*(const S& p, const swapped_t v);
|
||||
friend S operator*(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator%(const S& p, const swapped_t v);
|
||||
friend S operator%(const S& p, const SwappedT v);
|
||||
|
||||
// Arithmetic + assignments
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator+=(const S& p, const swapped_t v);
|
||||
friend S operator+=(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator-=(const S& p, const swapped_t v);
|
||||
friend S operator-=(const S& p, const SwappedT v);
|
||||
|
||||
// Bitmath
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator&(const S& p, const swapped_t v);
|
||||
friend S operator&(const S& p, const SwappedT v);
|
||||
|
||||
// Comparison
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator<(const S& p, const swapped_t v);
|
||||
friend bool operator<(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator>(const S& p, const swapped_t v);
|
||||
friend bool operator>(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator<=(const S& p, const swapped_t v);
|
||||
friend bool operator<=(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator>=(const S& p, const swapped_t v);
|
||||
friend bool operator>=(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator!=(const S& p, const swapped_t v);
|
||||
friend bool operator!=(const S& p, const SwappedT v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator==(const S& p, const swapped_t v);
|
||||
friend bool operator==(const S& p, const SwappedT v);
|
||||
};
|
||||
|
||||
// Arithmetic
|
||||
template <typename S, typename T, typename F>
|
||||
S operator+(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator+(const S& i, const SwapStructT<T, F> v) {
|
||||
return i + v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator-(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator-(const S& i, const SwapStructT<T, F> v) {
|
||||
return i - v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator/(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator/(const S& i, const SwapStructT<T, F> v) {
|
||||
return i / v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator*(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator*(const S& i, const SwapStructT<T, F> v) {
|
||||
return i * v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator%(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator%(const S& i, const SwapStructT<T, F> v) {
|
||||
return i % v.swap();
|
||||
}
|
||||
|
||||
// Arithmetic + assignments
|
||||
template <typename S, typename T, typename F>
|
||||
S& operator+=(S& i, const swap_struct_t<T, F> v) {
|
||||
S& operator+=(S& i, const SwapStructT<T, F> v) {
|
||||
i += v.swap();
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S& operator-=(S& i, const swap_struct_t<T, F> v) {
|
||||
S& operator-=(S& i, const SwapStructT<T, F> v) {
|
||||
i -= v.swap();
|
||||
return i;
|
||||
}
|
||||
|
||||
// Logical
|
||||
template <typename S, typename T, typename F>
|
||||
S operator&(const S& i, const swap_struct_t<T, F> v) {
|
||||
S operator&(const S& i, const SwapStructT<T, F> v) {
|
||||
return i & v.swap();
|
||||
}
|
||||
|
||||
// Comparison
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator<(const S& p, const SwapStructT<T, F> v) {
|
||||
return p < v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator>(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator>(const S& p, const SwapStructT<T, F> v) {
|
||||
return p > v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator<=(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator<=(const S& p, const SwapStructT<T, F> v) {
|
||||
return p <= v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator>=(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator>=(const S& p, const SwapStructT<T, F> v) {
|
||||
return p >= v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator!=(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator!=(const S& p, const SwapStructT<T, F> v) {
|
||||
return p != v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator==(const S& p, const swap_struct_t<T, F> v) {
|
||||
bool operator==(const S& p, const SwapStructT<T, F> v) {
|
||||
return p == v.swap();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct swap_64_t {
|
||||
struct Swap64T {
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(Common::swap64(x));
|
||||
return T(Common::swap64(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct swap_32_t {
|
||||
struct Swap32T {
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(Common::swap32(x));
|
||||
return T(Common::swap32(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct swap_16_t {
|
||||
struct Swap16T {
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(Common::swap16(x));
|
||||
return T(Common::swap16(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct swap_float_t {
|
||||
struct SwapFloatT {
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(Common::swapf(x));
|
||||
return T(Common::swapf(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct swap_double_t {
|
||||
struct SwapDoubleT {
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(Common::swapd(x));
|
||||
return T(Common::swapd(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct swap_enum_t {
|
||||
struct SwapEnumT {
|
||||
static_assert(std::is_enum_v<T>);
|
||||
using base = std::underlying_type_t<T>;
|
||||
|
||||
public:
|
||||
swap_enum_t() = default;
|
||||
swap_enum_t(const T& v) : value(swap(v)) {}
|
||||
SwapEnumT() = default;
|
||||
SwapEnumT(const T& v) : value(swap(v)) {}
|
||||
|
||||
swap_enum_t& operator=(const T& v) {
|
||||
SwapEnumT& operator=(const T& v) {
|
||||
value = swap(v);
|
||||
return *this;
|
||||
}
|
||||
@@ -540,22 +543,20 @@ public:
|
||||
}
|
||||
|
||||
explicit operator base() const {
|
||||
return static_cast<base>(swap(value));
|
||||
return base(swap(value));
|
||||
}
|
||||
|
||||
protected:
|
||||
T value{};
|
||||
// clang-format off
|
||||
using swap_t = std::conditional_t<
|
||||
std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
|
||||
std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
|
||||
std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
|
||||
std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
|
||||
std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
|
||||
std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
|
||||
// clang-format on
|
||||
std::is_same_v<base, u16>, Swap16T<u16>, std::conditional_t<
|
||||
std::is_same_v<base, s16>, Swap16T<s16>, std::conditional_t<
|
||||
std::is_same_v<base, u32>, Swap32T<u32>, std::conditional_t<
|
||||
std::is_same_v<base, s32>, Swap32T<s32>, std::conditional_t<
|
||||
std::is_same_v<base, u64>, Swap64T<u64>, std::conditional_t<
|
||||
std::is_same_v<base, s64>, Swap64T<s64>, void>>>>>>;
|
||||
static T swap(T x) {
|
||||
return static_cast<T>(swap_t::swap(static_cast<base>(x)));
|
||||
return T(swap_t::swap(base(x)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -581,17 +582,17 @@ struct AddEndian<u8, SwapTag> {
|
||||
|
||||
template <>
|
||||
struct AddEndian<u16, SwapTag> {
|
||||
using type = swap_struct_t<u16, swap_16_t<u16>>;
|
||||
using type = SwapStructT<u16, Swap16T<u16>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<u32, SwapTag> {
|
||||
using type = swap_struct_t<u32, swap_32_t<u32>>;
|
||||
using type = SwapStructT<u32, Swap32T<u32>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<u64, SwapTag> {
|
||||
using type = swap_struct_t<u64, swap_64_t<u64>>;
|
||||
using type = SwapStructT<u64, Swap64T<u64>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -601,33 +602,33 @@ struct AddEndian<s8, SwapTag> {
|
||||
|
||||
template <>
|
||||
struct AddEndian<s16, SwapTag> {
|
||||
using type = swap_struct_t<s16, swap_16_t<s16>>;
|
||||
using type = SwapStructT<s16, Swap16T<s16>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<s32, SwapTag> {
|
||||
using type = swap_struct_t<s32, swap_32_t<s32>>;
|
||||
using type = SwapStructT<s32, Swap32T<s32>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<s64, SwapTag> {
|
||||
using type = swap_struct_t<s64, swap_64_t<s64>>;
|
||||
using type = SwapStructT<s64, Swap64T<s64>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<float, SwapTag> {
|
||||
using type = swap_struct_t<float, swap_float_t<float>>;
|
||||
using type = SwapStructT<float, SwapFloatT<float>>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AddEndian<double, SwapTag> {
|
||||
using type = swap_struct_t<double, swap_double_t<double>>;
|
||||
using type = SwapStructT<double, SwapDoubleT<double>>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct AddEndian<T, SwapTag> {
|
||||
static_assert(std::is_enum_v<T>);
|
||||
using type = swap_enum_t<T>;
|
||||
using type = SwapEnumT<T>;
|
||||
};
|
||||
|
||||
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
||||
|
||||
@@ -1199,10 +1199,10 @@ else()
|
||||
target_link_libraries(core PUBLIC Boost::headers)
|
||||
endif()
|
||||
|
||||
target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto MbedTLS::mbedtls)
|
||||
if (MINGW)
|
||||
target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi)
|
||||
endif()
|
||||
target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX})
|
||||
# if (MINGW)
|
||||
# target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi)
|
||||
# endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE)
|
||||
@@ -1231,6 +1231,7 @@ endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_sources(core PRIVATE
|
||||
arm/dynarmic/arm_dynarmic.cpp
|
||||
arm/dynarmic/arm_dynarmic.h
|
||||
arm/dynarmic/arm_dynarmic_64.cpp
|
||||
arm/dynarmic/arm_dynarmic_64.h
|
||||
|
||||
52
src/core/arm/dynarmic/arm_dynarmic.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "common/signal_chain.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local Core::Memory::Memory* g_current_memory{};
|
||||
std::once_flag g_registered{};
|
||||
struct sigaction g_old_segv {};
|
||||
|
||||
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
||||
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return g_old_segv.sa_sigaction(sig, info, ctx);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
||||
g_current_memory = std::addressof(process->GetMemory());
|
||||
}
|
||||
|
||||
ScopedJitExecution::~ScopedJitExecution() {
|
||||
g_current_memory = nullptr;
|
||||
}
|
||||
|
||||
void ScopedJitExecution::RegisterHandler() {
|
||||
std::call_once(g_registered, [] {
|
||||
struct sigaction sa {};
|
||||
sa.sa_sigaction = &HandleSigSegv;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
#endif
|
||||
@@ -29,4 +29,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||
return static_cast<HaltReason>(hr);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process);
|
||||
~ScopedJitExecution();
|
||||
static void RegisterHandler();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
||||
~ScopedJitExecution() {}
|
||||
static void RegisterHandler() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -210,9 +210,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
|
||||
config.wall_clock_cntpct = m_uses_wall_clock;
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size - max in ARM is 128MiB, max in x86_64 is 2GiB
|
||||
// Solaris doesn't support kPageSize >= 512MiB
|
||||
// Code cache size
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
#endif
|
||||
|
||||
// Allow memory fault handling to work
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
@@ -341,11 +344,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -387,6 +394,7 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl);
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||
|
||||
@@ -269,9 +269,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
config.wall_clock_cntpct = m_uses_wall_clock;
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size - max in ARM is 128MiB, max in x86_64 is 2GiB
|
||||
// Solaris doesn't support kPageSize >= 512MiB
|
||||
// Code cache size
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
#endif
|
||||
|
||||
// Allow memory fault handling to work
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
@@ -372,11 +375,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -416,6 +423,7 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||
auto& page_table_impl = page_table.GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||
|
||||
@@ -297,6 +297,9 @@ struct System::Impl {
|
||||
std::string vendor = gpu_core->Renderer().GetDeviceVendor();
|
||||
LOG_INFO(Core, "GPU Vendor: {}", vendor);
|
||||
|
||||
// Reset all per-game flags
|
||||
Settings::values.use_squashed_iterated_blend = false;
|
||||
|
||||
// Insert PC overrides here
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -322,6 +325,13 @@ struct System::Impl {
|
||||
|
||||
#endif
|
||||
|
||||
// Ninja Gaiden Ragebound
|
||||
constexpr u64 ngr = 0x0100781020710000ULL;
|
||||
|
||||
if (programId == ngr) {
|
||||
LOG_INFO(Core, "Enabling game specifc override: use_squashed_iterated_blend");
|
||||
Settings::values.use_squashed_iterated_blend = true;
|
||||
}
|
||||
}
|
||||
|
||||
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
||||
@@ -425,6 +435,9 @@ struct System::Impl {
|
||||
void ShutdownMainProcess() {
|
||||
SetShuttingDown(true);
|
||||
|
||||
// Reset per-game flags
|
||||
Settings::values.use_squashed_iterated_blend = false;
|
||||
|
||||
is_powered_on = false;
|
||||
exit_locked = false;
|
||||
exit_requested = false;
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
@@ -18,11 +16,11 @@
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/fs_types.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/fs/symlink.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include <ranges>
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
@@ -492,6 +490,32 @@ void ProfileManager::ResetUserSaveFile()
|
||||
ParseUserSaveFile();
|
||||
}
|
||||
|
||||
std::vector<UUID> ProfileManager::FindExistingProfileUUIDs()
|
||||
{
|
||||
std::vector<UUID> uuids;
|
||||
for (const ProfileInfo& p : profiles) {
|
||||
auto uuid = p.user_uuid;
|
||||
if (!uuid.IsInvalid()) {
|
||||
uuids.emplace_back(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
return uuids;
|
||||
}
|
||||
|
||||
std::vector<std::string> ProfileManager::FindExistingProfileStrings()
|
||||
{
|
||||
std::vector<UUID> uuids = FindExistingProfileUUIDs();
|
||||
std::vector<std::string> uuid_strings;
|
||||
|
||||
for (const UUID &uuid : uuids) {
|
||||
auto user_id = uuid.AsU128();
|
||||
uuid_strings.emplace_back(fmt::format("{:016X}{:016X}", user_id[1], user_id[0]));
|
||||
}
|
||||
|
||||
return uuid_strings;
|
||||
}
|
||||
|
||||
std::vector<std::string> ProfileManager::FindGoodProfiles()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
@@ -501,31 +525,17 @@ std::vector<std::string> ProfileManager::FindGoodProfiles()
|
||||
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
|
||||
/ "user/save/0000000000000000";
|
||||
|
||||
// some exceptions because certain games just LOVE TO CAUSE ISSUES
|
||||
static constexpr const std::array<const char* const, 2> EXCEPTION_UUIDS
|
||||
= {"5755CC2A545A87128500000000000000", "00000000000000000000000000000000"};
|
||||
// some exceptions, e.g. the "system" profile
|
||||
static constexpr const std::array<const char* const, 1> EXCEPTION_UUIDS
|
||||
= {"00000000000000000000000000000000"};
|
||||
|
||||
for (const char *const uuid : EXCEPTION_UUIDS) {
|
||||
if (fs::exists(path / uuid))
|
||||
good_uuids.emplace_back(uuid);
|
||||
}
|
||||
|
||||
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]);
|
||||
}();
|
||||
|
||||
if (uuid_string != "0") good_uuids.emplace_back(uuid_string);
|
||||
}
|
||||
auto existing = FindExistingProfileStrings();
|
||||
good_uuids.insert(good_uuids.end(), existing.begin(), existing.end());
|
||||
|
||||
return good_uuids;
|
||||
}
|
||||
@@ -562,7 +572,8 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
|
||||
override = true;
|
||||
|
||||
// if there are any regular files (NOT directories) there, do NOT delete it :p
|
||||
if (file.is_regular_file())
|
||||
// Also: check for symlinks
|
||||
if (file.is_regular_file() || Common::FS::IsSymlink(file.path()))
|
||||
return false;
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
|
||||
@@ -105,6 +105,8 @@ public:
|
||||
|
||||
void ResetUserSaveFile();
|
||||
|
||||
std::vector<Common::UUID> FindExistingProfileUUIDs();
|
||||
std::vector<std::string> FindExistingProfileStrings();
|
||||
std::vector<std::string> FindGoodProfiles();
|
||||
std::vector<std::string> FindOrphanedProfiles();
|
||||
|
||||
|
||||
@@ -237,7 +237,6 @@ WebBrowser::~WebBrowser() = default;
|
||||
|
||||
void WebBrowser::Initialize() {
|
||||
if (Settings::values.disable_web_applet) {
|
||||
LOG_INFO(Service_AM, "Web Browser Applet disabled, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -305,6 +304,7 @@ void WebBrowser::ExecuteInteractive() {
|
||||
|
||||
void WebBrowser::Execute() {
|
||||
if (Settings::values.disable_web_applet) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, Web Browser Applet is disabled");
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,8 +229,7 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<SoftwareKeyboard>(system, applet, mode,
|
||||
*frontend.software_keyboard);
|
||||
return std::make_shared<SoftwareKeyboard>(system, applet, mode, *frontend.software_keyboard);
|
||||
case AppletId::MiiEdit:
|
||||
return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
|
||||
case AppletId::Web:
|
||||
@@ -244,9 +243,7 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
|
||||
case AppletId::NetConnect:
|
||||
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X}. Falling back to stub applet", static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>(system, applet, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -393,6 +396,24 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size()};
|
||||
const std::size_t buffer_size{GetWriteBufferSize(buffer_index)};
|
||||
|
||||
// Defensive check: if client didn't provide output buffer, log detailed error but don't crash
|
||||
if (buffer_size == 0) {
|
||||
LOG_ERROR(Core,
|
||||
"WriteBuffer called but client provided NO output buffer! "
|
||||
"Requested size: 0x{:X}, buffer_index: {}, is_buffer_b: {}, "
|
||||
"BufferB count: {}, BufferC count: {}",
|
||||
size, buffer_index, is_buffer_b, BufferDescriptorB().size(),
|
||||
BufferDescriptorC().size());
|
||||
|
||||
// Log command context for debugging
|
||||
LOG_ERROR(Core, "IPC Command: 0x{:X}, Type: {}", GetCommand(),
|
||||
static_cast<u32>(GetCommandType()));
|
||||
|
||||
// Return 0 instead of crashing - let service handle error
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size > buffer_size) {
|
||||
LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
|
||||
buffer_size);
|
||||
|
||||
@@ -1230,7 +1230,22 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
||||
if (rasterizer) {
|
||||
impl->InvalidateGPUMemory(ptr, size);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
return mapped && ptr != nullptr;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
#ifdef __linux__
|
||||
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core::Memory
|
||||
|
||||
@@ -495,6 +495,8 @@ public:
|
||||
|
||||
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
|
||||
|
||||
bool InvalidateSeparateHeap(void* fault_address);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
# SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
add_library(yuzu-room STATIC EXCLUDE_FROM_ALL
|
||||
yuzu_room.cpp
|
||||
yuzu_room.h
|
||||
@@ -19,7 +16,7 @@ if (ENABLE_WEB_SERVICE)
|
||||
target_link_libraries(yuzu-room PRIVATE web_service)
|
||||
endif()
|
||||
|
||||
target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto MbedTLS::mbedtls)
|
||||
target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX})
|
||||
if (MSVC)
|
||||
target_link_libraries(yuzu-room PRIVATE getopt)
|
||||
endif()
|
||||
|
||||
@@ -81,11 +81,6 @@ if (MSVC)
|
||||
/bigobj # Increase number of sections in .obj files
|
||||
/DNOMINMAX)
|
||||
|
||||
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
endif()
|
||||
|
||||
if (CXX_CLANG)
|
||||
list(APPEND DYNARMIC_CXX_FLAGS
|
||||
-Qunused-arguments
|
||||
|
||||
@@ -125,6 +125,10 @@ struct Jit::Impl final {
|
||||
current_state.exclusive_state = false;
|
||||
}
|
||||
|
||||
std::string Disassemble() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||
@@ -231,4 +235,8 @@ void Jit::ClearExclusiveState() {
|
||||
impl->ClearExclusiveState();
|
||||
}
|
||||
|
||||
std::string Jit::Disassemble() const {
|
||||
return impl->Disassemble();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
||||
@@ -152,7 +152,7 @@ struct Jit::Impl final {
|
||||
}
|
||||
|
||||
std::string Disassemble() const {
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,16 +80,15 @@ public:
|
||||
};
|
||||
|
||||
// TODO: Check code alignment
|
||||
const CodePtr aligned_code_ptr = CodePtr((uintptr_t(GetCurrentBlock()) + 15) & ~uintptr_t(15));
|
||||
const CodePtr current_code_ptr = [this, aligned_code_ptr] {
|
||||
|
||||
const CodePtr current_code_ptr = [this] {
|
||||
// RSB optimization
|
||||
const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSBPtrMask;
|
||||
if (jit_state.GetUniqueHash() == jit_state.rsb_location_descriptors[new_rsb_ptr]) {
|
||||
jit_state.rsb_ptr = new_rsb_ptr;
|
||||
return CodePtr(jit_state.rsb_codeptrs[new_rsb_ptr]);
|
||||
}
|
||||
return aligned_code_ptr;
|
||||
//return GetCurrentBlock();
|
||||
return CodePtr((uintptr_t(GetCurrentBlock()) + 15) & ~uintptr_t(15));
|
||||
}();
|
||||
|
||||
const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr);
|
||||
|
||||
@@ -28,7 +28,7 @@ const QString GetOpenFileName(const QString &title,
|
||||
Options options)
|
||||
{
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
|
||||
return QFileDialog::getOpenFileName(rootObject, title, dir, filter, selectedFilter, options);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -39,7 +39,14 @@ const QString GetSaveFileName(const QString &title,
|
||||
Options options)
|
||||
{
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
return QFileDialog::getSaveFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
|
||||
return QFileDialog::getSaveFileName(rootObject, title, dir, filter, selectedFilter, options);
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString GetExistingDirectory(const QString& caption, const QString& dir,
|
||||
Options options) {
|
||||
#ifdef YUZU_QT_WIDGETS
|
||||
return QFileDialog::getExistingDirectory(rootObject, caption, dir, options);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -135,5 +135,9 @@ const QString GetSaveFileName(const QString &title,
|
||||
QString *selectedFilter = nullptr,
|
||||
Options options = Options());
|
||||
|
||||
const QString GetExistingDirectory(const QString &caption = QString(),
|
||||
const QString &dir = QString(),
|
||||
Options options = Option::ShowDirsOnly);
|
||||
|
||||
} // namespace QtCommon::Frontend
|
||||
#endif // FRONTEND_H
|
||||
|
||||
@@ -294,6 +294,17 @@ void QtConfig::ReadUIGamelistValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
const int linked_size = BeginArray("ryujinx_linked");
|
||||
for (int i = 0; i < linked_size; ++i) {
|
||||
SetArrayIndex(i);
|
||||
|
||||
QDir ryu_dir = QString::fromStdString(ReadStringSetting("ryujinx_path"));
|
||||
u64 program_id = ReadUnsignedIntegerSetting("program_id");
|
||||
|
||||
UISettings::values.ryujinx_link_paths.insert(program_id, ryu_dir);
|
||||
}
|
||||
EndArray();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
@@ -499,6 +510,21 @@ void QtConfig::SaveUIGamelistValues() {
|
||||
}
|
||||
EndArray(); // favorites
|
||||
|
||||
BeginArray(std::string("ryujinx_linked"));
|
||||
int i = 0;
|
||||
QMapIterator iter(UISettings::values.ryujinx_link_paths);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
|
||||
SetArrayIndex(i);
|
||||
WriteIntegerSetting("program_id", iter.key());
|
||||
WriteStringSetting("ryujinx_path", iter.value().absolutePath().toStdString());
|
||||
++i;
|
||||
}
|
||||
|
||||
EndArray(); // ryujinx
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,54 +28,54 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject *parent);
|
||||
std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent);
|
||||
|
||||
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = {
|
||||
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
|
||||
{Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))},
|
||||
{Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))},
|
||||
{Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "None"))},
|
||||
{Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "FXAA"))},
|
||||
{Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "SMAA"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = {
|
||||
{Settings::ScalingFilter::NearestNeighbor,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Nearest"))},
|
||||
{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"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Bilinear"))},
|
||||
{Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Bicubic"))},
|
||||
{Settings::ScalingFilter::ZeroTangent, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Zero-Tangent"))},
|
||||
{Settings::ScalingFilter::BSpline, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "B-Spline"))},
|
||||
{Settings::ScalingFilter::Mitchell, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Mitchell"))},
|
||||
{Settings::ScalingFilter::Spline1,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Spline-1"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Spline-1"))},
|
||||
{Settings::ScalingFilter::Gaussian,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Gaussian"))},
|
||||
{Settings::ScalingFilter::Lanczos,
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Lanczos"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Lanczos"))},
|
||||
{Settings::ScalingFilter::ScaleForce,
|
||||
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"))},
|
||||
QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "ScaleForce"))},
|
||||
{Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "FSR"))},
|
||||
{Settings::ScalingFilter::Area, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Area"))},
|
||||
{Settings::ScalingFilter::Mmpx, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "MMPX"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
|
||||
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
|
||||
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
|
||||
{Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Docked"))},
|
||||
{Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Handheld"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
|
||||
{Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
|
||||
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
|
||||
{Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
|
||||
{Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Normal"))},
|
||||
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "High"))},
|
||||
{Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Extreme"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = {
|
||||
{Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))},
|
||||
{Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))},
|
||||
{Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))},
|
||||
{Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Vulkan"))},
|
||||
{Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "OpenGL"))},
|
||||
{Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Null"))},
|
||||
};
|
||||
|
||||
static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = {
|
||||
{Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
|
||||
{Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
|
||||
{Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
|
||||
{Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "GLSL"))},
|
||||
{Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "GLASM"))},
|
||||
{Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "SPIRV"))},
|
||||
};
|
||||
|
||||
} // namespace ConfigurationShared
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
#include <qdir.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
@@ -201,6 +202,7 @@ struct Values {
|
||||
Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
|
||||
Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
|
||||
QVector<u64> favorited_ids;
|
||||
QMap<u64, QDir> ryujinx_link_paths;
|
||||
|
||||
// Compatibility List
|
||||
Setting<bool> show_compat{linkage, true, "show_compat", Category::UiGameList};
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
#include "frozen/map.h"
|
||||
#include "frozen/string.h"
|
||||
|
||||
/// Small helper to look up enums.
|
||||
/// res = the result code
|
||||
/// base = the base matching value in the StringKey table
|
||||
#define LOOKUP_ENUM(res, base) StringLookup::Lookup( \
|
||||
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::base))
|
||||
|
||||
namespace QtCommon::StringLookup {
|
||||
|
||||
Q_NAMESPACE
|
||||
|
||||
@@ -25,8 +25,7 @@ enum class FirmwareInstallResult {
|
||||
|
||||
inline const QString GetFirmwareInstallResultString(FirmwareInstallResult result)
|
||||
{
|
||||
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>(
|
||||
(int) result + (int) QtCommon::StringLookup::FwInstallSuccess));
|
||||
return LOOKUP_ENUM(result, FwInstallSuccess);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +35,7 @@ inline const QString GetFirmwareInstallResultString(FirmwareInstallResult result
|
||||
*/
|
||||
inline const QString GetKeyInstallResultString(FirmwareManager::KeyInstallResult result)
|
||||
{
|
||||
// this can probably be made into a common function of sorts
|
||||
return QtCommon::StringLookup::Lookup(static_cast<StringLookup::StringKey>(
|
||||
(int) result + (int) QtCommon::StringLookup::KeyInstallSuccess));
|
||||
return LOOKUP_ENUM(result, KeyInstallSuccess);
|
||||
}
|
||||
|
||||
void InstallFirmware(const QString &location, bool recursive);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include "fs.h"
|
||||
#include "common/fs/ryujinx_compat.h"
|
||||
#include "common/fs/symlink.h"
|
||||
#include "frontend_common/data_manager.h"
|
||||
#include "fs.h"
|
||||
#include "qt_common/abstract/frontend.h"
|
||||
#include "qt_common/qt_string_lookup.h"
|
||||
|
||||
@@ -56,6 +56,9 @@ bool CheckUnlink(const fs::path &eden_dir, const fs::path &ryu_dir)
|
||||
orig = eden_dir;
|
||||
}
|
||||
|
||||
linked.make_preferred();
|
||||
orig.make_preferred();
|
||||
|
||||
// first cleanup the symlink/junction,
|
||||
try {
|
||||
// NB: do NOT use remove_all, as Windows treats this as a remove_all to the target,
|
||||
@@ -84,47 +87,64 @@ bool CheckUnlink(const fs::path &eden_dir, const fs::path &ryu_dir)
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 GetRyujinxSaveID(const u64 &program_id)
|
||||
const fs::path GetRyujinxSavePath(const fs::path &path_hint, const u64 &program_id)
|
||||
{
|
||||
auto path = Common::FS::GetKvdbPath();
|
||||
auto ryu_path = path_hint;
|
||||
|
||||
auto kvdb_path = Common::FS::GetKvdbPath(ryu_path);
|
||||
|
||||
if (!fs::exists(kvdb_path)) {
|
||||
using namespace QtCommon::Frontend;
|
||||
auto res = Warning(
|
||||
tr("Could not find Ryujinx installation"),
|
||||
tr("Could not find a valid Ryujinx installation. This may typically occur if you are "
|
||||
"using Ryujinx in portable mode.\n\nWould you like to manually select a portable "
|
||||
"folder to use?"), StandardButton::Yes | StandardButton::No);
|
||||
|
||||
if (res == StandardButton::Yes) {
|
||||
auto selected_path = GetExistingDirectory(tr("Ryujinx Portable Location"), QDir::homePath()).toStdString();
|
||||
if (selected_path.empty())
|
||||
return fs::path{};
|
||||
|
||||
ryu_path = selected_path;
|
||||
|
||||
// In case the user selects the actual ryujinx installation dir INSTEAD OF
|
||||
// the portable dir
|
||||
if (fs::exists(ryu_path / "portable")) {
|
||||
ryu_path = ryu_path / "portable";
|
||||
}
|
||||
|
||||
kvdb_path = Common::FS::GetKvdbPath(ryu_path);
|
||||
|
||||
if (!fs::exists(kvdb_path)) {
|
||||
QtCommon::Frontend::Critical(
|
||||
tr("Not a valid Ryujinx directory"),
|
||||
tr("The specified directory does not contain valid Ryujinx data."));
|
||||
return fs::path{};
|
||||
}
|
||||
} else {
|
||||
return fs::path{};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Common::FS::IMEN> imens;
|
||||
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(path, imens);
|
||||
Common::FS::IMENReadResult res = Common::FS::ReadKvdb(kvdb_path, imens);
|
||||
|
||||
if (res == Common::FS::IMENReadResult::Success) {
|
||||
// TODO: this can probably be done with std::find_if but I'm lazy
|
||||
for (const Common::FS::IMEN &imen : imens) {
|
||||
if (imen.title_id == program_id)
|
||||
return imen.save_id;
|
||||
return Common::FS::GetRyuSavePath(ryu_path, imen.save_id);
|
||||
}
|
||||
|
||||
QtCommon::Frontend::Critical(
|
||||
tr("Could not find Ryujinx save data"),
|
||||
StringLookup::Lookup(StringLookup::RyujinxNoSaveId).arg(program_id, 0, 16));
|
||||
} else {
|
||||
// TODO: make this long thing a function or something
|
||||
QString caption = StringLookup::Lookup(
|
||||
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::KvdbNonexistent));
|
||||
QString caption = LOOKUP_ENUM(res, KvdbNonexistent);
|
||||
QtCommon::Frontend::Critical(tr("Could not find Ryujinx save data"), caption);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::optional<std::pair<fs::path, fs::path> > GetEmuPaths(
|
||||
const u64 program_id, const u64 save_id, const std::string &user_id)
|
||||
{
|
||||
fs::path ryu_dir = Common::FS::GetRyuSavePath(save_id);
|
||||
|
||||
if (user_id.empty())
|
||||
return std::nullopt;
|
||||
|
||||
std::string hex_program = fmt::format("{:016X}", program_id);
|
||||
fs::path eden_dir
|
||||
= FrontendCommon::DataManager::GetDataDir(FrontendCommon::DataManager::DataDir::Saves,
|
||||
user_id)
|
||||
/ hex_program;
|
||||
|
||||
return std::make_pair(eden_dir, ryu_dir);
|
||||
return fs::path{};
|
||||
}
|
||||
|
||||
} // namespace QtCommon::FS
|
||||
|
||||
@@ -10,13 +10,10 @@
|
||||
namespace QtCommon::FS {
|
||||
|
||||
void LinkRyujinx(std::filesystem::path &from, std::filesystem::path &to);
|
||||
u64 GetRyujinxSaveID(const u64 &program_id);
|
||||
|
||||
/// @brief {eden, ryu}
|
||||
std::optional<std::pair<std::filesystem::path, std::filesystem::path>> GetEmuPaths(
|
||||
const u64 program_id, const u64 save_id, const std::string &user_id);
|
||||
const std::filesystem::path GetRyujinxSavePath(const std::filesystem::path &path_hint, const u64 &program_id);
|
||||
|
||||
/// returns FALSE if the dirs are NOT linked
|
||||
bool CheckUnlink(const std::filesystem::path &eden_dir, const std::filesystem::path &ryu_dir);
|
||||
bool CheckUnlink(const std::filesystem::path& eden_dir,
|
||||
const std::filesystem::path& ryu_dir);
|
||||
|
||||
} // namespace QtCommon::FS
|
||||
|
||||
@@ -81,14 +81,12 @@ add_library(shader_recompiler STATIC
|
||||
environment.h
|
||||
exception.h
|
||||
frontend/ir/abstract_syntax_list.h
|
||||
frontend/ir/attribute.cpp
|
||||
frontend/ir/attribute.h
|
||||
frontend/ir/basic_block.cpp
|
||||
frontend/ir/basic_block.h
|
||||
frontend/ir/breadth_first_search.h
|
||||
frontend/ir/condition.cpp
|
||||
frontend/ir/condition.h
|
||||
frontend/ir/flow_test.cpp
|
||||
frontend/ir/flow_test.h
|
||||
frontend/ir/ir_emitter.cpp
|
||||
frontend/ir/ir_emitter.h
|
||||
|
||||
@@ -380,13 +380,14 @@ void EmitContext::SetupExtensions() {
|
||||
if (info.uses_int64 && profile.support_int64) {
|
||||
header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
|
||||
}
|
||||
if (info.uses_int64_bit_atomics) {
|
||||
if (info.uses_int64_bit_atomics && profile.support_gl_shader_atomic_int64) {
|
||||
header += "#extension GL_NV_shader_atomic_int64 : enable\n";
|
||||
}
|
||||
if (info.uses_atomic_f32_add) {
|
||||
if (info.uses_atomic_f32_add && profile.support_gl_shader_atomic_float) {
|
||||
header += "#extension GL_NV_shader_atomic_float : enable\n";
|
||||
}
|
||||
if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) {
|
||||
if ((info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) &&
|
||||
profile.support_gl_shader_atomic_fp16_vector) {
|
||||
header += "#extension GL_NV_shader_atomic_fp16_vector : enable\n";
|
||||
}
|
||||
if (info.uses_fp16) {
|
||||
|
||||
@@ -341,19 +341,35 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||
void SetupDenormControl(const Profile& profile, const IR::Program& program, EmitContext& ctx,
|
||||
Id main_func) {
|
||||
const Info& info{program.info};
|
||||
|
||||
// User-forced behavior overrides (Android Eden Veil/Extensions)
|
||||
// When force flags are active, they take precedence over shader-declared behavior
|
||||
const bool force_flush = profile.force_fp32_denorm_flush;
|
||||
const bool force_preserve = profile.force_fp32_denorm_preserve;
|
||||
|
||||
if (force_flush && force_preserve) {
|
||||
LOG_WARNING(Shader_SPIRV, "Both FTZ and Preserve forced simultaneously - FTZ takes precedence");
|
||||
}
|
||||
|
||||
if (info.uses_fp32_denorms_flush && info.uses_fp32_denorms_preserve) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 denorm flush and preserve on the same shader");
|
||||
} else if (info.uses_fp32_denorms_flush) {
|
||||
} else if (force_flush || info.uses_fp32_denorms_flush) {
|
||||
if (profile.support_fp32_denorm_flush) {
|
||||
ctx.AddCapability(spv::Capability::DenormFlushToZero);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U);
|
||||
if (force_flush) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 DenormFlushToZero FORCED by user setting");
|
||||
}
|
||||
} else {
|
||||
// Drivers will most likely flush denorms by default, no need to warn
|
||||
}
|
||||
} else if (info.uses_fp32_denorms_preserve) {
|
||||
} else if (force_preserve || info.uses_fp32_denorms_preserve) {
|
||||
if (profile.support_fp32_denorm_preserve) {
|
||||
ctx.AddCapability(spv::Capability::DenormPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 32U);
|
||||
if (force_preserve) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 DenormPreserve FORCED by user setting");
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 denorm preserve used in shader without host support");
|
||||
}
|
||||
@@ -386,13 +402,24 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr
|
||||
if (profile.has_broken_fp16_float_controls && program.info.uses_fp16) {
|
||||
return;
|
||||
}
|
||||
|
||||
// User-forced behavior (Android Eden Veil/Extensions)
|
||||
const bool force_signed_zero_inf_nan = profile.force_fp32_signed_zero_inf_nan;
|
||||
|
||||
if (program.info.uses_fp16 && profile.support_fp16_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 16U);
|
||||
}
|
||||
if (profile.support_fp32_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 32U);
|
||||
if (force_signed_zero_inf_nan || profile.support_fp32_signed_zero_nan_preserve) {
|
||||
if (profile.support_fp32_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
ctx.AddExecutionMode(main_func, spv::ExecutionMode::SignedZeroInfNanPreserve, 32U);
|
||||
if (force_signed_zero_inf_nan) {
|
||||
LOG_DEBUG(Shader_SPIRV, "Fp32 SignedZeroInfNanPreserve FORCED by user setting");
|
||||
}
|
||||
} else if (force_signed_zero_inf_nan) {
|
||||
LOG_WARNING(Shader_SPIRV, "SignedZeroInfNanPreserve forced but driver doesn't support it");
|
||||
}
|
||||
}
|
||||
if (program.info.uses_fp64 && profile.support_fp64_signed_zero_nan_preserve) {
|
||||
ctx.AddCapability(spv::Capability::SignedZeroInfNanPreserve);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,459 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/ir/attribute.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
bool IsGeneric(Attribute attribute) noexcept {
|
||||
return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
|
||||
}
|
||||
|
||||
u32 GenericAttributeIndex(Attribute attribute) {
|
||||
if (!IsGeneric(attribute)) {
|
||||
throw InvalidArgument("Attribute is not generic {}", attribute);
|
||||
}
|
||||
return (static_cast<u32>(attribute) - static_cast<u32>(Attribute::Generic0X)) / 4u;
|
||||
}
|
||||
|
||||
u32 GenericAttributeElement(Attribute attribute) {
|
||||
if (!IsGeneric(attribute)) {
|
||||
throw InvalidArgument("Attribute is not generic {}", attribute);
|
||||
}
|
||||
return static_cast<u32>(attribute) % 4;
|
||||
}
|
||||
|
||||
std::string NameOf(Attribute attribute) {
|
||||
switch (attribute) {
|
||||
case Attribute::PrimitiveId:
|
||||
return "PrimitiveId";
|
||||
case Attribute::Layer:
|
||||
return "Layer";
|
||||
case Attribute::ViewportIndex:
|
||||
return "ViewportIndex";
|
||||
case Attribute::PointSize:
|
||||
return "PointSize";
|
||||
case Attribute::PositionX:
|
||||
return "Position.X";
|
||||
case Attribute::PositionY:
|
||||
return "Position.Y";
|
||||
case Attribute::PositionZ:
|
||||
return "Position.Z";
|
||||
case Attribute::PositionW:
|
||||
return "Position.W";
|
||||
case Attribute::Generic0X:
|
||||
return "Generic[0].X";
|
||||
case Attribute::Generic0Y:
|
||||
return "Generic[0].Y";
|
||||
case Attribute::Generic0Z:
|
||||
return "Generic[0].Z";
|
||||
case Attribute::Generic0W:
|
||||
return "Generic[0].W";
|
||||
case Attribute::Generic1X:
|
||||
return "Generic[1].X";
|
||||
case Attribute::Generic1Y:
|
||||
return "Generic[1].Y";
|
||||
case Attribute::Generic1Z:
|
||||
return "Generic[1].Z";
|
||||
case Attribute::Generic1W:
|
||||
return "Generic[1].W";
|
||||
case Attribute::Generic2X:
|
||||
return "Generic[2].X";
|
||||
case Attribute::Generic2Y:
|
||||
return "Generic[2].Y";
|
||||
case Attribute::Generic2Z:
|
||||
return "Generic[2].Z";
|
||||
case Attribute::Generic2W:
|
||||
return "Generic[2].W";
|
||||
case Attribute::Generic3X:
|
||||
return "Generic[3].X";
|
||||
case Attribute::Generic3Y:
|
||||
return "Generic[3].Y";
|
||||
case Attribute::Generic3Z:
|
||||
return "Generic[3].Z";
|
||||
case Attribute::Generic3W:
|
||||
return "Generic[3].W";
|
||||
case Attribute::Generic4X:
|
||||
return "Generic[4].X";
|
||||
case Attribute::Generic4Y:
|
||||
return "Generic[4].Y";
|
||||
case Attribute::Generic4Z:
|
||||
return "Generic[4].Z";
|
||||
case Attribute::Generic4W:
|
||||
return "Generic[4].W";
|
||||
case Attribute::Generic5X:
|
||||
return "Generic[5].X";
|
||||
case Attribute::Generic5Y:
|
||||
return "Generic[5].Y";
|
||||
case Attribute::Generic5Z:
|
||||
return "Generic[5].Z";
|
||||
case Attribute::Generic5W:
|
||||
return "Generic[5].W";
|
||||
case Attribute::Generic6X:
|
||||
return "Generic[6].X";
|
||||
case Attribute::Generic6Y:
|
||||
return "Generic[6].Y";
|
||||
case Attribute::Generic6Z:
|
||||
return "Generic[6].Z";
|
||||
case Attribute::Generic6W:
|
||||
return "Generic[6].W";
|
||||
case Attribute::Generic7X:
|
||||
return "Generic[7].X";
|
||||
case Attribute::Generic7Y:
|
||||
return "Generic[7].Y";
|
||||
case Attribute::Generic7Z:
|
||||
return "Generic[7].Z";
|
||||
case Attribute::Generic7W:
|
||||
return "Generic[7].W";
|
||||
case Attribute::Generic8X:
|
||||
return "Generic[8].X";
|
||||
case Attribute::Generic8Y:
|
||||
return "Generic[8].Y";
|
||||
case Attribute::Generic8Z:
|
||||
return "Generic[8].Z";
|
||||
case Attribute::Generic8W:
|
||||
return "Generic[8].W";
|
||||
case Attribute::Generic9X:
|
||||
return "Generic[9].X";
|
||||
case Attribute::Generic9Y:
|
||||
return "Generic[9].Y";
|
||||
case Attribute::Generic9Z:
|
||||
return "Generic[9].Z";
|
||||
case Attribute::Generic9W:
|
||||
return "Generic[9].W";
|
||||
case Attribute::Generic10X:
|
||||
return "Generic[10].X";
|
||||
case Attribute::Generic10Y:
|
||||
return "Generic[10].Y";
|
||||
case Attribute::Generic10Z:
|
||||
return "Generic[10].Z";
|
||||
case Attribute::Generic10W:
|
||||
return "Generic[10].W";
|
||||
case Attribute::Generic11X:
|
||||
return "Generic[11].X";
|
||||
case Attribute::Generic11Y:
|
||||
return "Generic[11].Y";
|
||||
case Attribute::Generic11Z:
|
||||
return "Generic[11].Z";
|
||||
case Attribute::Generic11W:
|
||||
return "Generic[11].W";
|
||||
case Attribute::Generic12X:
|
||||
return "Generic[12].X";
|
||||
case Attribute::Generic12Y:
|
||||
return "Generic[12].Y";
|
||||
case Attribute::Generic12Z:
|
||||
return "Generic[12].Z";
|
||||
case Attribute::Generic12W:
|
||||
return "Generic[12].W";
|
||||
case Attribute::Generic13X:
|
||||
return "Generic[13].X";
|
||||
case Attribute::Generic13Y:
|
||||
return "Generic[13].Y";
|
||||
case Attribute::Generic13Z:
|
||||
return "Generic[13].Z";
|
||||
case Attribute::Generic13W:
|
||||
return "Generic[13].W";
|
||||
case Attribute::Generic14X:
|
||||
return "Generic[14].X";
|
||||
case Attribute::Generic14Y:
|
||||
return "Generic[14].Y";
|
||||
case Attribute::Generic14Z:
|
||||
return "Generic[14].Z";
|
||||
case Attribute::Generic14W:
|
||||
return "Generic[14].W";
|
||||
case Attribute::Generic15X:
|
||||
return "Generic[15].X";
|
||||
case Attribute::Generic15Y:
|
||||
return "Generic[15].Y";
|
||||
case Attribute::Generic15Z:
|
||||
return "Generic[15].Z";
|
||||
case Attribute::Generic15W:
|
||||
return "Generic[15].W";
|
||||
case Attribute::Generic16X:
|
||||
return "Generic[16].X";
|
||||
case Attribute::Generic16Y:
|
||||
return "Generic[16].Y";
|
||||
case Attribute::Generic16Z:
|
||||
return "Generic[16].Z";
|
||||
case Attribute::Generic16W:
|
||||
return "Generic[16].W";
|
||||
case Attribute::Generic17X:
|
||||
return "Generic[17].X";
|
||||
case Attribute::Generic17Y:
|
||||
return "Generic[17].Y";
|
||||
case Attribute::Generic17Z:
|
||||
return "Generic[17].Z";
|
||||
case Attribute::Generic17W:
|
||||
return "Generic[17].W";
|
||||
case Attribute::Generic18X:
|
||||
return "Generic[18].X";
|
||||
case Attribute::Generic18Y:
|
||||
return "Generic[18].Y";
|
||||
case Attribute::Generic18Z:
|
||||
return "Generic[18].Z";
|
||||
case Attribute::Generic18W:
|
||||
return "Generic[18].W";
|
||||
case Attribute::Generic19X:
|
||||
return "Generic[19].X";
|
||||
case Attribute::Generic19Y:
|
||||
return "Generic[19].Y";
|
||||
case Attribute::Generic19Z:
|
||||
return "Generic[19].Z";
|
||||
case Attribute::Generic19W:
|
||||
return "Generic[19].W";
|
||||
case Attribute::Generic20X:
|
||||
return "Generic[20].X";
|
||||
case Attribute::Generic20Y:
|
||||
return "Generic[20].Y";
|
||||
case Attribute::Generic20Z:
|
||||
return "Generic[20].Z";
|
||||
case Attribute::Generic20W:
|
||||
return "Generic[20].W";
|
||||
case Attribute::Generic21X:
|
||||
return "Generic[21].X";
|
||||
case Attribute::Generic21Y:
|
||||
return "Generic[21].Y";
|
||||
case Attribute::Generic21Z:
|
||||
return "Generic[21].Z";
|
||||
case Attribute::Generic21W:
|
||||
return "Generic[21].W";
|
||||
case Attribute::Generic22X:
|
||||
return "Generic[22].X";
|
||||
case Attribute::Generic22Y:
|
||||
return "Generic[22].Y";
|
||||
case Attribute::Generic22Z:
|
||||
return "Generic[22].Z";
|
||||
case Attribute::Generic22W:
|
||||
return "Generic[22].W";
|
||||
case Attribute::Generic23X:
|
||||
return "Generic[23].X";
|
||||
case Attribute::Generic23Y:
|
||||
return "Generic[23].Y";
|
||||
case Attribute::Generic23Z:
|
||||
return "Generic[23].Z";
|
||||
case Attribute::Generic23W:
|
||||
return "Generic[23].W";
|
||||
case Attribute::Generic24X:
|
||||
return "Generic[24].X";
|
||||
case Attribute::Generic24Y:
|
||||
return "Generic[24].Y";
|
||||
case Attribute::Generic24Z:
|
||||
return "Generic[24].Z";
|
||||
case Attribute::Generic24W:
|
||||
return "Generic[24].W";
|
||||
case Attribute::Generic25X:
|
||||
return "Generic[25].X";
|
||||
case Attribute::Generic25Y:
|
||||
return "Generic[25].Y";
|
||||
case Attribute::Generic25Z:
|
||||
return "Generic[25].Z";
|
||||
case Attribute::Generic25W:
|
||||
return "Generic[25].W";
|
||||
case Attribute::Generic26X:
|
||||
return "Generic[26].X";
|
||||
case Attribute::Generic26Y:
|
||||
return "Generic[26].Y";
|
||||
case Attribute::Generic26Z:
|
||||
return "Generic[26].Z";
|
||||
case Attribute::Generic26W:
|
||||
return "Generic[26].W";
|
||||
case Attribute::Generic27X:
|
||||
return "Generic[27].X";
|
||||
case Attribute::Generic27Y:
|
||||
return "Generic[27].Y";
|
||||
case Attribute::Generic27Z:
|
||||
return "Generic[27].Z";
|
||||
case Attribute::Generic27W:
|
||||
return "Generic[27].W";
|
||||
case Attribute::Generic28X:
|
||||
return "Generic[28].X";
|
||||
case Attribute::Generic28Y:
|
||||
return "Generic[28].Y";
|
||||
case Attribute::Generic28Z:
|
||||
return "Generic[28].Z";
|
||||
case Attribute::Generic28W:
|
||||
return "Generic[28].W";
|
||||
case Attribute::Generic29X:
|
||||
return "Generic[29].X";
|
||||
case Attribute::Generic29Y:
|
||||
return "Generic[29].Y";
|
||||
case Attribute::Generic29Z:
|
||||
return "Generic[29].Z";
|
||||
case Attribute::Generic29W:
|
||||
return "Generic[29].W";
|
||||
case Attribute::Generic30X:
|
||||
return "Generic[30].X";
|
||||
case Attribute::Generic30Y:
|
||||
return "Generic[30].Y";
|
||||
case Attribute::Generic30Z:
|
||||
return "Generic[30].Z";
|
||||
case Attribute::Generic30W:
|
||||
return "Generic[30].W";
|
||||
case Attribute::Generic31X:
|
||||
return "Generic[31].X";
|
||||
case Attribute::Generic31Y:
|
||||
return "Generic[31].Y";
|
||||
case Attribute::Generic31Z:
|
||||
return "Generic[31].Z";
|
||||
case Attribute::Generic31W:
|
||||
return "Generic[31].W";
|
||||
case Attribute::ColorFrontDiffuseR:
|
||||
return "ColorFrontDiffuse.R";
|
||||
case Attribute::ColorFrontDiffuseG:
|
||||
return "ColorFrontDiffuse.G";
|
||||
case Attribute::ColorFrontDiffuseB:
|
||||
return "ColorFrontDiffuse.B";
|
||||
case Attribute::ColorFrontDiffuseA:
|
||||
return "ColorFrontDiffuse.A";
|
||||
case Attribute::ColorFrontSpecularR:
|
||||
return "ColorFrontSpecular.R";
|
||||
case Attribute::ColorFrontSpecularG:
|
||||
return "ColorFrontSpecular.G";
|
||||
case Attribute::ColorFrontSpecularB:
|
||||
return "ColorFrontSpecular.B";
|
||||
case Attribute::ColorFrontSpecularA:
|
||||
return "ColorFrontSpecular.A";
|
||||
case Attribute::ColorBackDiffuseR:
|
||||
return "ColorBackDiffuse.R";
|
||||
case Attribute::ColorBackDiffuseG:
|
||||
return "ColorBackDiffuse.G";
|
||||
case Attribute::ColorBackDiffuseB:
|
||||
return "ColorBackDiffuse.B";
|
||||
case Attribute::ColorBackDiffuseA:
|
||||
return "ColorBackDiffuse.A";
|
||||
case Attribute::ColorBackSpecularR:
|
||||
return "ColorBackSpecular.R";
|
||||
case Attribute::ColorBackSpecularG:
|
||||
return "ColorBackSpecular.G";
|
||||
case Attribute::ColorBackSpecularB:
|
||||
return "ColorBackSpecular.B";
|
||||
case Attribute::ColorBackSpecularA:
|
||||
return "ColorBackSpecular.A";
|
||||
case Attribute::ClipDistance0:
|
||||
return "ClipDistance[0]";
|
||||
case Attribute::ClipDistance1:
|
||||
return "ClipDistance[1]";
|
||||
case Attribute::ClipDistance2:
|
||||
return "ClipDistance[2]";
|
||||
case Attribute::ClipDistance3:
|
||||
return "ClipDistance[3]";
|
||||
case Attribute::ClipDistance4:
|
||||
return "ClipDistance[4]";
|
||||
case Attribute::ClipDistance5:
|
||||
return "ClipDistance[5]";
|
||||
case Attribute::ClipDistance6:
|
||||
return "ClipDistance[6]";
|
||||
case Attribute::ClipDistance7:
|
||||
return "ClipDistance[7]";
|
||||
case Attribute::PointSpriteS:
|
||||
return "PointSprite.S";
|
||||
case Attribute::PointSpriteT:
|
||||
return "PointSprite.T";
|
||||
case Attribute::FogCoordinate:
|
||||
return "FogCoordinate";
|
||||
case Attribute::TessellationEvaluationPointU:
|
||||
return "TessellationEvaluationPoint.U";
|
||||
case Attribute::TessellationEvaluationPointV:
|
||||
return "TessellationEvaluationPoint.V";
|
||||
case Attribute::InstanceId:
|
||||
return "InstanceId";
|
||||
case Attribute::VertexId:
|
||||
return "VertexId";
|
||||
case Attribute::FixedFncTexture0S:
|
||||
return "FixedFncTexture[0].S";
|
||||
case Attribute::FixedFncTexture0T:
|
||||
return "FixedFncTexture[0].T";
|
||||
case Attribute::FixedFncTexture0R:
|
||||
return "FixedFncTexture[0].R";
|
||||
case Attribute::FixedFncTexture0Q:
|
||||
return "FixedFncTexture[0].Q";
|
||||
case Attribute::FixedFncTexture1S:
|
||||
return "FixedFncTexture[1].S";
|
||||
case Attribute::FixedFncTexture1T:
|
||||
return "FixedFncTexture[1].T";
|
||||
case Attribute::FixedFncTexture1R:
|
||||
return "FixedFncTexture[1].R";
|
||||
case Attribute::FixedFncTexture1Q:
|
||||
return "FixedFncTexture[1].Q";
|
||||
case Attribute::FixedFncTexture2S:
|
||||
return "FixedFncTexture[2].S";
|
||||
case Attribute::FixedFncTexture2T:
|
||||
return "FixedFncTexture[2].T";
|
||||
case Attribute::FixedFncTexture2R:
|
||||
return "FixedFncTexture[2].R";
|
||||
case Attribute::FixedFncTexture2Q:
|
||||
return "FixedFncTexture[2].Q";
|
||||
case Attribute::FixedFncTexture3S:
|
||||
return "FixedFncTexture[3].S";
|
||||
case Attribute::FixedFncTexture3T:
|
||||
return "FixedFncTexture[3].T";
|
||||
case Attribute::FixedFncTexture3R:
|
||||
return "FixedFncTexture[3].R";
|
||||
case Attribute::FixedFncTexture3Q:
|
||||
return "FixedFncTexture[3].Q";
|
||||
case Attribute::FixedFncTexture4S:
|
||||
return "FixedFncTexture[4].S";
|
||||
case Attribute::FixedFncTexture4T:
|
||||
return "FixedFncTexture[4].T";
|
||||
case Attribute::FixedFncTexture4R:
|
||||
return "FixedFncTexture[4].R";
|
||||
case Attribute::FixedFncTexture4Q:
|
||||
return "FixedFncTexture[4].Q";
|
||||
case Attribute::FixedFncTexture5S:
|
||||
return "FixedFncTexture[5].S";
|
||||
case Attribute::FixedFncTexture5T:
|
||||
return "FixedFncTexture[5].T";
|
||||
case Attribute::FixedFncTexture5R:
|
||||
return "FixedFncTexture[5].R";
|
||||
case Attribute::FixedFncTexture5Q:
|
||||
return "FixedFncTexture[5].Q";
|
||||
case Attribute::FixedFncTexture6S:
|
||||
return "FixedFncTexture[6].S";
|
||||
case Attribute::FixedFncTexture6T:
|
||||
return "FixedFncTexture[6].T";
|
||||
case Attribute::FixedFncTexture6R:
|
||||
return "FixedFncTexture[6].R";
|
||||
case Attribute::FixedFncTexture6Q:
|
||||
return "FixedFncTexture[6].Q";
|
||||
case Attribute::FixedFncTexture7S:
|
||||
return "FixedFncTexture[7].S";
|
||||
case Attribute::FixedFncTexture7T:
|
||||
return "FixedFncTexture[7].T";
|
||||
case Attribute::FixedFncTexture7R:
|
||||
return "FixedFncTexture[7].R";
|
||||
case Attribute::FixedFncTexture7Q:
|
||||
return "FixedFncTexture[7].Q";
|
||||
case Attribute::FixedFncTexture8S:
|
||||
return "FixedFncTexture[8].S";
|
||||
case Attribute::FixedFncTexture8T:
|
||||
return "FixedFncTexture[8].T";
|
||||
case Attribute::FixedFncTexture8R:
|
||||
return "FixedFncTexture[8].R";
|
||||
case Attribute::FixedFncTexture8Q:
|
||||
return "FixedFncTexture[8].Q";
|
||||
case Attribute::FixedFncTexture9S:
|
||||
return "FixedFncTexture[9].S";
|
||||
case Attribute::FixedFncTexture9T:
|
||||
return "FixedFncTexture[9].T";
|
||||
case Attribute::FixedFncTexture9R:
|
||||
return "FixedFncTexture[9].R";
|
||||
case Attribute::FixedFncTexture9Q:
|
||||
return "FixedFncTexture[9].Q";
|
||||
case Attribute::ViewportMask:
|
||||
return "ViewportMask";
|
||||
case Attribute::FrontFace:
|
||||
return "FrontFace";
|
||||
case Attribute::BaseInstance:
|
||||
return "BaseInstance";
|
||||
case Attribute::BaseVertex:
|
||||
return "BaseVertex";
|
||||
case Attribute::DrawID:
|
||||
return "DrawID";
|
||||
}
|
||||
return fmt::format("<reserved attribute {}>", static_cast<int>(attribute));
|
||||
}
|
||||
|
||||
} // namespace Shader::IR
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -6,240 +9,261 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
enum class Attribute : u64 {
|
||||
PrimitiveId = 24,
|
||||
Layer = 25,
|
||||
ViewportIndex = 26,
|
||||
PointSize = 27,
|
||||
PositionX = 28,
|
||||
PositionY = 29,
|
||||
PositionZ = 30,
|
||||
PositionW = 31,
|
||||
Generic0X = 32,
|
||||
Generic0Y = 33,
|
||||
Generic0Z = 34,
|
||||
Generic0W = 35,
|
||||
Generic1X = 36,
|
||||
Generic1Y = 37,
|
||||
Generic1Z = 38,
|
||||
Generic1W = 39,
|
||||
Generic2X = 40,
|
||||
Generic2Y = 41,
|
||||
Generic2Z = 42,
|
||||
Generic2W = 43,
|
||||
Generic3X = 44,
|
||||
Generic3Y = 45,
|
||||
Generic3Z = 46,
|
||||
Generic3W = 47,
|
||||
Generic4X = 48,
|
||||
Generic4Y = 49,
|
||||
Generic4Z = 50,
|
||||
Generic4W = 51,
|
||||
Generic5X = 52,
|
||||
Generic5Y = 53,
|
||||
Generic5Z = 54,
|
||||
Generic5W = 55,
|
||||
Generic6X = 56,
|
||||
Generic6Y = 57,
|
||||
Generic6Z = 58,
|
||||
Generic6W = 59,
|
||||
Generic7X = 60,
|
||||
Generic7Y = 61,
|
||||
Generic7Z = 62,
|
||||
Generic7W = 63,
|
||||
Generic8X = 64,
|
||||
Generic8Y = 65,
|
||||
Generic8Z = 66,
|
||||
Generic8W = 67,
|
||||
Generic9X = 68,
|
||||
Generic9Y = 69,
|
||||
Generic9Z = 70,
|
||||
Generic9W = 71,
|
||||
Generic10X = 72,
|
||||
Generic10Y = 73,
|
||||
Generic10Z = 74,
|
||||
Generic10W = 75,
|
||||
Generic11X = 76,
|
||||
Generic11Y = 77,
|
||||
Generic11Z = 78,
|
||||
Generic11W = 79,
|
||||
Generic12X = 80,
|
||||
Generic12Y = 81,
|
||||
Generic12Z = 82,
|
||||
Generic12W = 83,
|
||||
Generic13X = 84,
|
||||
Generic13Y = 85,
|
||||
Generic13Z = 86,
|
||||
Generic13W = 87,
|
||||
Generic14X = 88,
|
||||
Generic14Y = 89,
|
||||
Generic14Z = 90,
|
||||
Generic14W = 91,
|
||||
Generic15X = 92,
|
||||
Generic15Y = 93,
|
||||
Generic15Z = 94,
|
||||
Generic15W = 95,
|
||||
Generic16X = 96,
|
||||
Generic16Y = 97,
|
||||
Generic16Z = 98,
|
||||
Generic16W = 99,
|
||||
Generic17X = 100,
|
||||
Generic17Y = 101,
|
||||
Generic17Z = 102,
|
||||
Generic17W = 103,
|
||||
Generic18X = 104,
|
||||
Generic18Y = 105,
|
||||
Generic18Z = 106,
|
||||
Generic18W = 107,
|
||||
Generic19X = 108,
|
||||
Generic19Y = 109,
|
||||
Generic19Z = 110,
|
||||
Generic19W = 111,
|
||||
Generic20X = 112,
|
||||
Generic20Y = 113,
|
||||
Generic20Z = 114,
|
||||
Generic20W = 115,
|
||||
Generic21X = 116,
|
||||
Generic21Y = 117,
|
||||
Generic21Z = 118,
|
||||
Generic21W = 119,
|
||||
Generic22X = 120,
|
||||
Generic22Y = 121,
|
||||
Generic22Z = 122,
|
||||
Generic22W = 123,
|
||||
Generic23X = 124,
|
||||
Generic23Y = 125,
|
||||
Generic23Z = 126,
|
||||
Generic23W = 127,
|
||||
Generic24X = 128,
|
||||
Generic24Y = 129,
|
||||
Generic24Z = 130,
|
||||
Generic24W = 131,
|
||||
Generic25X = 132,
|
||||
Generic25Y = 133,
|
||||
Generic25Z = 134,
|
||||
Generic25W = 135,
|
||||
Generic26X = 136,
|
||||
Generic26Y = 137,
|
||||
Generic26Z = 138,
|
||||
Generic26W = 139,
|
||||
Generic27X = 140,
|
||||
Generic27Y = 141,
|
||||
Generic27Z = 142,
|
||||
Generic27W = 143,
|
||||
Generic28X = 144,
|
||||
Generic28Y = 145,
|
||||
Generic28Z = 146,
|
||||
Generic28W = 147,
|
||||
Generic29X = 148,
|
||||
Generic29Y = 149,
|
||||
Generic29Z = 150,
|
||||
Generic29W = 151,
|
||||
Generic30X = 152,
|
||||
Generic30Y = 153,
|
||||
Generic30Z = 154,
|
||||
Generic30W = 155,
|
||||
Generic31X = 156,
|
||||
Generic31Y = 157,
|
||||
Generic31Z = 158,
|
||||
Generic31W = 159,
|
||||
ColorFrontDiffuseR = 160,
|
||||
ColorFrontDiffuseG = 161,
|
||||
ColorFrontDiffuseB = 162,
|
||||
ColorFrontDiffuseA = 163,
|
||||
ColorFrontSpecularR = 164,
|
||||
ColorFrontSpecularG = 165,
|
||||
ColorFrontSpecularB = 166,
|
||||
ColorFrontSpecularA = 167,
|
||||
ColorBackDiffuseR = 168,
|
||||
ColorBackDiffuseG = 169,
|
||||
ColorBackDiffuseB = 170,
|
||||
ColorBackDiffuseA = 171,
|
||||
ColorBackSpecularR = 172,
|
||||
ColorBackSpecularG = 173,
|
||||
ColorBackSpecularB = 174,
|
||||
ColorBackSpecularA = 175,
|
||||
ClipDistance0 = 176,
|
||||
ClipDistance1 = 177,
|
||||
ClipDistance2 = 178,
|
||||
ClipDistance3 = 179,
|
||||
ClipDistance4 = 180,
|
||||
ClipDistance5 = 181,
|
||||
ClipDistance6 = 182,
|
||||
ClipDistance7 = 183,
|
||||
PointSpriteS = 184,
|
||||
PointSpriteT = 185,
|
||||
FogCoordinate = 186,
|
||||
TessellationEvaluationPointU = 188,
|
||||
TessellationEvaluationPointV = 189,
|
||||
InstanceId = 190,
|
||||
VertexId = 191,
|
||||
FixedFncTexture0S = 192,
|
||||
FixedFncTexture0T = 193,
|
||||
FixedFncTexture0R = 194,
|
||||
FixedFncTexture0Q = 195,
|
||||
FixedFncTexture1S = 196,
|
||||
FixedFncTexture1T = 197,
|
||||
FixedFncTexture1R = 198,
|
||||
FixedFncTexture1Q = 199,
|
||||
FixedFncTexture2S = 200,
|
||||
FixedFncTexture2T = 201,
|
||||
FixedFncTexture2R = 202,
|
||||
FixedFncTexture2Q = 203,
|
||||
FixedFncTexture3S = 204,
|
||||
FixedFncTexture3T = 205,
|
||||
FixedFncTexture3R = 206,
|
||||
FixedFncTexture3Q = 207,
|
||||
FixedFncTexture4S = 208,
|
||||
FixedFncTexture4T = 209,
|
||||
FixedFncTexture4R = 210,
|
||||
FixedFncTexture4Q = 211,
|
||||
FixedFncTexture5S = 212,
|
||||
FixedFncTexture5T = 213,
|
||||
FixedFncTexture5R = 214,
|
||||
FixedFncTexture5Q = 215,
|
||||
FixedFncTexture6S = 216,
|
||||
FixedFncTexture6T = 217,
|
||||
FixedFncTexture6R = 218,
|
||||
FixedFncTexture6Q = 219,
|
||||
FixedFncTexture7S = 220,
|
||||
FixedFncTexture7T = 221,
|
||||
FixedFncTexture7R = 222,
|
||||
FixedFncTexture7Q = 223,
|
||||
FixedFncTexture8S = 224,
|
||||
FixedFncTexture8T = 225,
|
||||
FixedFncTexture8R = 226,
|
||||
FixedFncTexture8Q = 227,
|
||||
FixedFncTexture9S = 228,
|
||||
FixedFncTexture9T = 229,
|
||||
FixedFncTexture9R = 230,
|
||||
FixedFncTexture9Q = 231,
|
||||
ViewportMask = 232,
|
||||
FrontFace = 255,
|
||||
|
||||
// Implementation attributes
|
||||
BaseInstance = 256,
|
||||
BaseVertex = 257,
|
||||
DrawID = 258,
|
||||
#define SRIR_ATTRIBUTE_LIST \
|
||||
SRIR_ATTRIBUTE_ELEM(PrimitiveId, 24) \
|
||||
SRIR_ATTRIBUTE_ELEM(Layer, 25) \
|
||||
SRIR_ATTRIBUTE_ELEM(ViewportIndex, 26) \
|
||||
SRIR_ATTRIBUTE_ELEM(PointSize, 27) \
|
||||
SRIR_ATTRIBUTE_ELEM(PositionX, 28) \
|
||||
SRIR_ATTRIBUTE_ELEM(PositionY, 29) \
|
||||
SRIR_ATTRIBUTE_ELEM(PositionZ, 30) \
|
||||
SRIR_ATTRIBUTE_ELEM(PositionW, 31) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic0X, 32) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic0Y, 33) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic0Z, 34) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic0W, 35) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic1X, 36) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic1Y, 37) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic1Z, 38) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic1W, 39) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic2X, 40) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic2Y, 41) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic2Z, 42) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic2W, 43) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic3X, 44) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic3Y, 45) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic3Z, 46) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic3W, 47) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic4X, 48) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic4Y, 49) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic4Z, 50) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic4W, 51) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic5X, 52) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic5Y, 53) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic5Z, 54) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic5W, 55) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic6X, 56) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic6Y, 57) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic6Z, 58) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic6W, 59) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic7X, 60) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic7Y, 61) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic7Z, 62) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic7W, 63) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic8X, 64) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic8Y, 65) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic8Z, 66) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic8W, 67) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic9X, 68) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic9Y, 69) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic9Z, 70) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic9W, 71) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic10X, 72) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic10Y, 73) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic10Z, 74) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic10W, 75) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic11X, 76) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic11Y, 77) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic11Z, 78) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic11W, 79) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic12X, 80) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic12Y, 81) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic12Z, 82) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic12W, 83) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic13X, 84) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic13Y, 85) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic13Z, 86) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic13W, 87) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic14X, 88) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic14Y, 89) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic14Z, 90) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic14W, 91) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic15X, 92) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic15Y, 93) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic15Z, 94) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic15W, 95) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic16X, 96) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic16Y, 97) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic16Z, 98) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic16W, 99) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic17X, 100) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic17Y, 101) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic17Z, 102) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic17W, 103) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic18X, 104) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic18Y, 105) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic18Z, 106) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic18W, 107) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic19X, 108) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic19Y, 109) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic19Z, 110) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic19W, 111) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic20X, 112) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic20Y, 113) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic20Z, 114) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic20W, 115) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic21X, 116) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic21Y, 117) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic21Z, 118) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic21W, 119) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic22X, 120) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic22Y, 121) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic22Z, 122) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic22W, 123) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic23X, 124) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic23Y, 125) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic23Z, 126) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic23W, 127) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic24X, 128) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic24Y, 129) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic24Z, 130) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic24W, 131) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic25X, 132) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic25Y, 133) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic25Z, 134) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic25W, 135) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic26X, 136) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic26Y, 137) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic26Z, 138) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic26W, 139) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic27X, 140) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic27Y, 141) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic27Z, 142) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic27W, 143) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic28X, 144) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic28Y, 145) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic28Z, 146) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic28W, 147) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic29X, 148) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic29Y, 149) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic29Z, 150) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic29W, 151) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic30X, 152) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic30Y, 153) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic30Z, 154) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic30W, 155) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic31X, 156) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic31Y, 157) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic31Z, 158) \
|
||||
SRIR_ATTRIBUTE_ELEM(Generic31W, 159) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseR, 160) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseG, 161) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseB, 162) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseA, 163) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularR, 164) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularG, 165) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularB, 166) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularA, 167) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseR, 168) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseG, 169) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseB, 170) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseA, 171) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackSpecularR, 172) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackSpecularG, 173) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackSpecularB, 174) \
|
||||
SRIR_ATTRIBUTE_ELEM(ColorBackSpecularA, 175) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance0, 176) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance1, 177) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance2, 178) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance3, 179) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance4, 180) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance5, 181) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance6, 182) \
|
||||
SRIR_ATTRIBUTE_ELEM(ClipDistance7, 183) \
|
||||
SRIR_ATTRIBUTE_ELEM(PointSpriteS, 184) \
|
||||
SRIR_ATTRIBUTE_ELEM(PointSpriteT, 185) \
|
||||
SRIR_ATTRIBUTE_ELEM(FogCoordinate, 186) \
|
||||
SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointU, 188) \
|
||||
SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointV, 189) \
|
||||
SRIR_ATTRIBUTE_ELEM(InstanceId, 190) \
|
||||
SRIR_ATTRIBUTE_ELEM(VertexId, 191) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture0S, 192) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture0T, 193) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture0R, 194) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture0Q, 195) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture1S, 196) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture1T, 197) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture1R, 198) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture1Q, 199) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture2S, 200) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture2T, 201) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture2R, 202) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture2Q, 203) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture3S, 204) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture3T, 205) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture3R, 206) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture3Q, 207) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture4S, 208) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture4T, 209) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture4R, 210) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture4Q, 211) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture5S, 212) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture5T, 213) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture5R, 214) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture5Q, 215) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture6S, 216) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture6T, 217) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture6R, 218) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture6Q, 219) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture7S, 220) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture7T, 221) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture7R, 222) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture7Q, 223) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture8S, 224) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture8T, 225) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture8R, 226) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture8Q, 227) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture9S, 228) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture9T, 229) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture9R, 230) \
|
||||
SRIR_ATTRIBUTE_ELEM(FixedFncTexture9Q, 231) \
|
||||
SRIR_ATTRIBUTE_ELEM(ViewportMask, 232) \
|
||||
SRIR_ATTRIBUTE_ELEM(FrontFace, 255) \
|
||||
/* Implementation attributes */ \
|
||||
SRIR_ATTRIBUTE_ELEM(BaseInstance, 256) \
|
||||
SRIR_ATTRIBUTE_ELEM(BaseVertex, 257) \
|
||||
SRIR_ATTRIBUTE_ELEM(DrawID, 258)
|
||||
#define SRIR_ATTRIBUTE_ELEM(n, v) n = v,
|
||||
SRIR_ATTRIBUTE_LIST
|
||||
#undef SRIR_ATTRIBUTE_ELEM
|
||||
};
|
||||
|
||||
constexpr size_t NUM_GENERICS = 32;
|
||||
|
||||
constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
|
||||
|
||||
[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
|
||||
[[nodiscard]] inline bool IsGeneric(Attribute attribute) noexcept {
|
||||
return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);
|
||||
[[nodiscard]] inline u32 GenericAttributeIndex(Attribute attribute) {
|
||||
if (!IsGeneric(attribute))
|
||||
throw InvalidArgument("Attribute is not generic {}", attribute);
|
||||
return (u32(attribute) - u32(Attribute::Generic0X)) / 4u;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 GenericAttributeElement(Attribute attribute);
|
||||
[[nodiscard]] inline u32 GenericAttributeElement(Attribute attribute) {
|
||||
if (!IsGeneric(attribute))
|
||||
throw InvalidArgument("Attribute is not generic {}", attribute);
|
||||
return u32(attribute) % 4;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string NameOf(Attribute attribute);
|
||||
[[nodiscard]] inline std::string NameOf(Attribute attribute) {
|
||||
switch (attribute) {
|
||||
#define SRIR_ATTRIBUTE_ELEM(n, v) case Attribute::n: return #n;
|
||||
SRIR_ATTRIBUTE_LIST
|
||||
#undef SRIR_ATTRIBUTE_ELEM
|
||||
default:
|
||||
return fmt::format("<reserved attribute {}>", int(attribute));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr IR::Attribute operator+(IR::Attribute attribute, size_t value) noexcept {
|
||||
return static_cast<IR::Attribute>(static_cast<size_t>(attribute) + value);
|
||||
return IR::Attribute(size_t(attribute) + value);
|
||||
}
|
||||
|
||||
} // namespace Shader::IR
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "shader_recompiler/frontend/ir/flow_test.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
std::string NameOf(FlowTest flow_test) {
|
||||
switch (flow_test) {
|
||||
case FlowTest::F:
|
||||
return "F";
|
||||
case FlowTest::LT:
|
||||
return "LT";
|
||||
case FlowTest::EQ:
|
||||
return "EQ";
|
||||
case FlowTest::LE:
|
||||
return "LE";
|
||||
case FlowTest::GT:
|
||||
return "GT";
|
||||
case FlowTest::NE:
|
||||
return "NE";
|
||||
case FlowTest::GE:
|
||||
return "GE";
|
||||
case FlowTest::NUM:
|
||||
return "NUM";
|
||||
case FlowTest::NaN:
|
||||
return "NAN";
|
||||
case FlowTest::LTU:
|
||||
return "LTU";
|
||||
case FlowTest::EQU:
|
||||
return "EQU";
|
||||
case FlowTest::LEU:
|
||||
return "LEU";
|
||||
case FlowTest::GTU:
|
||||
return "GTU";
|
||||
case FlowTest::NEU:
|
||||
return "NEU";
|
||||
case FlowTest::GEU:
|
||||
return "GEU";
|
||||
case FlowTest::T:
|
||||
return "T";
|
||||
case FlowTest::OFF:
|
||||
return "OFF";
|
||||
case FlowTest::LO:
|
||||
return "LO";
|
||||
case FlowTest::SFF:
|
||||
return "SFF";
|
||||
case FlowTest::LS:
|
||||
return "LS";
|
||||
case FlowTest::HI:
|
||||
return "HI";
|
||||
case FlowTest::SFT:
|
||||
return "SFT";
|
||||
case FlowTest::HS:
|
||||
return "HS";
|
||||
case FlowTest::OFT:
|
||||
return "OFT";
|
||||
case FlowTest::CSM_TA:
|
||||
return "CSM_TA";
|
||||
case FlowTest::CSM_TR:
|
||||
return "CSM_TR";
|
||||
case FlowTest::CSM_MX:
|
||||
return "CSM_MX";
|
||||
case FlowTest::FCSM_TA:
|
||||
return "FCSM_TA";
|
||||
case FlowTest::FCSM_TR:
|
||||
return "FCSM_TR";
|
||||
case FlowTest::FCSM_MX:
|
||||
return "FCSM_MX";
|
||||
case FlowTest::RLE:
|
||||
return "RLE";
|
||||
case FlowTest::RGT:
|
||||
return "RGT";
|
||||
}
|
||||
return fmt::format("<invalid flow test {}>", static_cast<int>(flow_test));
|
||||
}
|
||||
|
||||
} // namespace Shader::IR
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -7,45 +10,58 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
enum class FlowTest : u64 {
|
||||
F,
|
||||
LT,
|
||||
EQ,
|
||||
LE,
|
||||
GT,
|
||||
NE,
|
||||
GE,
|
||||
NUM,
|
||||
NaN,
|
||||
LTU,
|
||||
EQU,
|
||||
LEU,
|
||||
GTU,
|
||||
NEU,
|
||||
GEU,
|
||||
T,
|
||||
OFF,
|
||||
LO,
|
||||
SFF,
|
||||
LS,
|
||||
HI,
|
||||
SFT,
|
||||
HS,
|
||||
OFT,
|
||||
CSM_TA,
|
||||
CSM_TR,
|
||||
CSM_MX,
|
||||
FCSM_TA,
|
||||
FCSM_TR,
|
||||
FCSM_MX,
|
||||
RLE,
|
||||
RGT,
|
||||
#define SRIR_FLOW_TEST_LIST \
|
||||
SRIR_FLOW_TEST_ELEM(F) \
|
||||
SRIR_FLOW_TEST_ELEM(LT) \
|
||||
SRIR_FLOW_TEST_ELEM(EQ) \
|
||||
SRIR_FLOW_TEST_ELEM(LE) \
|
||||
SRIR_FLOW_TEST_ELEM(GT) \
|
||||
SRIR_FLOW_TEST_ELEM(NE) \
|
||||
SRIR_FLOW_TEST_ELEM(GE) \
|
||||
SRIR_FLOW_TEST_ELEM(NUM) \
|
||||
SRIR_FLOW_TEST_ELEM(NaN) \
|
||||
SRIR_FLOW_TEST_ELEM(LTU) \
|
||||
SRIR_FLOW_TEST_ELEM(EQU) \
|
||||
SRIR_FLOW_TEST_ELEM(LEU) \
|
||||
SRIR_FLOW_TEST_ELEM(GTU) \
|
||||
SRIR_FLOW_TEST_ELEM(NEU) \
|
||||
SRIR_FLOW_TEST_ELEM(GEU) \
|
||||
SRIR_FLOW_TEST_ELEM(T) \
|
||||
SRIR_FLOW_TEST_ELEM(OFF) \
|
||||
SRIR_FLOW_TEST_ELEM(LO) \
|
||||
SRIR_FLOW_TEST_ELEM(SFF) \
|
||||
SRIR_FLOW_TEST_ELEM(LS) \
|
||||
SRIR_FLOW_TEST_ELEM(HI) \
|
||||
SRIR_FLOW_TEST_ELEM(SFT) \
|
||||
SRIR_FLOW_TEST_ELEM(HS) \
|
||||
SRIR_FLOW_TEST_ELEM(OFT) \
|
||||
SRIR_FLOW_TEST_ELEM(CSM_TA) \
|
||||
SRIR_FLOW_TEST_ELEM(CSM_TR) \
|
||||
SRIR_FLOW_TEST_ELEM(CSM_MX) \
|
||||
SRIR_FLOW_TEST_ELEM(FCSM_TA) \
|
||||
SRIR_FLOW_TEST_ELEM(FCSM_TR) \
|
||||
SRIR_FLOW_TEST_ELEM(FCSM_MX) \
|
||||
SRIR_FLOW_TEST_ELEM(RLE) \
|
||||
SRIR_FLOW_TEST_ELEM(RGT)
|
||||
#define SRIR_FLOW_TEST_ELEM(n) n,
|
||||
SRIR_FLOW_TEST_LIST
|
||||
#undef SRIR_FLOW_TEST_ELEM
|
||||
};
|
||||
|
||||
[[nodiscard]] std::string NameOf(FlowTest flow_test);
|
||||
[[nodiscard]] inline std::string NameOf(FlowTest flow_test) {
|
||||
switch (flow_test) {
|
||||
#define SRIR_FLOW_TEST_ELEM(n) case FlowTest::n: return #n;
|
||||
SRIR_FLOW_TEST_LIST
|
||||
#undef SRIR_FLOW_TEST_ELEM
|
||||
default:
|
||||
return fmt::format("<invalid flow test {}>", int(flow_test));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::IR
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ bool IsSizeInt32(Size size) {
|
||||
}
|
||||
|
||||
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg,
|
||||
IR::Reg bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type,
|
||||
std::optional<IR::Reg> bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type,
|
||||
u64 bound_offset, bool is_bindless, bool write_result) {
|
||||
if (clamp != Clamp::IGN) {
|
||||
throw NotImplementedException("Clamp {}", clamp);
|
||||
@@ -158,8 +158,7 @@ void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR
|
||||
const TextureType tex_type{GetType(type)};
|
||||
const IR::Value coords{MakeCoords(v, coord_reg, type)};
|
||||
|
||||
const IR::U32 handle{is_bindless != 0 ? v.X(bindless_reg)
|
||||
: v.ir.Imm32(static_cast<u32>(bound_offset * 4))};
|
||||
const IR::U32 handle = is_bindless ? v.X(*bindless_reg) : v.ir.Imm32(u32(bound_offset * 4));
|
||||
IR::TextureInstInfo info{};
|
||||
info.type.Assign(tex_type);
|
||||
info.image_format.Assign(format);
|
||||
@@ -185,7 +184,7 @@ void TranslatorVisitor::SUATOM(u64 insn) {
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<20, 8, IR::Reg> operand_reg;
|
||||
BitField<36, 13, u64> bound_offset; // !is_bindless
|
||||
BitField<36, 13, u64> bound_offset; // !is_bindless
|
||||
BitField<39, 8, IR::Reg> bindless_reg; // is_bindless
|
||||
} const suatom{insn};
|
||||
|
||||
@@ -196,21 +195,20 @@ void TranslatorVisitor::SUATOM(u64 insn) {
|
||||
|
||||
void TranslatorVisitor::SURED(u64 insn) {
|
||||
// TODO: confirm offsets
|
||||
// SURED unlike SUATOM does NOT have a binded register
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<51, 1, u64> is_bound;
|
||||
BitField<21, 3, AtomicOp> op;
|
||||
BitField<33, 3, Type> type;
|
||||
BitField<20, 3, Size> size;
|
||||
BitField<49, 2, Clamp> clamp;
|
||||
BitField<0, 8, IR::Reg> operand_reg;
|
||||
BitField<8, 8, IR::Reg> coord_reg;
|
||||
BitField<36, 13, u64> bound_offset; // is_bound
|
||||
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
|
||||
BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp)
|
||||
BitField<33, 3, Type> type; //OK? - 33 (Dim)
|
||||
BitField<20, 3, Size> size; //?
|
||||
BitField<49, 2, Clamp> clamp; //OK - 49 (Clamp4)
|
||||
BitField<0, 8, IR::Reg> operand_reg; //RA?
|
||||
BitField<8, 8, IR::Reg> coord_reg; //RB?
|
||||
BitField<36, 13, u64> bound_offset; //OK 33 (TidB)
|
||||
} const sured{insn};
|
||||
ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, sured.bindless_reg,
|
||||
ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, std::nullopt,
|
||||
sured.op, sured.clamp, sured.size, sured.type, sured.bound_offset,
|
||||
sured.is_bound == 0, false);
|
||||
false, false);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -293,6 +296,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
}
|
||||
// This address is expected to either be a PackUint2x32, a IAdd64, or a CompositeConstructU32x2
|
||||
IR::Inst* addr_inst{addr.InstRecursive()};
|
||||
// Unwrap Identity ops introduced by lowerings (e.g., PackUint2x32 -> Identity)
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
s32 imm_offset{0};
|
||||
if (addr_inst->GetOpcode() == IR::Opcode::IAdd64) {
|
||||
// If it's an IAdd64, get the immediate offset it is applying and grab the address
|
||||
@@ -308,6 +319,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = iadd_addr.InstRecursive();
|
||||
// Unwrap Identity again if present after folding IAdd64
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
}
|
||||
// With IAdd64 handled, now PackUint2x32 is expected
|
||||
if (addr_inst->GetOpcode() == IR::Opcode::PackUint2x32) {
|
||||
@@ -317,6 +336,14 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = vector.InstRecursive();
|
||||
// Unwrap Identity that may replace PackUint2x32
|
||||
while (addr_inst->GetOpcode() == IR::Opcode::Identity) {
|
||||
const IR::Value id_arg{addr_inst->Arg(0)};
|
||||
if (id_arg.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
addr_inst = id_arg.InstRecursive();
|
||||
}
|
||||
}
|
||||
// The vector is expected to be a CompositeConstructU32x2
|
||||
if (addr_inst->GetOpcode() != IR::Opcode::CompositeConstructU32x2) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -25,6 +28,14 @@ struct Profile {
|
||||
bool support_fp16_signed_zero_nan_preserve{};
|
||||
bool support_fp32_signed_zero_nan_preserve{};
|
||||
bool support_fp64_signed_zero_nan_preserve{};
|
||||
|
||||
// User-forced float behavior overrides (Android Eden Veil/Extensions)
|
||||
// When shader_float_controls_force_enable is true, these override shader-declared behavior
|
||||
bool force_fp32_denorm_flush{}; // Force FTZ for all FP32 ops
|
||||
bool force_fp32_denorm_preserve{}; // Force denorm preservation for all FP32 ops
|
||||
bool force_fp32_rte_rounding{}; // Force Round-To-Even for all FP32 ops
|
||||
bool force_fp32_signed_zero_inf_nan{}; // Force signed zero/inf/nan preservation
|
||||
|
||||
bool support_explicit_workgroup_layout{};
|
||||
bool support_vote{};
|
||||
bool support_viewport_index_layer_non_geometry{};
|
||||
@@ -38,6 +49,9 @@ struct Profile {
|
||||
bool support_gl_nv_gpu_shader_5{};
|
||||
bool support_gl_amd_gpu_shader_half_float{};
|
||||
bool support_gl_texture_shadow_lod{};
|
||||
bool support_gl_shader_atomic_float{};
|
||||
bool support_gl_shader_atomic_fp16_vector{};
|
||||
bool support_gl_shader_atomic_int64{};
|
||||
bool support_gl_warp_intrinsics{};
|
||||
bool support_gl_variable_aoffi{};
|
||||
bool support_gl_sparse_textures{};
|
||||
|
||||
@@ -27,3 +27,12 @@ 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)
|
||||
|
||||
# needed for vma
|
||||
if (NOT MSVC)
|
||||
target_compile_options(tests PRIVATE
|
||||
-Wno-conversion
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-parameter
|
||||
-Wno-missing-field-initializers)
|
||||
endif()
|
||||
|
||||