Merge branch 'stuffmadeforfun' of https://git.eden-emu.dev/eden-emu/eden into stuffmadeforfun

This commit is contained in:
CamilleLaVey 2025-11-13 23:10:40 -04:00
commit 9085ff1229
74 changed files with 1357 additions and 1269 deletions

19
.github/workflows/sources.yml vendored Normal file
View 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
View 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

View file

@ -21,6 +21,11 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(PLATFORM_LINUX ON) set(PLATFORM_LINUX ON)
endif() endif()
# dumb heuristic to detect msys2
if (CMAKE_COMMAND MATCHES "msys64")
set(PLATFORM_MSYS ON)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CXX_CLANG ON) set(CXX_CLANG ON)
if (MSVC) if (MSVC)
@ -85,6 +90,89 @@ if (PLATFORM_NETBSD)
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig") set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
endif() 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 # 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 # 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) 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
# 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_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF) cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "ENABLE_SDL2" OFF)
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
endif()
# qt stuff # qt stuff
option(ENABLE_QT "Enable the Qt frontend" ON) 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 # ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT}) 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 # 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 # 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) 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() else()
message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}") message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
endif() 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() endif()
# TODO(crueter): CI this? # TODO(crueter): CI this?
@ -355,13 +456,6 @@ if (ANDROID)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe
endif() 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 # Default to a Release build
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
@ -582,6 +676,7 @@ else()
find_package(stb MODULE) find_package(stb MODULE)
find_package(Opus 1.3 MODULE REQUIRED) find_package(Opus 1.3 MODULE REQUIRED)
find_package(ZLIB 1.2 REQUIRED) find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED MODULE) find_package(zstd 1.5 REQUIRED MODULE)
@ -634,15 +729,15 @@ if (APPLE)
# Umbrella framework for everything GUI-related # Umbrella framework for everything GUI-related
find_library(COCOA_LIBRARY Cocoa) find_library(COCOA_LIBRARY Cocoa)
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
find_library(ICONV_LIBRARY iconv REQUIRED) # find_library(ICONV_LIBRARY iconv REQUIRED)
list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY}) # list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY})
elseif (WIN32) elseif (WIN32)
# Target Windows 10 # Target Windows 10
add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00) 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) if (MINGW)
# PSAPI is the Process Status API # 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() endif()
elseif (PLATFORM_HAIKU) elseif (PLATFORM_HAIKU)
# Haiku is so special :) # Haiku is so special :)
@ -655,6 +750,8 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
set(PLATFORM_LIBRARIES rt) set(PLATFORM_LIBRARIES rt)
endif() endif()
message(STATUS "Platform Libraries: ${PLATFORM_LIBRARIES}")
add_subdirectory(externals) add_subdirectory(externals)
# pass targets from externals # pass targets from externals

View file

@ -542,10 +542,11 @@ function(AddCIPackage)
PACKAGE PACKAGE
EXTENSION EXTENSION
MIN_VERSION 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) if(NOT DEFINED PKG_ARGS_VERSION)
message(FATAL_ERROR "[CPMUtil] VERSION is required") message(FATAL_ERROR "[CPMUtil] VERSION is required")

View file

@ -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-FileCopyrightText: 2022 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
@ -10,6 +13,10 @@ find_package_handle_standard_args(Opus
VERSION_VAR OPUS_VERSION VERSION_VAR OPUS_VERSION
) )
if (PLATFORM_MSYS)
FixMsysPath(PkgConfig::OPUS)
endif()
if (Opus_FOUND AND NOT TARGET Opus::opus) if (Opus_FOUND AND NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS PkgConfig::OPUS) add_library(Opus::opus ALIAS PkgConfig::OPUS)
endif() endif()

View file

@ -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-FileCopyrightText: 2022 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
@ -10,6 +13,10 @@ find_package_handle_standard_args(SPIRV-Tools
VERSION_VAR SPIRV-Tools_VERSION 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 (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools)
if (TARGET SPIRV-Tools) if (TARGET SPIRV-Tools)
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools) add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools)

View file

@ -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-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
@ -11,6 +14,10 @@ find_package_handle_standard_args(enet
VERSION_VAR ENET_VERSION VERSION_VAR ENET_VERSION
) )
if (PLATFORM_MSYS)
FixMsysPath(PkgConfig::ENET)
endif()
if (enet_FOUND AND NOT TARGET enet::enet) if (enet_FOUND AND NOT TARGET enet::enet)
add_library(enet::enet ALIAS PkgConfig::ENET) add_library(enet::enet ALIAS PkgConfig::ENET)
endif() endif()

View file

@ -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-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
@ -11,6 +14,10 @@ find_package_handle_standard_args(libusb
VERSION_VAR LIBUSB_VERSION VERSION_VAR LIBUSB_VERSION
) )
if (PLATFORM_MSYS)
FixMsysPath(PkgConfig::LIBUSB)
endif()
if (libusb_FOUND AND NOT TARGET libusb::usb) if (libusb_FOUND AND NOT TARGET libusb::usb)
add_library(libusb::usb ALIAS PkgConfig::LIBUSB) add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
endif() endif()

View file

@ -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-FileCopyrightText: 2022 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
@ -9,6 +12,11 @@ if (lz4_CONSIDERED_CONFIGS)
else() else()
find_package(PkgConfig QUIET) find_package(PkgConfig QUIET)
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4) pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
if (PLATFORM_MSYS)
FixMsysPath(PkgConfig::LZ4)
endif()
find_package_handle_standard_args(lz4 find_package_handle_standard_args(lz4
REQUIRED_VARS LZ4_LINK_LIBRARIES REQUIRED_VARS LZ4_LINK_LIBRARIES
VERSION_VAR LZ4_VERSION VERSION_VAR LZ4_VERSION

View file

@ -6,22 +6,34 @@
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package(PkgConfig QUIET) find_package(zstd QUIET CONFIG)
pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) if (zstd_CONSIDERED_CONFIGS)
find_package_handle_standard_args(zstd find_package_handle_standard_args(zstd CONFIG_MODE)
REQUIRED_VARS ZSTD_LINK_LIBRARIES else()
VERSION_VAR ZSTD_VERSION 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 (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::zstd ALIAS zstd::libzstd_shared)
add_library(zstd::libzstd ALIAS zstd::libzstd_shared)
elseif (TARGET zstd::libzstd_static) elseif (TARGET zstd::libzstd_static)
add_library(zstd::zstd ALIAS zstd::libzstd_static) add_library(zstd::zstd ALIAS zstd::libzstd_static)
add_library(zstd::libzstd ALIAS zstd::libzstd_static)
else() else()
add_library(zstd::zstd ALIAS PkgConfig::ZSTD) 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()
endif() endif()

View 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()

View file

@ -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()

View file

@ -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()

BIN
dist/eden.ico vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

After

Width:  |  Height:  |  Size: 386 KiB

Before After
Before After

9
dist/icon_variations/README.md vendored Normal file
View 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
View 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/yuzu.bmp vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

Before After
Before After

View file

@ -160,13 +160,6 @@ if (YUZU_USE_BUNDLED_SIRIT)
AddJsonPackage(sirit-ci) AddJsonPackage(sirit-ci)
else() else()
AddJsonPackage(sirit) 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) if(MSVC AND CXX_CLANG)
target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument) target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument)
endif() endif()

View file

@ -25,18 +25,26 @@ if (UNIX AND NOT ANDROID)
if (NOT APPLE) if (NOT APPLE)
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
if(PLATFORM_SUN) if(PLATFORM_SUN)
list(APPEND FFmpeg_HWACCEL_LIBRARIES find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib)
X11 if(LIBDRM_LIB)
"/usr/lib/xorg/amd64/libdrm.so") 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() else()
pkg_check_modules(LIBDRM libdrm REQUIRED) pkg_check_modules(LIBDRM libdrm REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES list(APPEND FFmpeg_HWACCEL_LIBRARIES
${LIBDRM_LIBRARIES}) ${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS}) ${LIBDRM_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-libdrm)
endif() endif()
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-libdrm)
endif() endif()
if(LIBVA_FOUND) if(LIBVA_FOUND)
@ -89,7 +97,7 @@ if (UNIX AND NOT ANDROID)
endif(CUDA_FOUND) endif(CUDA_FOUND)
endif() endif()
if (VDPAU_FOUND) if (VDPAU_FOUND AND NOT APPLE)
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-vdpau --enable-vdpau
--enable-hwaccel=h264_vdpau --enable-hwaccel=h264_vdpau
@ -247,11 +255,19 @@ else()
SYSTEM_THREADS) SYSTEM_THREADS)
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) 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( add_custom_command(
OUTPUT OUTPUT
${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_BUILD_LIBRARIES}
COMMAND COMMAND
make -j${SYSTEM_THREADS} make ${FFmpeg_MAKE_ARGS}
WORKING_DIRECTORY WORKING_DIRECTORY
${FFmpeg_BUILD_DIR} ${FFmpeg_BUILD_DIR}
) )

View file

@ -15,8 +15,7 @@
"disabled_platforms": [ "disabled_platforms": [
"freebsd-amd64", "freebsd-amd64",
"solaris-amd64", "solaris-amd64",
"openbsd-amd64", "openbsd-amd64"
"macos-universal"
] ]
} }
} }

View file

@ -5,7 +5,7 @@
"git_host": "git.crueter.xyz", "git_host": "git.crueter.xyz",
"artifact": "%VERSION%.tar.gz", "artifact": "%VERSION%.tar.gz",
"tag": "%VERSION%", "tag": "%VERSION%",
"hash": "87abb2aeca716d5d77b05317086dbc2f8acfc2f3f76ce4778345ee3df19973e6cd8ecbf16cfab5ad94c9636a6c44fd3588f9aadd3cba89403cfd56c8bec645c5", "hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
"version": "091025" "version": "121125"
} }
} }

View file

@ -35,7 +35,6 @@ if (MSVC AND NOT CXX_CLANG)
# /W4 - Level 4 warnings # /W4 - Level 4 warnings
# /MP - Multi-threaded compilation # /MP - Multi-threaded compilation
# /Zi - Output debugging information
# /Zm - Specifies the precompiled header memory allocation limit # /Zm - Specifies the precompiled header memory allocation limit
# /Zo - Enhanced debug info for optimized builds # /Zo - Enhanced debug info for optimized builds
# /permissive- - Enables stricter C++ standards conformance checks # /permissive- - Enables stricter C++ standards conformance checks
@ -98,11 +97,6 @@ if (MSVC AND NOT CXX_CLANG)
) )
endif() 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) if (ARCHITECTURE_x86_64)
add_compile_options(/QIntel-jcc-erratum) add_compile_options(/QIntel-jcc-erratum)
endif() endif()
@ -176,16 +170,28 @@ else()
add_compile_definitions(_FILE_OFFSET_BITS=64) add_compile_definitions(_FILE_OFFSET_BITS=64)
endif() 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) if (MINGW)
add_compile_definitions(MINGW_HAS_SECURE_API) add_compile_definitions(MINGW_HAS_SECURE_API)
# Only windows has this requirement, thanks windows # Only windows has this requirement, thanks windows
if (WIN32) if (WIN32 AND ARCHITECTURE_x86_64)
add_compile_options("-msse4.1") add_compile_options("-msse4.1")
endif() endif()
if (MINGW_STATIC_BUILD)
add_compile_definitions(QT_STATICPLUGIN)
add_compile_options("-static")
endif()
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW) if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)

View file

@ -16,11 +16,15 @@ import java.io.FileOutputStream
import java.security.KeyStore import java.security.KeyStore
import javax.net.ssl.TrustManagerFactory import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager 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.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.PowerStateUpdater import org.yuzu.yuzu_emu.utils.PowerStateUpdater
import java.util.Locale
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
@ -73,5 +77,38 @@ class YuzuApplication : Application() {
val appContext: Context val appContext: Context
get() = application.applicationContext 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)
}
} }
} }

View file

@ -86,6 +86,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private var foregroundService: Intent? = null private var foregroundService: Intent? = null
override fun attachBaseContext(base: Context) {
super.attachBaseContext(YuzuApplication.applyLanguage(base))
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.gameLaunched = true Log.gameLaunched = true
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)

View file

@ -32,6 +32,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
MAX_ANISOTROPY("max_anisotropy"), MAX_ANISOTROPY("max_anisotropy"),
THEME("theme"), THEME("theme"),
THEME_MODE("theme_mode"), THEME_MODE("theme_mode"),
APP_LANGUAGE("app_language"),
OVERLAY_SCALE("control_scale"), OVERLAY_SCALE("control_scale"),
OVERLAY_OPACITY("control_opacity"), OVERLAY_OPACITY("control_opacity"),
LOCK_DRAWER("lock_drawer"), LOCK_DRAWER("lock_drawer"),

View file

@ -667,10 +667,11 @@ abstract class SettingsItem(
) )
) )
put( put(
SliderSetting( SpinBoxSetting(
IntSetting.CPU_TICKS, IntSetting.CPU_TICKS,
titleId = R.string.cpu_ticks, titleId = R.string.cpu_ticks,
descriptionId = 0, descriptionId = 0,
valueHint = R.string.cpu_ticks,
min = 77, min = 77,
max = 65535 max = 65535
) )
@ -756,6 +757,15 @@ abstract class SettingsItem(
titleId = R.string.enable_update_checks, 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( put(
SwitchSetting( SwitchSetting(
BooleanSetting.RENDERER_DEBUG, BooleanSetting.RENDERER_DEBUG,

View file

@ -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-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui package org.yuzu.yuzu_emu.features.settings.ui
import android.content.Context
import org.yuzu.yuzu_emu.YuzuApplication
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup.MarginLayoutParams 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.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.collect
class SettingsActivity : AppCompatActivity() { class SettingsActivity : AppCompatActivity() {
private lateinit var binding: ActivitySettingsBinding private lateinit var binding: ActivitySettingsBinding
@ -32,6 +38,10 @@ class SettingsActivity : AppCompatActivity() {
private val settingsViewModel: SettingsViewModel by viewModels() private val settingsViewModel: SettingsViewModel by viewModels()
override fun attachBaseContext(base: Context) {
super.attachBaseContext(YuzuApplication.applyLanguage(base))
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
@ -125,6 +135,16 @@ class SettingsActivity : AppCompatActivity() {
NativeConfig.savePerGameConfig() NativeConfig.savePerGameConfig()
NativeConfig.unloadPerGameConfig() 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())
}
}
} }
} }

View file

@ -425,6 +425,14 @@ class SettingsAdapter(
position position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) ).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 return true
} }

View file

@ -14,6 +14,9 @@ import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.MotionEvent
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -197,6 +200,54 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
updateValidity(newValue) 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 { spinboxBinding.editValue.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
@ -336,6 +387,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.show() .show()
} }
scSetting.setSelectedValue(value) scSetting.setSelectedValue(value)
if (scSetting.setting.key == "app_language") {
settingsViewModel.setShouldRecreateForLanguageChange(true)
// recreate page apply language change instantly
requireActivity().recreate()
}
} }
is StringSingleChoiceSetting -> { is StringSingleChoiceSetting -> {

View file

@ -1030,8 +1030,10 @@ class SettingsFragmentPresenter(
override fun reset() = IntSetting.THEME.setInt(defaultValue) override fun reset() = IntSetting.THEME.setInt(defaultValue)
} }
add(HeaderSetting(R.string.app_settings))
add(IntSetting.APP_LANGUAGE.key)
if (NativeLibrary.isUpdateCheckerEnabled()) { if (NativeLibrary.isUpdateCheckerEnabled()) {
add(HeaderSetting(R.string.app_settings))
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key) add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
} }

View file

@ -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-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -54,6 +57,8 @@ class SettingsViewModel : ViewModel() {
private val _shouldShowResetInputDialog = MutableStateFlow(false) private val _shouldShowResetInputDialog = MutableStateFlow(false)
val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow() val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow()
private val _shouldRecreateForLanguageChange = MutableStateFlow(false)
val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow()
fun setShouldRecreate(value: Boolean) { fun setShouldRecreate(value: Boolean) {
_shouldRecreate.value = value _shouldRecreate.value = value
} }
@ -103,6 +108,10 @@ class SettingsViewModel : ViewModel() {
_shouldShowResetInputDialog.value = value _shouldShowResetInputDialog.value = value
} }
fun setShouldRecreateForLanguageChange(value: Boolean) {
_shouldRecreateForLanguageChange.value = value
}
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage = fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
try { try {
InputHandler.registeredControllers[currentDevice] InputHandler.registeredControllers[currentDevice]

View file

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.ui.main package org.yuzu.yuzu_emu.ui.main
import android.content.Intent import android.content.Intent
import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
@ -53,6 +54,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
import kotlin.text.compareTo import kotlin.text.compareTo
import androidx.core.net.toUri import androidx.core.net.toUri
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.YuzuApplication
class MainActivity : AppCompatActivity(), ThemeProvider { class MainActivity : AppCompatActivity(), ThemeProvider {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
@ -68,6 +70,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private val CHECKED_DECRYPTION = "CheckedDecryption" private val CHECKED_DECRYPTION = "CheckedDecryption"
private var checkedDecryption = false private var checkedDecryption = false
override fun attachBaseContext(base: Context) {
super.attachBaseContext(YuzuApplication.applyLanguage(base))
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen() val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }

View file

@ -62,6 +62,7 @@ namespace AndroidSettings {
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds", Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
Settings::Category::Android}; 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::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
Settings::Category::Android}; Settings::Category::Android};

View file

@ -4,6 +4,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#define VMA_IMPLEMENTATION
#include "video_core/vulkan_common/vma.h"
#include <codecvt> #include <codecvt>
#include <locale> #include <locale>

View file

@ -391,6 +391,61 @@
<item>2</item> <item>2</item>
</integer-array> </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"> <string-array name="outputEngineEntries">
<item>@string/auto</item> <item>@string/auto</item>
<item>@string/oboe</item> <item>@string/oboe</item>

View file

@ -1028,6 +1028,35 @@
<string name="use_black_backgrounds">Black backgrounds</string> <string name="use_black_backgrounds">Black backgrounds</string>
<string name="use_black_backgrounds_description">When using the dark theme, apply 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 --> <!-- Static Themes -->
<string name="static_theme_color">Theme Color</string> <string name="static_theme_color">Theme Color</string>
<string name="eden_theme">Eden (Default)</string> <string name="eden_theme">Eden (Default)</string>

View file

@ -252,7 +252,7 @@ if(CXX_CLANG)
endif() endif()
if (BOOST_NO_HEADERS) if (BOOST_NO_HEADERS)
target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool Boost::filesystem) target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool)
else() else()
target_link_libraries(common PUBLIC Boost::headers) target_link_libraries(common PUBLIC Boost::headers)
endif() endif()

View file

@ -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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -103,46 +106,60 @@ template <>
#else #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> template <typename T>
[[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected) { [[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) { [[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected) {
unsigned __int128 value_a; RealU128 value_a;
unsigned __int128 expected_a; RealU128 expected_a;
std::memcpy(&value_a, value.data(), sizeof(u128)); std::memcpy(&value_a, value.data(), sizeof(u128));
std::memcpy(&expected_a, expected.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> template <typename T>
[[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected, T& actual) { [[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; return actual == expected;
} }
[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected, [[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected, u128& actual) {
u128& actual) { RealU128 value_a;
unsigned __int128 value_a; RealU128 expected_a;
unsigned __int128 expected_a; RealU128 actual_a;
unsigned __int128 actual_a;
std::memcpy(&value_a, value.data(), sizeof(u128)); std::memcpy(&value_a, value.data(), sizeof(u128));
std::memcpy(&expected_a, expected.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)); std::memcpy(actual.data(), &actual_a, sizeof(u128));
return actual_a == expected_a; return actual_a == expected_a;
} }
[[nodiscard]] inline u128 AtomicLoad128(u64* pointer) { [[nodiscard]] inline u128 AtomicLoad128(u64* pointer) {
unsigned __int128 zeros_a = 0; RealU128 zeros_a = U128_ZERO_INIT;
unsigned __int128 result_a = RealU128 result_a = SYNC_VAL_COMPARE_AND_SWAP((RealU128*)pointer, zeros_a, zeros_a);
__sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
u128 result; u128 result;
std::memcpy(result.data(), &result_a, sizeof(u128)); std::memcpy(result.data(), &result_a, sizeof(u128));
return result; return result;
} }
#undef U128_ZERO_INIT
#undef SYNC_VAL_COMPARE_AND_SWAP
#undef SYNC_BOOL_COMPARE_AND_SWAP
#endif #endif

View file

@ -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-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "common/swap.h"
// adapted from https://github.com/fmtlib/fmt/issues/2704 // adapted from https://github.com/fmtlib/fmt/issues/2704
// a generic formatter for enum classes // 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 #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));
}
};

View file

@ -359,6 +359,9 @@ void RestoreGlobalState(bool is_powered_on) {
for (const auto& reset : values.linkage.restore_functions) { for (const auto& reset : values.linkage.restore_functions) {
reset(); reset();
} }
// Reset per-game flags
values.use_squashed_iterated_blend = false;
} }
static bool configuring_global = true; static bool configuring_global = true;

View file

@ -759,6 +759,9 @@ struct Values {
// Add-Ons // Add-Ons
std::map<u64, std::vector<std::string>> disabled_addons; std::map<u64, std::vector<std::string>> disabled_addons;
// Per-game overrides
bool use_squashed_iterated_blend;
}; };
extern Values values; extern Values values;

View file

@ -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 PPSSPP Project
// SPDX-FileCopyrightText: 2012 Dolphin Emulator Project // SPDX-FileCopyrightText: 2012 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -17,7 +20,17 @@
namespace Common { 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 { [[nodiscard]] inline u16 swap16(u16 data) noexcept {
return _byteswap_ushort(data); return _byteswap_ushort(data);
} }
@ -28,12 +41,6 @@ namespace Common {
return _byteswap_uint64(data); return _byteswap_uint64(data);
} }
#elif defined(__clang__) || defined(__GNUC__) #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 { [[nodiscard]] inline u16 swap16(u16 data) noexcept {
return __builtin_bswap16(data); return __builtin_bswap16(data);
} }
@ -44,7 +51,9 @@ namespace Common {
return __builtin_bswap64(data); return __builtin_bswap64(data);
} }
#else #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 { [[nodiscard]] inline u16 swap16(u16 data) noexcept {
return (data >> 8) | (data << 8); return (data >> 8) | (data << 8);
} }
@ -62,33 +71,27 @@ namespace Common {
[[nodiscard]] inline float swapf(float f) noexcept { [[nodiscard]] inline float swapf(float f) noexcept {
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t."); static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
u32 value; u32 value;
std::memcpy(&value, &f, sizeof(u32)); std::memcpy(&value, &f, sizeof(u32));
value = swap32(value); value = swap32(value);
std::memcpy(&f, &value, sizeof(u32)); std::memcpy(&f, &value, sizeof(u32));
return f; return f;
} }
[[nodiscard]] inline double swapd(double f) noexcept { [[nodiscard]] inline double swapd(double f) noexcept {
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t."); static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
u64 value; u64 value;
std::memcpy(&value, &f, sizeof(u64)); std::memcpy(&value, &f, sizeof(u64));
value = swap64(value); value = swap64(value);
std::memcpy(&f, &value, sizeof(u64)); std::memcpy(&f, &value, sizeof(u64));
return f; return f;
} }
} // Namespace Common } // Namespace Common
template <typename T, typename F> template <typename T, typename F>
struct swap_struct_t { struct SwapStructT {
using swapped_t = swap_struct_t; using SwappedT = SwapStructT;
protected: protected:
T value; T value;
@ -101,137 +104,137 @@ public:
T swap() const { T swap() const {
return swap(value); return swap(value);
} }
swap_struct_t() = default; SwapStructT() = default;
swap_struct_t(const T& v) : value(swap(v)) {} SwapStructT(const T& v) : value(swap(v)) {}
template <typename S> template <typename S>
swapped_t& operator=(const S& source) { SwappedT& operator=(const S& source) {
value = swap(static_cast<T>(source)); value = swap(T(source));
return *this; return *this;
} }
operator s8() const { operator s8() const {
return static_cast<s8>(swap()); return s8(swap());
} }
operator u8() const { operator u8() const {
return static_cast<u8>(swap()); return u8(swap());
} }
operator s16() const { operator s16() const {
return static_cast<s16>(swap()); return s16(swap());
} }
operator u16() const { operator u16() const {
return static_cast<u16>(swap()); return u16(swap());
} }
operator s32() const { operator s32() const {
return static_cast<s32>(swap()); return s32(swap());
} }
operator u32() const { operator u32() const {
return static_cast<u32>(swap()); return u32(swap());
} }
operator s64() const { operator s64() const {
return static_cast<s64>(swap()); return s64(swap());
} }
operator u64() const { operator u64() const {
return static_cast<u64>(swap()); return u64(swap());
} }
operator float() const { operator float() const {
return static_cast<float>(swap()); return float(swap());
} }
operator double() const { operator double() const {
return static_cast<double>(swap()); return double(swap());
} }
// +v // +v
swapped_t operator+() const { SwappedT operator+() const {
return +swap(); return +swap();
} }
// -v // -v
swapped_t operator-() const { SwappedT operator-() const {
return -swap(); return -swap();
} }
// v / 5 // v / 5
swapped_t operator/(const swapped_t& i) const { SwappedT operator/(const SwappedT& i) const {
return swap() / i.swap(); return swap() / i.swap();
} }
template <typename S> template <typename S>
swapped_t operator/(const S& i) const { SwappedT operator/(const S& i) const {
return swap() / i; return swap() / i;
} }
// v * 5 // v * 5
swapped_t operator*(const swapped_t& i) const { SwappedT operator*(const SwappedT& i) const {
return swap() * i.swap(); return swap() * i.swap();
} }
template <typename S> template <typename S>
swapped_t operator*(const S& i) const { SwappedT operator*(const S& i) const {
return swap() * i; return swap() * i;
} }
// v + 5 // v + 5
swapped_t operator+(const swapped_t& i) const { SwappedT operator+(const SwappedT& i) const {
return swap() + i.swap(); return swap() + i.swap();
} }
template <typename S> template <typename S>
swapped_t operator+(const S& i) const { SwappedT operator+(const S& i) const {
return swap() + static_cast<T>(i); return swap() + T(i);
} }
// v - 5 // v - 5
swapped_t operator-(const swapped_t& i) const { SwappedT operator-(const SwappedT& i) const {
return swap() - i.swap(); return swap() - i.swap();
} }
template <typename S> template <typename S>
swapped_t operator-(const S& i) const { SwappedT operator-(const S& i) const {
return swap() - static_cast<T>(i); return swap() - T(i);
} }
// v += 5 // v += 5
swapped_t& operator+=(const swapped_t& i) { SwappedT& operator+=(const SwappedT& i) {
value = swap(swap() + i.swap()); value = swap(swap() + i.swap());
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t& operator+=(const S& i) { SwappedT& operator+=(const S& i) {
value = swap(swap() + static_cast<T>(i)); value = swap(swap() + T(i));
return *this; return *this;
} }
// v -= 5 // v -= 5
swapped_t& operator-=(const swapped_t& i) { SwappedT& operator-=(const SwappedT& i) {
value = swap(swap() - i.swap()); value = swap(swap() - i.swap());
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t& operator-=(const S& i) { SwappedT& operator-=(const S& i) {
value = swap(swap() - static_cast<T>(i)); value = swap(swap() - T(i));
return *this; return *this;
} }
// ++v // ++v
swapped_t& operator++() { SwappedT& operator++() {
value = swap(swap() + 1); value = swap(swap() + 1);
return *this; return *this;
} }
// --v // --v
swapped_t& operator--() { SwappedT& operator--() {
value = swap(swap() - 1); value = swap(swap() - 1);
return *this; return *this;
} }
// v++ // v++
swapped_t operator++(int) { SwappedT operator++(int) {
swapped_t old = *this; SwappedT old = *this;
value = swap(swap() + 1); value = swap(swap() + 1);
return old; return old;
} }
// v-- // v--
swapped_t operator--(int) { SwappedT operator--(int) {
swapped_t old = *this; SwappedT old = *this;
value = swap(swap() - 1); value = swap(swap() - 1);
return old; return old;
} }
// Comparison // Comparison
// v == i // v == i
bool operator==(const swapped_t& i) const { bool operator==(const SwappedT& i) const {
return swap() == i.swap(); return swap() == i.swap();
} }
template <typename S> template <typename S>
@ -240,7 +243,7 @@ public:
} }
// v != i // v != i
bool operator!=(const swapped_t& i) const { bool operator!=(const SwappedT& i) const {
return swap() != i.swap(); return swap() != i.swap();
} }
template <typename S> template <typename S>
@ -249,7 +252,7 @@ public:
} }
// v > i // v > i
bool operator>(const swapped_t& i) const { bool operator>(const SwappedT& i) const {
return swap() > i.swap(); return swap() > i.swap();
} }
template <typename S> template <typename S>
@ -258,7 +261,7 @@ public:
} }
// v < i // v < i
bool operator<(const swapped_t& i) const { bool operator<(const SwappedT& i) const {
return swap() < i.swap(); return swap() < i.swap();
} }
template <typename S> template <typename S>
@ -267,7 +270,7 @@ public:
} }
// v >= i // v >= i
bool operator>=(const swapped_t& i) const { bool operator>=(const SwappedT& i) const {
return swap() >= i.swap(); return swap() >= i.swap();
} }
template <typename S> template <typename S>
@ -276,7 +279,7 @@ public:
} }
// v <= i // v <= i
bool operator<=(const swapped_t& i) const { bool operator<=(const SwappedT& i) const {
return swap() <= i.swap(); return swap() <= i.swap();
} }
template <typename S> template <typename S>
@ -285,82 +288,82 @@ public:
} }
// logical // logical
swapped_t operator!() const { SwappedT operator!() const {
return !swap(); return !swap();
} }
// bitmath // bitmath
swapped_t operator~() const { SwappedT operator~() const {
return ~swap(); return ~swap();
} }
swapped_t operator&(const swapped_t& b) const { SwappedT operator&(const SwappedT& b) const {
return swap() & b.swap(); return swap() & b.swap();
} }
template <typename S> template <typename S>
swapped_t operator&(const S& b) const { SwappedT operator&(const S& b) const {
return swap() & b; return swap() & b;
} }
swapped_t& operator&=(const swapped_t& b) { SwappedT& operator&=(const SwappedT& b) {
value = swap(swap() & b.swap()); value = swap(swap() & b.swap());
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t& operator&=(const S b) { SwappedT& operator&=(const S b) {
value = swap(swap() & b); value = swap(swap() & b);
return *this; return *this;
} }
swapped_t operator|(const swapped_t& b) const { SwappedT operator|(const SwappedT& b) const {
return swap() | b.swap(); return swap() | b.swap();
} }
template <typename S> template <typename S>
swapped_t operator|(const S& b) const { SwappedT operator|(const S& b) const {
return swap() | b; return swap() | b;
} }
swapped_t& operator|=(const swapped_t& b) { SwappedT& operator|=(const SwappedT& b) {
value = swap(swap() | b.swap()); value = swap(swap() | b.swap());
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t& operator|=(const S& b) { SwappedT& operator|=(const S& b) {
value = swap(swap() | b); value = swap(swap() | b);
return *this; return *this;
} }
swapped_t operator^(const swapped_t& b) const { SwappedT operator^(const SwappedT& b) const {
return swap() ^ b.swap(); return swap() ^ b.swap();
} }
template <typename S> template <typename S>
swapped_t operator^(const S& b) const { SwappedT operator^(const S& b) const {
return swap() ^ b; return swap() ^ b;
} }
swapped_t& operator^=(const swapped_t& b) { SwappedT& operator^=(const SwappedT& b) {
value = swap(swap() ^ b.swap()); value = swap(swap() ^ b.swap());
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t& operator^=(const S& b) { SwappedT& operator^=(const S& b) {
value = swap(swap() ^ b); value = swap(swap() ^ b);
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t operator<<(const S& b) const { SwappedT operator<<(const S& b) const {
return swap() << b; return swap() << b;
} }
template <typename S> template <typename S>
swapped_t& operator<<=(const S& b) const { SwappedT& operator<<=(const S& b) const {
value = swap(swap() << b); value = swap(swap() << b);
return *this; return *this;
} }
template <typename S> template <typename S>
swapped_t operator>>(const S& b) const { SwappedT operator>>(const S& b) const {
return swap() >> b; return swap() >> b;
} }
template <typename S> template <typename S>
swapped_t& operator>>=(const S& b) const { SwappedT& operator>>=(const S& b) const {
value = swap(swap() >> b); value = swap(swap() >> b);
return *this; return *this;
} }
@ -370,167 +373,167 @@ public:
// Arithmetic // Arithmetic
template <typename S, typename T2, typename F2> 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> 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> 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> 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> 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 // Arithmetic + assignments
template <typename S, typename T2, typename F2> 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> 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 // Bitmath
template <typename S, typename T2, typename F2> 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 // Comparison
template <typename S, typename T2, typename F2> 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> 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> 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> 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> 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> 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 // Arithmetic
template <typename S, typename T, typename F> 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(); return i + v.swap();
} }
template <typename S, typename T, typename F> 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(); return i - v.swap();
} }
template <typename S, typename T, typename F> 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(); return i / v.swap();
} }
template <typename S, typename T, typename F> 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(); return i * v.swap();
} }
template <typename S, typename T, typename F> 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(); return i % v.swap();
} }
// Arithmetic + assignments // Arithmetic + assignments
template <typename S, typename T, typename F> 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(); i += v.swap();
return i; return i;
} }
template <typename S, typename T, typename F> 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(); i -= v.swap();
return i; return i;
} }
// Logical // Logical
template <typename S, typename T, typename F> 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(); return i & v.swap();
} }
// Comparison // Comparison
template <typename S, typename T, typename F> 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(); return p < v.swap();
} }
template <typename S, typename T, typename F> 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(); return p > v.swap();
} }
template <typename S, typename T, typename F> 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(); return p <= v.swap();
} }
template <typename S, typename T, typename F> 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(); return p >= v.swap();
} }
template <typename S, typename T, typename F> 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(); return p != v.swap();
} }
template <typename S, typename T, typename F> 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(); return p == v.swap();
} }
template <typename T> template <typename T>
struct swap_64_t { struct Swap64T {
static T swap(T x) { static T swap(T x) {
return static_cast<T>(Common::swap64(x)); return T(Common::swap64(x));
} }
}; };
template <typename T> template <typename T>
struct swap_32_t { struct Swap32T {
static T swap(T x) { static T swap(T x) {
return static_cast<T>(Common::swap32(x)); return T(Common::swap32(x));
} }
}; };
template <typename T> template <typename T>
struct swap_16_t { struct Swap16T {
static T swap(T x) { static T swap(T x) {
return static_cast<T>(Common::swap16(x)); return T(Common::swap16(x));
} }
}; };
template <typename T> template <typename T>
struct swap_float_t { struct SwapFloatT {
static T swap(T x) { static T swap(T x) {
return static_cast<T>(Common::swapf(x)); return T(Common::swapf(x));
} }
}; };
template <typename T> template <typename T>
struct swap_double_t { struct SwapDoubleT {
static T swap(T x) { static T swap(T x) {
return static_cast<T>(Common::swapd(x)); return T(Common::swapd(x));
} }
}; };
template <typename T> template <typename T>
struct swap_enum_t { struct SwapEnumT {
static_assert(std::is_enum_v<T>); static_assert(std::is_enum_v<T>);
using base = std::underlying_type_t<T>; using base = std::underlying_type_t<T>;
public: public:
swap_enum_t() = default; SwapEnumT() = default;
swap_enum_t(const T& v) : value(swap(v)) {} SwapEnumT(const T& v) : value(swap(v)) {}
swap_enum_t& operator=(const T& v) { SwapEnumT& operator=(const T& v) {
value = swap(v); value = swap(v);
return *this; return *this;
} }
@ -540,22 +543,20 @@ public:
} }
explicit operator base() const { explicit operator base() const {
return static_cast<base>(swap(value)); return base(swap(value));
} }
protected: protected:
T value{}; T value{};
// clang-format off
using swap_t = std::conditional_t< using swap_t = std::conditional_t<
std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t< std::is_same_v<base, u16>, Swap16T<u16>, std::conditional_t<
std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t< std::is_same_v<base, s16>, Swap16T<s16>, std::conditional_t<
std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t< std::is_same_v<base, u32>, Swap32T<u32>, std::conditional_t<
std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t< std::is_same_v<base, s32>, Swap32T<s32>, std::conditional_t<
std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t< std::is_same_v<base, u64>, Swap64T<u64>, std::conditional_t<
std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>; std::is_same_v<base, s64>, Swap64T<s64>, void>>>>>>;
// clang-format on
static T swap(T x) { 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 <> template <>
struct AddEndian<u16, SwapTag> { struct AddEndian<u16, SwapTag> {
using type = swap_struct_t<u16, swap_16_t<u16>>; using type = SwapStructT<u16, Swap16T<u16>>;
}; };
template <> template <>
struct AddEndian<u32, SwapTag> { struct AddEndian<u32, SwapTag> {
using type = swap_struct_t<u32, swap_32_t<u32>>; using type = SwapStructT<u32, Swap32T<u32>>;
}; };
template <> template <>
struct AddEndian<u64, SwapTag> { struct AddEndian<u64, SwapTag> {
using type = swap_struct_t<u64, swap_64_t<u64>>; using type = SwapStructT<u64, Swap64T<u64>>;
}; };
template <> template <>
@ -601,33 +602,33 @@ struct AddEndian<s8, SwapTag> {
template <> template <>
struct AddEndian<s16, SwapTag> { struct AddEndian<s16, SwapTag> {
using type = swap_struct_t<s16, swap_16_t<s16>>; using type = SwapStructT<s16, Swap16T<s16>>;
}; };
template <> template <>
struct AddEndian<s32, SwapTag> { struct AddEndian<s32, SwapTag> {
using type = swap_struct_t<s32, swap_32_t<s32>>; using type = SwapStructT<s32, Swap32T<s32>>;
}; };
template <> template <>
struct AddEndian<s64, SwapTag> { struct AddEndian<s64, SwapTag> {
using type = swap_struct_t<s64, swap_64_t<s64>>; using type = SwapStructT<s64, Swap64T<s64>>;
}; };
template <> template <>
struct AddEndian<float, SwapTag> { struct AddEndian<float, SwapTag> {
using type = swap_struct_t<float, swap_float_t<float>>; using type = SwapStructT<float, SwapFloatT<float>>;
}; };
template <> template <>
struct AddEndian<double, SwapTag> { struct AddEndian<double, SwapTag> {
using type = swap_struct_t<double, swap_double_t<double>>; using type = SwapStructT<double, SwapDoubleT<double>>;
}; };
template <typename T> template <typename T>
struct AddEndian<T, SwapTag> { struct AddEndian<T, SwapTag> {
static_assert(std::is_enum_v<T>); 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 // Alias LETag/BETag as KeepTag/SwapTag depending on the system

View file

@ -1199,10 +1199,10 @@ else()
target_link_libraries(core PUBLIC Boost::headers) target_link_libraries(core PUBLIC Boost::headers)
endif() endif()
target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto MbedTLS::mbedtls) 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) # if (MINGW)
target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi) # target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi)
endif() # endif()
if (ENABLE_WEB_SERVICE) if (ENABLE_WEB_SERVICE)
target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE) target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE)

View file

@ -297,6 +297,9 @@ struct System::Impl {
std::string vendor = gpu_core->Renderer().GetDeviceVendor(); std::string vendor = gpu_core->Renderer().GetDeviceVendor();
LOG_INFO(Core, "GPU Vendor: {}", vendor); LOG_INFO(Core, "GPU Vendor: {}", vendor);
// Reset all per-game flags
Settings::values.use_squashed_iterated_blend = false;
// Insert PC overrides here // Insert PC overrides here
#ifdef ANDROID #ifdef ANDROID
@ -322,6 +325,13 @@ struct System::Impl {
#endif #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, SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
@ -425,6 +435,9 @@ struct System::Impl {
void ShutdownMainProcess() { void ShutdownMainProcess() {
SetShuttingDown(true); SetShuttingDown(true);
// Reset per-game flags
Settings::values.use_squashed_iterated_blend = false;
is_powered_on = false; is_powered_on = false;
exit_locked = false; exit_locked = false;
exit_requested = false; exit_requested = false;

View file

@ -237,7 +237,6 @@ WebBrowser::~WebBrowser() = default;
void WebBrowser::Initialize() { void WebBrowser::Initialize() {
if (Settings::values.disable_web_applet) { if (Settings::values.disable_web_applet) {
LOG_INFO(Service_AM, "Web Browser Applet disabled, skipping.");
return; return;
} }
@ -305,6 +304,7 @@ void WebBrowser::ExecuteInteractive() {
void WebBrowser::Execute() { void WebBrowser::Execute() {
if (Settings::values.disable_web_applet) { if (Settings::values.disable_web_applet) {
LOG_WARNING(Service_AM, "(STUBBED) called, Web Browser Applet is disabled");
WebBrowserExit(WebExitReason::EndButtonPressed); WebBrowserExit(WebExitReason::EndButtonPressed);
return; return;
} }

View file

@ -229,8 +229,7 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
case AppletId::ProfileSelect: case AppletId::ProfileSelect:
return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select); return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard: case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(system, applet, mode, return std::make_shared<SoftwareKeyboard>(system, applet, mode, *frontend.software_keyboard);
*frontend.software_keyboard);
case AppletId::MiiEdit: case AppletId::MiiEdit:
return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit); return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
case AppletId::Web: case AppletId::Web:
@ -244,9 +243,7 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
case AppletId::NetConnect: case AppletId::NetConnect:
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect); return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
default: default:
UNIMPLEMENTED_MSG( LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X}. Falling back to stub applet", static_cast<u8>(id));
"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); return std::make_shared<StubApplet>(system, applet, id, mode);
} }
} }

View file

@ -4,9 +4,6 @@
# SPDX-FileCopyrightText: 2017 Citra Emulator Project # SPDX-FileCopyrightText: 2017 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
add_library(yuzu-room STATIC EXCLUDE_FROM_ALL add_library(yuzu-room STATIC EXCLUDE_FROM_ALL
yuzu_room.cpp yuzu_room.cpp
yuzu_room.h yuzu_room.h
@ -19,7 +16,7 @@ if (ENABLE_WEB_SERVICE)
target_link_libraries(yuzu-room PRIVATE web_service) target_link_libraries(yuzu-room PRIVATE web_service)
endif() 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) if (MSVC)
target_link_libraries(yuzu-room PRIVATE getopt) target_link_libraries(yuzu-room PRIVATE getopt)
endif() endif()

View file

@ -81,11 +81,6 @@ if (MSVC)
/bigobj # Increase number of sections in .obj files /bigobj # Increase number of sections in .obj files
/DNOMINMAX) /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) if (CXX_CLANG)
list(APPEND DYNARMIC_CXX_FLAGS list(APPEND DYNARMIC_CXX_FLAGS
-Qunused-arguments -Qunused-arguments

View file

@ -81,14 +81,12 @@ add_library(shader_recompiler STATIC
environment.h environment.h
exception.h exception.h
frontend/ir/abstract_syntax_list.h frontend/ir/abstract_syntax_list.h
frontend/ir/attribute.cpp
frontend/ir/attribute.h frontend/ir/attribute.h
frontend/ir/basic_block.cpp frontend/ir/basic_block.cpp
frontend/ir/basic_block.h frontend/ir/basic_block.h
frontend/ir/breadth_first_search.h frontend/ir/breadth_first_search.h
frontend/ir/condition.cpp frontend/ir/condition.cpp
frontend/ir/condition.h frontend/ir/condition.h
frontend/ir/flow_test.cpp
frontend/ir/flow_test.h frontend/ir/flow_test.h
frontend/ir/ir_emitter.cpp frontend/ir/ir_emitter.cpp
frontend/ir/ir_emitter.h frontend/ir/ir_emitter.h

View file

@ -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

View file

@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -6,240 +9,261 @@
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "common/common_types.h" #include "common/common_types.h"
#include "shader_recompiler/exception.h"
namespace Shader::IR { namespace Shader::IR {
enum class Attribute : u64 { enum class Attribute : u64 {
PrimitiveId = 24, #define SRIR_ATTRIBUTE_LIST \
Layer = 25, SRIR_ATTRIBUTE_ELEM(PrimitiveId, 24) \
ViewportIndex = 26, SRIR_ATTRIBUTE_ELEM(Layer, 25) \
PointSize = 27, SRIR_ATTRIBUTE_ELEM(ViewportIndex, 26) \
PositionX = 28, SRIR_ATTRIBUTE_ELEM(PointSize, 27) \
PositionY = 29, SRIR_ATTRIBUTE_ELEM(PositionX, 28) \
PositionZ = 30, SRIR_ATTRIBUTE_ELEM(PositionY, 29) \
PositionW = 31, SRIR_ATTRIBUTE_ELEM(PositionZ, 30) \
Generic0X = 32, SRIR_ATTRIBUTE_ELEM(PositionW, 31) \
Generic0Y = 33, SRIR_ATTRIBUTE_ELEM(Generic0X, 32) \
Generic0Z = 34, SRIR_ATTRIBUTE_ELEM(Generic0Y, 33) \
Generic0W = 35, SRIR_ATTRIBUTE_ELEM(Generic0Z, 34) \
Generic1X = 36, SRIR_ATTRIBUTE_ELEM(Generic0W, 35) \
Generic1Y = 37, SRIR_ATTRIBUTE_ELEM(Generic1X, 36) \
Generic1Z = 38, SRIR_ATTRIBUTE_ELEM(Generic1Y, 37) \
Generic1W = 39, SRIR_ATTRIBUTE_ELEM(Generic1Z, 38) \
Generic2X = 40, SRIR_ATTRIBUTE_ELEM(Generic1W, 39) \
Generic2Y = 41, SRIR_ATTRIBUTE_ELEM(Generic2X, 40) \
Generic2Z = 42, SRIR_ATTRIBUTE_ELEM(Generic2Y, 41) \
Generic2W = 43, SRIR_ATTRIBUTE_ELEM(Generic2Z, 42) \
Generic3X = 44, SRIR_ATTRIBUTE_ELEM(Generic2W, 43) \
Generic3Y = 45, SRIR_ATTRIBUTE_ELEM(Generic3X, 44) \
Generic3Z = 46, SRIR_ATTRIBUTE_ELEM(Generic3Y, 45) \
Generic3W = 47, SRIR_ATTRIBUTE_ELEM(Generic3Z, 46) \
Generic4X = 48, SRIR_ATTRIBUTE_ELEM(Generic3W, 47) \
Generic4Y = 49, SRIR_ATTRIBUTE_ELEM(Generic4X, 48) \
Generic4Z = 50, SRIR_ATTRIBUTE_ELEM(Generic4Y, 49) \
Generic4W = 51, SRIR_ATTRIBUTE_ELEM(Generic4Z, 50) \
Generic5X = 52, SRIR_ATTRIBUTE_ELEM(Generic4W, 51) \
Generic5Y = 53, SRIR_ATTRIBUTE_ELEM(Generic5X, 52) \
Generic5Z = 54, SRIR_ATTRIBUTE_ELEM(Generic5Y, 53) \
Generic5W = 55, SRIR_ATTRIBUTE_ELEM(Generic5Z, 54) \
Generic6X = 56, SRIR_ATTRIBUTE_ELEM(Generic5W, 55) \
Generic6Y = 57, SRIR_ATTRIBUTE_ELEM(Generic6X, 56) \
Generic6Z = 58, SRIR_ATTRIBUTE_ELEM(Generic6Y, 57) \
Generic6W = 59, SRIR_ATTRIBUTE_ELEM(Generic6Z, 58) \
Generic7X = 60, SRIR_ATTRIBUTE_ELEM(Generic6W, 59) \
Generic7Y = 61, SRIR_ATTRIBUTE_ELEM(Generic7X, 60) \
Generic7Z = 62, SRIR_ATTRIBUTE_ELEM(Generic7Y, 61) \
Generic7W = 63, SRIR_ATTRIBUTE_ELEM(Generic7Z, 62) \
Generic8X = 64, SRIR_ATTRIBUTE_ELEM(Generic7W, 63) \
Generic8Y = 65, SRIR_ATTRIBUTE_ELEM(Generic8X, 64) \
Generic8Z = 66, SRIR_ATTRIBUTE_ELEM(Generic8Y, 65) \
Generic8W = 67, SRIR_ATTRIBUTE_ELEM(Generic8Z, 66) \
Generic9X = 68, SRIR_ATTRIBUTE_ELEM(Generic8W, 67) \
Generic9Y = 69, SRIR_ATTRIBUTE_ELEM(Generic9X, 68) \
Generic9Z = 70, SRIR_ATTRIBUTE_ELEM(Generic9Y, 69) \
Generic9W = 71, SRIR_ATTRIBUTE_ELEM(Generic9Z, 70) \
Generic10X = 72, SRIR_ATTRIBUTE_ELEM(Generic9W, 71) \
Generic10Y = 73, SRIR_ATTRIBUTE_ELEM(Generic10X, 72) \
Generic10Z = 74, SRIR_ATTRIBUTE_ELEM(Generic10Y, 73) \
Generic10W = 75, SRIR_ATTRIBUTE_ELEM(Generic10Z, 74) \
Generic11X = 76, SRIR_ATTRIBUTE_ELEM(Generic10W, 75) \
Generic11Y = 77, SRIR_ATTRIBUTE_ELEM(Generic11X, 76) \
Generic11Z = 78, SRIR_ATTRIBUTE_ELEM(Generic11Y, 77) \
Generic11W = 79, SRIR_ATTRIBUTE_ELEM(Generic11Z, 78) \
Generic12X = 80, SRIR_ATTRIBUTE_ELEM(Generic11W, 79) \
Generic12Y = 81, SRIR_ATTRIBUTE_ELEM(Generic12X, 80) \
Generic12Z = 82, SRIR_ATTRIBUTE_ELEM(Generic12Y, 81) \
Generic12W = 83, SRIR_ATTRIBUTE_ELEM(Generic12Z, 82) \
Generic13X = 84, SRIR_ATTRIBUTE_ELEM(Generic12W, 83) \
Generic13Y = 85, SRIR_ATTRIBUTE_ELEM(Generic13X, 84) \
Generic13Z = 86, SRIR_ATTRIBUTE_ELEM(Generic13Y, 85) \
Generic13W = 87, SRIR_ATTRIBUTE_ELEM(Generic13Z, 86) \
Generic14X = 88, SRIR_ATTRIBUTE_ELEM(Generic13W, 87) \
Generic14Y = 89, SRIR_ATTRIBUTE_ELEM(Generic14X, 88) \
Generic14Z = 90, SRIR_ATTRIBUTE_ELEM(Generic14Y, 89) \
Generic14W = 91, SRIR_ATTRIBUTE_ELEM(Generic14Z, 90) \
Generic15X = 92, SRIR_ATTRIBUTE_ELEM(Generic14W, 91) \
Generic15Y = 93, SRIR_ATTRIBUTE_ELEM(Generic15X, 92) \
Generic15Z = 94, SRIR_ATTRIBUTE_ELEM(Generic15Y, 93) \
Generic15W = 95, SRIR_ATTRIBUTE_ELEM(Generic15Z, 94) \
Generic16X = 96, SRIR_ATTRIBUTE_ELEM(Generic15W, 95) \
Generic16Y = 97, SRIR_ATTRIBUTE_ELEM(Generic16X, 96) \
Generic16Z = 98, SRIR_ATTRIBUTE_ELEM(Generic16Y, 97) \
Generic16W = 99, SRIR_ATTRIBUTE_ELEM(Generic16Z, 98) \
Generic17X = 100, SRIR_ATTRIBUTE_ELEM(Generic16W, 99) \
Generic17Y = 101, SRIR_ATTRIBUTE_ELEM(Generic17X, 100) \
Generic17Z = 102, SRIR_ATTRIBUTE_ELEM(Generic17Y, 101) \
Generic17W = 103, SRIR_ATTRIBUTE_ELEM(Generic17Z, 102) \
Generic18X = 104, SRIR_ATTRIBUTE_ELEM(Generic17W, 103) \
Generic18Y = 105, SRIR_ATTRIBUTE_ELEM(Generic18X, 104) \
Generic18Z = 106, SRIR_ATTRIBUTE_ELEM(Generic18Y, 105) \
Generic18W = 107, SRIR_ATTRIBUTE_ELEM(Generic18Z, 106) \
Generic19X = 108, SRIR_ATTRIBUTE_ELEM(Generic18W, 107) \
Generic19Y = 109, SRIR_ATTRIBUTE_ELEM(Generic19X, 108) \
Generic19Z = 110, SRIR_ATTRIBUTE_ELEM(Generic19Y, 109) \
Generic19W = 111, SRIR_ATTRIBUTE_ELEM(Generic19Z, 110) \
Generic20X = 112, SRIR_ATTRIBUTE_ELEM(Generic19W, 111) \
Generic20Y = 113, SRIR_ATTRIBUTE_ELEM(Generic20X, 112) \
Generic20Z = 114, SRIR_ATTRIBUTE_ELEM(Generic20Y, 113) \
Generic20W = 115, SRIR_ATTRIBUTE_ELEM(Generic20Z, 114) \
Generic21X = 116, SRIR_ATTRIBUTE_ELEM(Generic20W, 115) \
Generic21Y = 117, SRIR_ATTRIBUTE_ELEM(Generic21X, 116) \
Generic21Z = 118, SRIR_ATTRIBUTE_ELEM(Generic21Y, 117) \
Generic21W = 119, SRIR_ATTRIBUTE_ELEM(Generic21Z, 118) \
Generic22X = 120, SRIR_ATTRIBUTE_ELEM(Generic21W, 119) \
Generic22Y = 121, SRIR_ATTRIBUTE_ELEM(Generic22X, 120) \
Generic22Z = 122, SRIR_ATTRIBUTE_ELEM(Generic22Y, 121) \
Generic22W = 123, SRIR_ATTRIBUTE_ELEM(Generic22Z, 122) \
Generic23X = 124, SRIR_ATTRIBUTE_ELEM(Generic22W, 123) \
Generic23Y = 125, SRIR_ATTRIBUTE_ELEM(Generic23X, 124) \
Generic23Z = 126, SRIR_ATTRIBUTE_ELEM(Generic23Y, 125) \
Generic23W = 127, SRIR_ATTRIBUTE_ELEM(Generic23Z, 126) \
Generic24X = 128, SRIR_ATTRIBUTE_ELEM(Generic23W, 127) \
Generic24Y = 129, SRIR_ATTRIBUTE_ELEM(Generic24X, 128) \
Generic24Z = 130, SRIR_ATTRIBUTE_ELEM(Generic24Y, 129) \
Generic24W = 131, SRIR_ATTRIBUTE_ELEM(Generic24Z, 130) \
Generic25X = 132, SRIR_ATTRIBUTE_ELEM(Generic24W, 131) \
Generic25Y = 133, SRIR_ATTRIBUTE_ELEM(Generic25X, 132) \
Generic25Z = 134, SRIR_ATTRIBUTE_ELEM(Generic25Y, 133) \
Generic25W = 135, SRIR_ATTRIBUTE_ELEM(Generic25Z, 134) \
Generic26X = 136, SRIR_ATTRIBUTE_ELEM(Generic25W, 135) \
Generic26Y = 137, SRIR_ATTRIBUTE_ELEM(Generic26X, 136) \
Generic26Z = 138, SRIR_ATTRIBUTE_ELEM(Generic26Y, 137) \
Generic26W = 139, SRIR_ATTRIBUTE_ELEM(Generic26Z, 138) \
Generic27X = 140, SRIR_ATTRIBUTE_ELEM(Generic26W, 139) \
Generic27Y = 141, SRIR_ATTRIBUTE_ELEM(Generic27X, 140) \
Generic27Z = 142, SRIR_ATTRIBUTE_ELEM(Generic27Y, 141) \
Generic27W = 143, SRIR_ATTRIBUTE_ELEM(Generic27Z, 142) \
Generic28X = 144, SRIR_ATTRIBUTE_ELEM(Generic27W, 143) \
Generic28Y = 145, SRIR_ATTRIBUTE_ELEM(Generic28X, 144) \
Generic28Z = 146, SRIR_ATTRIBUTE_ELEM(Generic28Y, 145) \
Generic28W = 147, SRIR_ATTRIBUTE_ELEM(Generic28Z, 146) \
Generic29X = 148, SRIR_ATTRIBUTE_ELEM(Generic28W, 147) \
Generic29Y = 149, SRIR_ATTRIBUTE_ELEM(Generic29X, 148) \
Generic29Z = 150, SRIR_ATTRIBUTE_ELEM(Generic29Y, 149) \
Generic29W = 151, SRIR_ATTRIBUTE_ELEM(Generic29Z, 150) \
Generic30X = 152, SRIR_ATTRIBUTE_ELEM(Generic29W, 151) \
Generic30Y = 153, SRIR_ATTRIBUTE_ELEM(Generic30X, 152) \
Generic30Z = 154, SRIR_ATTRIBUTE_ELEM(Generic30Y, 153) \
Generic30W = 155, SRIR_ATTRIBUTE_ELEM(Generic30Z, 154) \
Generic31X = 156, SRIR_ATTRIBUTE_ELEM(Generic30W, 155) \
Generic31Y = 157, SRIR_ATTRIBUTE_ELEM(Generic31X, 156) \
Generic31Z = 158, SRIR_ATTRIBUTE_ELEM(Generic31Y, 157) \
Generic31W = 159, SRIR_ATTRIBUTE_ELEM(Generic31Z, 158) \
ColorFrontDiffuseR = 160, SRIR_ATTRIBUTE_ELEM(Generic31W, 159) \
ColorFrontDiffuseG = 161, SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseR, 160) \
ColorFrontDiffuseB = 162, SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseG, 161) \
ColorFrontDiffuseA = 163, SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseB, 162) \
ColorFrontSpecularR = 164, SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseA, 163) \
ColorFrontSpecularG = 165, SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularR, 164) \
ColorFrontSpecularB = 166, SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularG, 165) \
ColorFrontSpecularA = 167, SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularB, 166) \
ColorBackDiffuseR = 168, SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularA, 167) \
ColorBackDiffuseG = 169, SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseR, 168) \
ColorBackDiffuseB = 170, SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseG, 169) \
ColorBackDiffuseA = 171, SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseB, 170) \
ColorBackSpecularR = 172, SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseA, 171) \
ColorBackSpecularG = 173, SRIR_ATTRIBUTE_ELEM(ColorBackSpecularR, 172) \
ColorBackSpecularB = 174, SRIR_ATTRIBUTE_ELEM(ColorBackSpecularG, 173) \
ColorBackSpecularA = 175, SRIR_ATTRIBUTE_ELEM(ColorBackSpecularB, 174) \
ClipDistance0 = 176, SRIR_ATTRIBUTE_ELEM(ColorBackSpecularA, 175) \
ClipDistance1 = 177, SRIR_ATTRIBUTE_ELEM(ClipDistance0, 176) \
ClipDistance2 = 178, SRIR_ATTRIBUTE_ELEM(ClipDistance1, 177) \
ClipDistance3 = 179, SRIR_ATTRIBUTE_ELEM(ClipDistance2, 178) \
ClipDistance4 = 180, SRIR_ATTRIBUTE_ELEM(ClipDistance3, 179) \
ClipDistance5 = 181, SRIR_ATTRIBUTE_ELEM(ClipDistance4, 180) \
ClipDistance6 = 182, SRIR_ATTRIBUTE_ELEM(ClipDistance5, 181) \
ClipDistance7 = 183, SRIR_ATTRIBUTE_ELEM(ClipDistance6, 182) \
PointSpriteS = 184, SRIR_ATTRIBUTE_ELEM(ClipDistance7, 183) \
PointSpriteT = 185, SRIR_ATTRIBUTE_ELEM(PointSpriteS, 184) \
FogCoordinate = 186, SRIR_ATTRIBUTE_ELEM(PointSpriteT, 185) \
TessellationEvaluationPointU = 188, SRIR_ATTRIBUTE_ELEM(FogCoordinate, 186) \
TessellationEvaluationPointV = 189, SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointU, 188) \
InstanceId = 190, SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointV, 189) \
VertexId = 191, SRIR_ATTRIBUTE_ELEM(InstanceId, 190) \
FixedFncTexture0S = 192, SRIR_ATTRIBUTE_ELEM(VertexId, 191) \
FixedFncTexture0T = 193, SRIR_ATTRIBUTE_ELEM(FixedFncTexture0S, 192) \
FixedFncTexture0R = 194, SRIR_ATTRIBUTE_ELEM(FixedFncTexture0T, 193) \
FixedFncTexture0Q = 195, SRIR_ATTRIBUTE_ELEM(FixedFncTexture0R, 194) \
FixedFncTexture1S = 196, SRIR_ATTRIBUTE_ELEM(FixedFncTexture0Q, 195) \
FixedFncTexture1T = 197, SRIR_ATTRIBUTE_ELEM(FixedFncTexture1S, 196) \
FixedFncTexture1R = 198, SRIR_ATTRIBUTE_ELEM(FixedFncTexture1T, 197) \
FixedFncTexture1Q = 199, SRIR_ATTRIBUTE_ELEM(FixedFncTexture1R, 198) \
FixedFncTexture2S = 200, SRIR_ATTRIBUTE_ELEM(FixedFncTexture1Q, 199) \
FixedFncTexture2T = 201, SRIR_ATTRIBUTE_ELEM(FixedFncTexture2S, 200) \
FixedFncTexture2R = 202, SRIR_ATTRIBUTE_ELEM(FixedFncTexture2T, 201) \
FixedFncTexture2Q = 203, SRIR_ATTRIBUTE_ELEM(FixedFncTexture2R, 202) \
FixedFncTexture3S = 204, SRIR_ATTRIBUTE_ELEM(FixedFncTexture2Q, 203) \
FixedFncTexture3T = 205, SRIR_ATTRIBUTE_ELEM(FixedFncTexture3S, 204) \
FixedFncTexture3R = 206, SRIR_ATTRIBUTE_ELEM(FixedFncTexture3T, 205) \
FixedFncTexture3Q = 207, SRIR_ATTRIBUTE_ELEM(FixedFncTexture3R, 206) \
FixedFncTexture4S = 208, SRIR_ATTRIBUTE_ELEM(FixedFncTexture3Q, 207) \
FixedFncTexture4T = 209, SRIR_ATTRIBUTE_ELEM(FixedFncTexture4S, 208) \
FixedFncTexture4R = 210, SRIR_ATTRIBUTE_ELEM(FixedFncTexture4T, 209) \
FixedFncTexture4Q = 211, SRIR_ATTRIBUTE_ELEM(FixedFncTexture4R, 210) \
FixedFncTexture5S = 212, SRIR_ATTRIBUTE_ELEM(FixedFncTexture4Q, 211) \
FixedFncTexture5T = 213, SRIR_ATTRIBUTE_ELEM(FixedFncTexture5S, 212) \
FixedFncTexture5R = 214, SRIR_ATTRIBUTE_ELEM(FixedFncTexture5T, 213) \
FixedFncTexture5Q = 215, SRIR_ATTRIBUTE_ELEM(FixedFncTexture5R, 214) \
FixedFncTexture6S = 216, SRIR_ATTRIBUTE_ELEM(FixedFncTexture5Q, 215) \
FixedFncTexture6T = 217, SRIR_ATTRIBUTE_ELEM(FixedFncTexture6S, 216) \
FixedFncTexture6R = 218, SRIR_ATTRIBUTE_ELEM(FixedFncTexture6T, 217) \
FixedFncTexture6Q = 219, SRIR_ATTRIBUTE_ELEM(FixedFncTexture6R, 218) \
FixedFncTexture7S = 220, SRIR_ATTRIBUTE_ELEM(FixedFncTexture6Q, 219) \
FixedFncTexture7T = 221, SRIR_ATTRIBUTE_ELEM(FixedFncTexture7S, 220) \
FixedFncTexture7R = 222, SRIR_ATTRIBUTE_ELEM(FixedFncTexture7T, 221) \
FixedFncTexture7Q = 223, SRIR_ATTRIBUTE_ELEM(FixedFncTexture7R, 222) \
FixedFncTexture8S = 224, SRIR_ATTRIBUTE_ELEM(FixedFncTexture7Q, 223) \
FixedFncTexture8T = 225, SRIR_ATTRIBUTE_ELEM(FixedFncTexture8S, 224) \
FixedFncTexture8R = 226, SRIR_ATTRIBUTE_ELEM(FixedFncTexture8T, 225) \
FixedFncTexture8Q = 227, SRIR_ATTRIBUTE_ELEM(FixedFncTexture8R, 226) \
FixedFncTexture9S = 228, SRIR_ATTRIBUTE_ELEM(FixedFncTexture8Q, 227) \
FixedFncTexture9T = 229, SRIR_ATTRIBUTE_ELEM(FixedFncTexture9S, 228) \
FixedFncTexture9R = 230, SRIR_ATTRIBUTE_ELEM(FixedFncTexture9T, 229) \
FixedFncTexture9Q = 231, SRIR_ATTRIBUTE_ELEM(FixedFncTexture9R, 230) \
ViewportMask = 232, SRIR_ATTRIBUTE_ELEM(FixedFncTexture9Q, 231) \
FrontFace = 255, SRIR_ATTRIBUTE_ELEM(ViewportMask, 232) \
SRIR_ATTRIBUTE_ELEM(FrontFace, 255) \
// Implementation attributes /* Implementation attributes */ \
BaseInstance = 256, SRIR_ATTRIBUTE_ELEM(BaseInstance, 256) \
BaseVertex = 257, SRIR_ATTRIBUTE_ELEM(BaseVertex, 257) \
DrawID = 258, 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_GENERICS = 32;
constexpr size_t NUM_FIXEDFNCTEXTURE = 10; 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 { [[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 } // namespace Shader::IR

View file

@ -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

View file

@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -7,45 +10,58 @@
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "common/common_types.h" #include "common/common_types.h"
#include "shader_recompiler/exception.h"
namespace Shader::IR { namespace Shader::IR {
enum class FlowTest : u64 { enum class FlowTest : u64 {
F, #define SRIR_FLOW_TEST_LIST \
LT, SRIR_FLOW_TEST_ELEM(F) \
EQ, SRIR_FLOW_TEST_ELEM(LT) \
LE, SRIR_FLOW_TEST_ELEM(EQ) \
GT, SRIR_FLOW_TEST_ELEM(LE) \
NE, SRIR_FLOW_TEST_ELEM(GT) \
GE, SRIR_FLOW_TEST_ELEM(NE) \
NUM, SRIR_FLOW_TEST_ELEM(GE) \
NaN, SRIR_FLOW_TEST_ELEM(NUM) \
LTU, SRIR_FLOW_TEST_ELEM(NaN) \
EQU, SRIR_FLOW_TEST_ELEM(LTU) \
LEU, SRIR_FLOW_TEST_ELEM(EQU) \
GTU, SRIR_FLOW_TEST_ELEM(LEU) \
NEU, SRIR_FLOW_TEST_ELEM(GTU) \
GEU, SRIR_FLOW_TEST_ELEM(NEU) \
T, SRIR_FLOW_TEST_ELEM(GEU) \
OFF, SRIR_FLOW_TEST_ELEM(T) \
LO, SRIR_FLOW_TEST_ELEM(OFF) \
SFF, SRIR_FLOW_TEST_ELEM(LO) \
LS, SRIR_FLOW_TEST_ELEM(SFF) \
HI, SRIR_FLOW_TEST_ELEM(LS) \
SFT, SRIR_FLOW_TEST_ELEM(HI) \
HS, SRIR_FLOW_TEST_ELEM(SFT) \
OFT, SRIR_FLOW_TEST_ELEM(HS) \
CSM_TA, SRIR_FLOW_TEST_ELEM(OFT) \
CSM_TR, SRIR_FLOW_TEST_ELEM(CSM_TA) \
CSM_MX, SRIR_FLOW_TEST_ELEM(CSM_TR) \
FCSM_TA, SRIR_FLOW_TEST_ELEM(CSM_MX) \
FCSM_TR, SRIR_FLOW_TEST_ELEM(FCSM_TA) \
FCSM_MX, SRIR_FLOW_TEST_ELEM(FCSM_TR) \
RLE, SRIR_FLOW_TEST_ELEM(FCSM_MX) \
RGT, 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 } // namespace Shader::IR

View file

@ -145,7 +145,7 @@ bool IsSizeInt32(Size size) {
} }
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg, 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) { u64 bound_offset, bool is_bindless, bool write_result) {
if (clamp != Clamp::IGN) { if (clamp != Clamp::IGN) {
throw NotImplementedException("Clamp {}", clamp); 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 TextureType tex_type{GetType(type)};
const IR::Value coords{MakeCoords(v, coord_reg, type)}; const IR::Value coords{MakeCoords(v, coord_reg, type)};
const IR::U32 handle{is_bindless != 0 ? v.X(bindless_reg) const IR::U32 handle = is_bindless ? v.X(*bindless_reg) : v.ir.Imm32(u32(bound_offset * 4));
: v.ir.Imm32(static_cast<u32>(bound_offset * 4))};
IR::TextureInstInfo info{}; IR::TextureInstInfo info{};
info.type.Assign(tex_type); info.type.Assign(tex_type);
info.image_format.Assign(format); info.image_format.Assign(format);
@ -185,7 +184,7 @@ void TranslatorVisitor::SUATOM(u64 insn) {
BitField<0, 8, IR::Reg> dest_reg; BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 8, IR::Reg> coord_reg; BitField<8, 8, IR::Reg> coord_reg;
BitField<20, 8, IR::Reg> operand_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 BitField<39, 8, IR::Reg> bindless_reg; // is_bindless
} const suatom{insn}; } const suatom{insn};
@ -196,21 +195,20 @@ void TranslatorVisitor::SUATOM(u64 insn) {
void TranslatorVisitor::SURED(u64 insn) { void TranslatorVisitor::SURED(u64 insn) {
// TODO: confirm offsets // TODO: confirm offsets
// SURED unlike SUATOM does NOT have a binded register
union { union {
u64 raw; u64 raw;
BitField<51, 1, u64> is_bound; BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp)
BitField<21, 3, AtomicOp> op; BitField<33, 3, Type> type; //OK? - 33 (Dim)
BitField<33, 3, Type> type; BitField<20, 3, Size> size; //?
BitField<20, 3, Size> size; BitField<49, 2, Clamp> clamp; //OK - 49 (Clamp4)
BitField<49, 2, Clamp> clamp; BitField<0, 8, IR::Reg> operand_reg; //RA?
BitField<0, 8, IR::Reg> operand_reg; BitField<8, 8, IR::Reg> coord_reg; //RB?
BitField<8, 8, IR::Reg> coord_reg; BitField<36, 13, u64> bound_offset; //OK 33 (TidB)
BitField<36, 13, u64> bound_offset; // is_bound
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
} const sured{insn}; } 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.op, sured.clamp, sured.size, sured.type, sured.bound_offset,
sured.is_bound == 0, false); false, false);
} }
} // namespace Shader::Maxwell } // namespace Shader::Maxwell

View file

@ -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) target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2WithMain Threads::Threads)
add_test(NAME tests COMMAND tests) 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()

View file

@ -1,6 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2019 Citra Emulator Project // SPDX-FileCopyrightText: 2019 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#define VMA_IMPLEMENTATION
#include "video_core/vulkan_common/vma.h"
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <type_traits> #include <type_traits>

View file

@ -312,7 +312,6 @@ add_library(video_core STATIC
vulkan_common/vulkan_wrapper.h vulkan_common/vulkan_wrapper.h
vulkan_common/nsight_aftermath_tracker.cpp vulkan_common/nsight_aftermath_tracker.cpp
vulkan_common/nsight_aftermath_tracker.h vulkan_common/nsight_aftermath_tracker.h
vulkan_common/vma.cpp
vulkan_common/vma.h vulkan_common/vma.h
vulkan_common/vulkan.h vulkan_common/vulkan.h
) )
@ -369,9 +368,6 @@ else()
# xbyak # xbyak
set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow") set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow")
# VMA
set_source_files_properties(vulkan_common/vma.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-unused-variable;-Wno-unused-parameter;-Wno-missing-field-initializers")
# Get around GCC failing with intrinsics in Debug # Get around GCC failing with intrinsics in Debug
if (CXX_GCC AND CMAKE_BUILD_TYPE MATCHES "Debug") if (CXX_GCC AND CMAKE_BUILD_TYPE MATCHES "Debug")
set_source_files_properties(host1x/vic.cpp PROPERTIES COMPILE_OPTIONS "-O2") set_source_files_properties(host1x/vic.cpp PROPERTIES COMPILE_OPTIONS "-O2")

View file

@ -1142,6 +1142,14 @@ void RasterizerOpenGL::SyncBlendState() {
glDisable(GL_BLEND); glDisable(GL_BLEND);
return; return;
} }
// Temporary workaround for games that use iterated blending
if (regs.iterated_blend.enable && Settings::values.use_squashed_iterated_blend) {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
return;
}
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.color_source), glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.color_source),
MaxwellToGL::BlendFunc(regs.blend.color_dest), MaxwellToGL::BlendFunc(regs.blend.color_dest),

View file

@ -11,6 +11,7 @@
#include <ranges> #include <ranges>
#include "common/cityhash.h" #include "common/cityhash.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h"
#include "video_core/engines/draw_manager.h" #include "video_core/engines/draw_manager.h"
#include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h"
#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_state_tracker.h"
@ -201,6 +202,19 @@ void FixedPipelineState::BlendingAttachment::Refresh(const Maxwell& regs, size_t
}; };
if (!regs.blend_per_target_enabled) { if (!regs.blend_per_target_enabled) {
// Temporary workaround for games that use iterated blending
// even when dynamic blending is off so overrides work with EDS = 0 as well
if (regs.iterated_blend.enable && Settings::values.use_squashed_iterated_blend) {
equation_rgb.Assign(PackBlendEquation(Maxwell::Blend::Equation::Add_GL));
equation_a.Assign(PackBlendEquation(Maxwell::Blend::Equation::Add_GL));
factor_source_rgb.Assign(PackBlendFactor(Maxwell::Blend::Factor::One_GL));
factor_dest_rgb.Assign(PackBlendFactor(Maxwell::Blend::Factor::One_GL));
factor_source_a.Assign(
PackBlendFactor(Maxwell::Blend::Factor::OneMinusSourceColor_GL));
factor_dest_a.Assign(PackBlendFactor(Maxwell::Blend::Factor::Zero_GL));
enable.Assign(1);
return;
}
setup_blend(regs.blend); setup_blend(regs.blend);
return; return;
} }

View file

@ -414,13 +414,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1, .has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1,
.has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2, .has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2,
.has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2, .has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2,
.has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(), .has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported() && dynamic_state > 2,
}; };
LOG_INFO(Render_Vulkan, "DynamicState1: {}", dynamic_features.has_extended_dynamic_state);
LOG_INFO(Render_Vulkan, "DynamicState2: {}", dynamic_features.has_extended_dynamic_state_2);
LOG_INFO(Render_Vulkan, "DynamicState3: {}", dynamic_features.has_extended_dynamic_state_3_enables);
LOG_INFO(Render_Vulkan, "DynamicVertexInput: {}", dynamic_features.has_dynamic_vertex_input);
} }
PipelineCache::~PipelineCache() { PipelineCache::~PipelineCache() {

View file

@ -956,38 +956,24 @@ void RasterizerVulkan::UpdateDynamicStates() {
const u8 dynamic_state = Settings::values.dyna_state.GetValue(); const u8 dynamic_state = Settings::values.dyna_state.GetValue();
auto features = DynamicFeatures{ if (device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0) {
.has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0,
.has_extended_dynamic_state_2 = device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1,
.has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1,
.has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2,
.has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2,
.has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(),
};
if (features.has_extended_dynamic_state) {
UpdateCullMode(regs); UpdateCullMode(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs); UpdateFrontFace(regs);
UpdateStencilOp(regs); UpdateStencilOp(regs);
if (state_tracker.TouchStateEnable()) { if (state_tracker.TouchStateEnable()) {
UpdateDepthBoundsTestEnable(regs); UpdateDepthBoundsTestEnable(regs);
UpdateDepthTestEnable(regs); UpdateDepthTestEnable(regs);
UpdateDepthWriteEnable(regs); UpdateDepthWriteEnable(regs);
UpdateStencilTestEnable(regs); UpdateStencilTestEnable(regs);
if (device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1) {
if (features.has_extended_dynamic_state_2) {
UpdatePrimitiveRestartEnable(regs); UpdatePrimitiveRestartEnable(regs);
UpdateRasterizerDiscardEnable(regs); UpdateRasterizerDiscardEnable(regs);
UpdateDepthBiasEnable(regs); UpdateDepthBiasEnable(regs);
} }
if (device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2) {
if (features.has_extended_dynamic_state_3_enables) {
using namespace Tegra::Engines; using namespace Tegra::Engines;
if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE || device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) {
if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE ||
device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) {
struct In { struct In {
const Maxwell3D::Regs::VertexAttribute::Type d; const Maxwell3D::Regs::VertexAttribute::Type d;
In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {}
@ -995,33 +981,28 @@ void RasterizerVulkan::UpdateDynamicStates() {
return n.type == d; return n.type == d;
} }
}; };
auto has_float = std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), In(Maxwell3D::Regs::VertexAttribute::Type::Float));
auto has_float = std::any_of(regs.vertex_attrib_format.begin(), if (regs.logic_op.enable) {
regs.vertex_attrib_format.end(),
In(Maxwell3D::Regs::VertexAttribute::Type::Float));
if (regs.logic_op.enable)
regs.logic_op.enable = static_cast<u32>(!has_float); regs.logic_op.enable = static_cast<u32>(!has_float);
}
UpdateLogicOpEnable(regs); UpdateLogicOpEnable(regs);
} else { } else {
UpdateLogicOpEnable(regs); UpdateLogicOpEnable(regs);
} }
UpdateDepthClampEnable(regs); UpdateDepthClampEnable(regs);
UpdateLineStippleEnable(regs);
UpdateConservativeRasterizationMode(regs);
} }
} }
if (features.has_extended_dynamic_state_2_extra) { if (device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1) {
UpdateLogicOp(regs); UpdateLogicOp(regs);
} }
if (features.has_extended_dynamic_state_3_enables) { if (device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2) {
UpdateBlending(regs); UpdateBlending(regs);
UpdateLineStippleEnable(regs);
UpdateConservativeRasterizationMode(regs);
} }
} }
if (features.has_dynamic_vertex_input) { if (device.IsExtVertexInputDynamicStateSupported() && dynamic_state > 2) {
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
gp && gp->HasDynamicVertexInput()) {
UpdateVertexInput(regs); UpdateVertexInput(regs);
} }
} }
@ -1557,22 +1538,41 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
if (state_tracker.TouchBlendEquations()) { if (state_tracker.TouchBlendEquations()) {
std::array<VkColorBlendEquationEXT, Maxwell::NumRenderTargets> setup_blends{}; std::array<VkColorBlendEquationEXT, Maxwell::NumRenderTargets> setup_blends{};
for (size_t index = 0; index < Maxwell::NumRenderTargets; index++) {
const auto blend_setup = [&]<typename T>(const T& guest_blend) { const auto blend_setup = [&](auto& host_blend, const auto& guest_blend) {
auto& host_blend = setup_blends[index]; host_blend.srcColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_source);
host_blend.srcColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_source); host_blend.dstColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_dest);
host_blend.dstColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_dest); host_blend.colorBlendOp = MaxwellToVK::BlendEquation(guest_blend.color_op);
host_blend.colorBlendOp = MaxwellToVK::BlendEquation(guest_blend.color_op); host_blend.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_source);
host_blend.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_source); host_blend.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_dest);
host_blend.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_dest); host_blend.alphaBlendOp = MaxwellToVK::BlendEquation(guest_blend.alpha_op);
host_blend.alphaBlendOp = MaxwellToVK::BlendEquation(guest_blend.alpha_op); };
};
if (!regs.blend_per_target_enabled) { // Single blend equation for all targets
blend_setup(regs.blend); if (!regs.blend_per_target_enabled) {
continue; // Temporary workaround for games that use iterated blending
if (regs.iterated_blend.enable && Settings::values.use_squashed_iterated_blend) {
setup_blends[0].srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
setup_blends[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
setup_blends[0].colorBlendOp = VK_BLEND_OP_ADD;
setup_blends[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
setup_blends[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
setup_blends[0].alphaBlendOp = VK_BLEND_OP_ADD;
} else {
blend_setup(setup_blends[0], regs.blend);
}
// Copy first blend state to all other targets
for (size_t index = 1; index < Maxwell::NumRenderTargets; index++) {
setup_blends[index] = setup_blends[0];
}
} else {
// Per-target blending
for (size_t index = 0; index < Maxwell::NumRenderTargets; index++) {
blend_setup(setup_blends[index], regs.blend_per_target[index]);
} }
blend_setup(regs.blend_per_target[index]);
} }
scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) { scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) {
cmdbuf.SetColorBlendEquationEXT(0, setup_blends); cmdbuf.SetColorBlendEquationEXT(0, setup_blends);
}); });

View file

@ -59,7 +59,7 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
case Tegra::Texture::TextureType::TextureCubeArray: case Tegra::Texture::TextureType::TextureCubeArray:
return Shader::TextureType::ColorArrayCube; return Shader::TextureType::ColorArrayCube;
default: default:
LOG_ERROR(Shader, "Invalid texture_type={}, falling back to texture_type={}", static_cast<int>(entry.texture_type.Value()), Shader::TextureType::Color2D); LOG_ERROR(Shader, "Invalid texture_type={}. Falling back to texture_type={}", static_cast<int>(entry.texture_type.Value()), Shader::TextureType::Color2D);
return Shader::TextureType::Color2D; return Shader::TextureType::Color2D;
} }
} }

View file

@ -1,6 +0,0 @@
// 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"

View file

@ -810,21 +810,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (Settings::values.dyna_state.GetValue() == 0) { if (Settings::values.dyna_state.GetValue() == 0) {
must_emulate_scaled_formats = true; must_emulate_scaled_formats = true;
LOG_INFO(Render_Vulkan, "Dynamic state is disabled (dyna_state = 0), forcing scaled format emulation ON"); LOG_INFO(Render_Vulkan, "Extended dynamic state is fully disabled, scaled format emulation is ON");
// Disable dynamic state 1-3 and all extensions
RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
dynamic_state3_blending = false; dynamic_state3_blending = false;
dynamic_state3_enables = false; dynamic_state3_enables = false;
LOG_INFO(Render_Vulkan, "All dynamic state extensions and features have been disabled"); LOG_INFO(Render_Vulkan, "All dynamic state extensions and features have been disabled");
} else { } else {
must_emulate_scaled_formats = false; must_emulate_scaled_formats = false;
LOG_INFO(Render_Vulkan, "Dynamic state is enabled (dyna_state = 1-3), disabling scaled format emulation"); LOG_INFO(Render_Vulkan, "Extended dynamic state is enabled, scaled format emulation is OFF");
} }
logical = vk::Device::Create(physical, queue_cis, ExtensionListForVulkan(loaded_extensions), first_next, dld); logical = vk::Device::Create(physical, queue_cis, ExtensionListForVulkan(loaded_extensions), first_next, dld);

View file

@ -370,15 +370,18 @@ if (APPLE)
if (YUZU_USE_BUNDLED_MOLTENVK) if (YUZU_USE_BUNDLED_MOLTENVK)
set(MOLTENVK_PLATFORM "macOS") set(MOLTENVK_PLATFORM "macOS")
set(MOLTENVK_VERSION "v1.3.0") set(MOLTENVK_VERSION "v1.4.0")
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION}) download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
endif() endif()
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED) find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.") message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES
MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
elseif(WIN32) elseif(WIN32)
# compile as a win32 gui application instead of a console application # compile as a win32 gui application instead of a console application
target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate) target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate)
@ -447,4 +450,39 @@ if (YUZU_ROOM)
target_link_libraries(yuzu PRIVATE Qt6::Widgets) target_link_libraries(yuzu PRIVATE Qt6::Widgets)
endif() endif()
if (NOT MSVC AND (APPLE OR NOT YUZU_STATIC_BUILD))
# needed for vma
target_compile_options(yuzu PRIVATE
-Wno-conversion
-Wno-unused-variable
-Wno-unused-parameter
-Wno-missing-field-initializers)
endif()
## certain libraries need extra static libs to be linked ##
# I have no fucking clue why it ONLY has to be on yuzu
# yuzu_cmd works totally fine but not this??????????
if (YUZU_STATIC_BUILD AND MINGW)
macro(extra_libs)
foreach(lib ${ARGN})
find_library(${lib}_LIBRARY ${lib} REQUIRED)
target_link_libraries(yuzu PRIVATE ${${lib}_LIBRARY})
endforeach()
endmacro()
# I am constantly impressed at how ridiculously stupid the linker is
# NB: yes, we have to put them here twice. I have no idea why
# libtiff.a
extra_libs(tiff jbig bz2 lzma deflate jpeg tiff)
# libfreetype.a
extra_libs(freetype bz2 Lerc brotlidec brotlicommon freetype)
# libharfbuzz.a
extra_libs(harfbuzz graphite2)
extra_libs(wsock32 ws2_32 crypt32 mswsock wlanapi)
endif()
create_target_directory_groups(yuzu) create_target_directory_groups(yuzu)

View file

@ -75,9 +75,10 @@ void ConfigureDebug::SetConfiguration() {
ui->disable_loop_safety_checks->setChecked(Settings::values.disable_shader_loop_safety_checks.GetValue()); ui->disable_loop_safety_checks->setChecked(Settings::values.disable_shader_loop_safety_checks.GetValue());
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue()); ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue());
#ifdef YUZU_USE_QT_WEB_ENGINE
ui->disable_web_applet->setChecked(Settings::values.disable_web_applet.GetValue()); ui->disable_web_applet->setChecked(Settings::values.disable_web_applet.GetValue());
#else
#ifndef YUZU_USE_QT_WEB_ENGINE ui->disable_web_applet->setChecked(true);
ui->disable_web_applet->setVisible(false); ui->disable_web_applet->setVisible(false);
#endif #endif
} }

View file

@ -6,10 +6,11 @@
#if YUZU_ROOM #if YUZU_ROOM
#include "dedicated_room/yuzu_room.h" #include "dedicated_room/yuzu_room.h"
#include <common/detached_tasks.h>
#include <cstring> #include <cstring>
#endif #endif
#include <common/detached_tasks.h>
#ifdef __unix__ #ifdef __unix__
#include "qt_common/gui_settings.h" #include "qt_common/gui_settings.h"
#endif #endif

View file

@ -1,6 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// Qt on macOS doesn't define VMA shit
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
#undef VMA_IMPLEMENTATION
#endif
#include "common/fs/ryujinx_compat.h" #include "common/fs/ryujinx_compat.h"
#include "main_window.h" #include "main_window.h"
#include "network/network.h" #include "network/network.h"
@ -44,6 +49,7 @@
// Qt Stuff // // Qt Stuff //
#define QT_NO_OPENGL #define QT_NO_OPENGL
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
#include <QStyleHints> #include <QStyleHints>
#endif #endif
@ -263,7 +269,14 @@ using namespace Common::Literals;
#endif #endif
#ifdef QT_STATICPLUGIN #ifdef QT_STATICPLUGIN
#include <QtPlugin>
#if defined(_WIN32)
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#elif defined(__APPLE__)
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
#endif
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@ -4897,3 +4910,8 @@ void VolumeButton::ResetMultiplier() {
#ifdef main #ifdef main
#undef main #undef main
#endif #endif
#if !defined(QT_STATICPLUGIN) || defined(__APPLE__)
#define VMA_IMPLEMENTATION
#include "video_core/vulkan_common/vma.h"
#endif

View file

@ -56,3 +56,12 @@ if(WIN32)
endif() endif()
create_target_directory_groups(yuzu-cmd) create_target_directory_groups(yuzu-cmd)
# needed for vma
if (NOT MSVC)
target_compile_options(yuzu-cmd PRIVATE
-Wno-conversion
-Wno-unused-variable
-Wno-unused-parameter
-Wno-missing-field-initializers)
endif()

View file

@ -4,12 +4,10 @@
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <regex> #include <regex>
#include <string> #include <string>
#include <thread>
#include <fmt/ostream.h> #include <fmt/ostream.h>
@ -17,7 +15,6 @@
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
@ -453,3 +450,6 @@ int main(int argc, char** argv) {
detached_tasks.WaitForAllTasks(); detached_tasks.WaitForAllTasks();
return 0; return 0;
} }
#define VMA_IMPLEMENTATION
#include "video_core/vulkan_common/vma.h"

View file

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
add_executable(yuzu_room_standalone add_executable(yuzu_room_standalone
yuzu_room_standalone.cpp yuzu_room_standalone.cpp
) )
@ -9,3 +12,5 @@ target_link_libraries(yuzu_room_standalone PRIVATE yuzu-room)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
install(TARGETS yuzu_room_standalone RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") install(TARGETS yuzu_room_standalone RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif() endif()
create_target_directory_groups(yuzu_room_standalone)

View file

@ -1,14 +0,0 @@
#!/bin/sh
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
for i in dist/languages/*.ts; do
SRC=en_US
TARGET=`head -n1 $i | awk -F 'language="' '{split($2, a, "\""); print a[1]}'`
# requires fd
SOURCES=`fd . src/yuzu src/qt_common -tf -e ui -e cpp -e h -e plist`
lupdate -source-language $SRC -target-language $TARGET $SOURCES -ts /data/code/eden/$i
done

View file

@ -3,10 +3,7 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
SRC=en_US SOURCES=$(find src/yuzu src/qt_common -type f \( -name "*.ui" -o -name "*.cpp" -o -name "*.h" -o -name "*.plist" \))
TARGET=en_US
# requires fd # shellcheck disable=SC2086
SOURCES=`fd . src/yuzu src/qt_common -tf -e ui -e cpp -e h -e plist` lupdate -source-language en_US -target-language en_US $SOURCES -ts dist/languages/en.ts
lupdate -source-language $SRC -target-language $TARGET $SOURCES -ts dist/languages/en.ts

View file

@ -1,4 +1,4 @@
#!/bin/sh -e #!/bin/sh -ex
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
@ -8,20 +8,21 @@
#which png2icns || (which yay && yay libicns) || exit #which png2icns || (which yay && yay libicns) || exit
which magick || exit which magick || exit
EDEN_SVG_ICO="dist/dev.eden_emu.eden.svg" EDEN_BASE_SVG="dist/icon_variations/base.svg"
EALT_SVG_ICO="dist/eden_named.svg" EDEN_SMALL_SVG="dist/icon_variations/base_small.svg"
EDEN_NAMED_SVG="dist/icon_variations/base_named.svg"
magick -density 256x256 -background transparent $EDEN_SVG_ICO -define icon:auto-resize -colors 256 dist/eden.ico || exit magick -density 256x256 -background transparent $EDEN_SMALL_SVG -define icon:auto-resize -colors 256 dist/eden.ico || exit
convert -density 256x256 -resize 256x256 -background transparent $EDEN_SVG_ICO dist/yuzu.bmp || exit convert -density 256x256 -resize 256x256 -background transparent $EDEN_SMALL_SVG dist/yuzu.bmp || exit
magick -size 256x256 -background transparent $EDEN_SVG_ICO dist/qt_themes/default/icons/256x256/eden.png || exit magick -size 256x256 -background transparent $EDEN_BASE_SVG dist/qt_themes/default/icons/256x256/eden.png || exit
magick -size 256x256 -background transparent $EALT_SVG_ICO dist/qt_themes/default/icons/256x256/eden_named.png || exit magick -size 256x256 -background transparent $EDEN_NAMED_SVG dist/qt_themes/default/icons/256x256/eden_named.png || exit
magick dist/qt_themes/default/icons/256x256/eden.png -resize 256x256! dist/qt_themes/default/icons/256x256/eden.png || exit magick dist/qt_themes/default/icons/256x256/eden.png -resize 256x256! dist/qt_themes/default/icons/256x256/eden.png || exit
magick dist/qt_themes/default/icons/256x256/eden_named.png -resize 256x256! dist/qt_themes/default/icons/256x256/eden_named.png || exit magick dist/qt_themes/default/icons/256x256/eden_named.png -resize 256x256! dist/qt_themes/default/icons/256x256/eden_named.png || exit
# Now do more fancy things (like composition) # Now do more fancy things (like composition)
TMP_PNG="dist/eden-tmp.png" TMP_PNG="dist/eden-tmp.png"
magick -size 1024x1024 -background transparent $EDEN_SVG_ICO $TMP_PNG || exit magick -size 1024x1024 -background transparent $EDEN_BASE_SVG $TMP_PNG || exit
composite $TMP_PNG -gravity center -geometry 2048x2048+0+0 \ composite $TMP_PNG -gravity center -geometry 2048x2048+0+0 \
src/android/app/src/main/res/drawable/ic_icon_bg_orig.png \ src/android/app/src/main/res/drawable/ic_icon_bg_orig.png \
src/android/app/src/main/res/drawable/ic_launcher.png || exit src/android/app/src/main/res/drawable/ic_launcher.png || exit
@ -31,6 +32,6 @@ optipng -o7 src/android/app/src/main/res/drawable/ic_launcher.png
optipng -o7 dist/qt_themes/default/icons/256x256/eden_named.png optipng -o7 dist/qt_themes/default/icons/256x256/eden_named.png
optipng -o7 dist/qt_themes/default/icons/256x256/eden.png optipng -o7 dist/qt_themes/default/icons/256x256/eden.png
png2icns dist/eden.icns $TMP_PNG png2icns dist/eden.icns $TMP_PNG || echo 'non fatal'
cp dist/eden.icns dist/yuzu.icns cp dist/eden.icns dist/yuzu.icns
rm $TMP_PNG rm $TMP_PNG