diff --git a/.github/workflows/sources.yml b/.github/workflows/sources.yml new file mode 100644 index 0000000000..8e98419cba --- /dev/null +++ b/.github/workflows/sources.yml @@ -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 diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml new file mode 100644 index 0000000000..07037c7f94 --- /dev/null +++ b/.github/workflows/translations.yml @@ -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 + diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae534444e..6f099834c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,11 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(PLATFORM_LINUX ON) endif() +# dumb heuristic to detect msys2 +if (CMAKE_COMMAND MATCHES "msys64") + set(PLATFORM_MSYS ON) +endif() + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CXX_CLANG ON) if (MSVC) @@ -85,6 +90,89 @@ if (PLATFORM_NETBSD) set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig") endif() +# MSYS2 utilities +if (PLATFORM_MSYS) + include(FixMsysPaths) + # really, really dumb heuristic to detect what environment we are in + macro(system var) + if (CMAKE_COMMAND MATCHES ${var}) + set(MSYSTEM ${var}) + endif() + endmacro() + + system(mingw64) + system(clang64) + system(clangarm64) + system(ucrt64) + + if (NOT DEFINED MSYSTEM) + set(MSYSTEM msys2) + endif() + + # we (generally) want to prioritize environment-specific binaries if possible + # some, like autoconf, are not present on environments besides msys2 though + set(CMAKE_PROGRAM_PATH C:/msys64/${MSYSTEM}/bin C:/msys64/usr/bin) + set(ENV{PKG_CONFIG_PATH} C:/msys64/${MSYSTEM}/lib/pkgconfig) +endif() + +# static stuff +option(YUZU_STATIC_BUILD "Use static libraries and executables if available" OFF) + +if (YUZU_STATIC_BUILD) + # lol + set(Boost_USE_STATIC_LIBS ON) + set(BUILD_SHARED_LIBS OFF) + + ## find .a libs first (static, usually) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + + ## some libraries define a Library::Name_static alternative ## + set(YUZU_STATIC_SUFFIX _static) + + ## some libraries use CMAKE_IMPORT_LIBRARY_SUFFIX e.g. Harfbuzz ## + set(CMAKE_IMPORT_LIBRARY_SUFFIX ".a") + + if (MINGW) + # simple hook to reject dynamic libs + function(find_library var) + # also skip previously-found libraries cuz... yaknow + if (${var}) + return() + endif() + + _find_library(${var} ${ARGN}) + if (${var}) + get_filename_component(lib_name "${${var}}" NAME) + if (lib_name MATCHES "dll\\.a$") + unset(${var} CACHE) + set(${var} "${var}-NOTFOUND" CACHE INTERNAL "" FORCE) + endif() + endif() + endfunction() + + # msys2 quazip does not build a static lib + set(QuaZip-Qt6_FORCE_BUNDLED ON) + + set(YUZU_USE_BUNDLED_FFMPEG ON) + set(YUZU_USE_BUNDLED_SDL2 ON) + + set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF) + elseif(APPLE) + # these libs do not properly provide static libs/let you do it with cmake + set(YUZU_USE_CPM ON) + + # IMPORTED_IMPLIB not set for imported target + # TODO(crueter): wtf + set(YUZU_USE_BUNDLED_FFMPEG ON) + set(YUZU_USE_EXTERNAL_SDL2 ON) + + set(fmt_FORCE_BUNDLED ON) + set(SPIRV-Tools_FORCE_BUNDLED ON) + set(SPIRV-Headers_FORCE_BUNDLED ON) + set(zstd_FORCE_BUNDLED ON) + endif() +endif() + # Detect current compilation architecture and create standard definitions # ======================================================================= @@ -219,11 +307,9 @@ endif() # On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion cmake_dependent_option(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF) -if (ENABLE_SDL2) - # TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system - cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF) - option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}") -endif() +# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system +cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Build SDL2 from external source" OFF "ENABLE_SDL2;NOT MSVC" OFF) +cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "ENABLE_SDL2" OFF) # qt stuff option(ENABLE_QT "Enable the Qt frontend" ON) @@ -244,10 +330,14 @@ option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if n # ffmpeg option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT}) -cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF) +cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF) # sirit -option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT}) +set(BUNDLED_SIRIT_DEFAULT OFF) +if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Debug|RelWithDebInfo") OR ANDROID)) + set(BUNDLED_SIRIT_DEFAULT ON) +endif() +option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT}) # Re-allow on FreeBSD once its on mainline ports cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR APPLE" OFF) @@ -284,6 +374,17 @@ if(USE_CCACHE) else() message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}") endif() + # Follow SCCache recommendations: + # + if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") + elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + endif() + endif() endif() # TODO(crueter): CI this? @@ -355,13 +456,6 @@ if (ANDROID) set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe endif() -# We need to downgrade debug info (/Zi -> /Z7) to use an older but more cacheable format -# See https://github.com/nanoant/CMakePCHCompiler/issues/21 -if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") -endif() - # Default to a Release build get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) @@ -582,6 +676,7 @@ else() find_package(stb MODULE) find_package(Opus 1.3 MODULE REQUIRED) + find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED MODULE) @@ -634,15 +729,15 @@ if (APPLE) # Umbrella framework for everything GUI-related find_library(COCOA_LIBRARY Cocoa) set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) - find_library(ICONV_LIBRARY iconv REQUIRED) - list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY}) + # find_library(ICONV_LIBRARY iconv REQUIRED) + # list(APPEND PLATFORM_LIBRARIES ${ICONV_LIBRARY}) elseif (WIN32) # Target Windows 10 add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00) - set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} winmm iphlpapi ws2_32 wlanapi) if (MINGW) # PSAPI is the Process Status API - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version crypt32 rpcrt4 gdi32 wldap32 mswsock) endif() elseif (PLATFORM_HAIKU) # Haiku is so special :) @@ -655,6 +750,8 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") set(PLATFORM_LIBRARIES rt) endif() +message(STATUS "Platform Libraries: ${PLATFORM_LIBRARIES}") + add_subdirectory(externals) # pass targets from externals diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 1c4a4874c6..78bab05030 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -542,10 +542,11 @@ function(AddCIPackage) PACKAGE EXTENSION MIN_VERSION - DISABLED_PLATFORMS ) - cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN}) + set(multiValueArgs DISABLED_PLATFORMS) + + cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT DEFINED PKG_ARGS_VERSION) message(FATAL_ERROR "[CPMUtil] VERSION is required") diff --git a/CMakeModules/FindOpus.cmake b/CMakeModules/FindOpus.cmake index 25a44fd870..5557cd1baf 100644 --- a/CMakeModules/FindOpus.cmake +++ b/CMakeModules/FindOpus.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -10,6 +13,10 @@ find_package_handle_standard_args(Opus VERSION_VAR OPUS_VERSION ) +if (PLATFORM_MSYS) + FixMsysPath(PkgConfig::OPUS) +endif() + if (Opus_FOUND AND NOT TARGET Opus::opus) add_library(Opus::opus ALIAS PkgConfig::OPUS) endif() diff --git a/CMakeModules/FindSPIRV-Tools.cmake b/CMakeModules/FindSPIRV-Tools.cmake index aef74df5d9..e0f9a88d54 100644 --- a/CMakeModules/FindSPIRV-Tools.cmake +++ b/CMakeModules/FindSPIRV-Tools.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -10,6 +13,10 @@ find_package_handle_standard_args(SPIRV-Tools VERSION_VAR SPIRV-Tools_VERSION ) +if (PLATFORM_MSYS) + FixMsysPath(PkgConfig::SPIRV-Tools) +endif() + if (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools) if (TARGET SPIRV-Tools) add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools) diff --git a/CMakeModules/Findenet.cmake b/CMakeModules/Findenet.cmake index 859a6f3866..d80e737ebb 100644 --- a/CMakeModules/Findenet.cmake +++ b/CMakeModules/Findenet.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 Alexandre Bouvier # # SPDX-License-Identifier: GPL-3.0-or-later @@ -11,6 +14,10 @@ find_package_handle_standard_args(enet VERSION_VAR ENET_VERSION ) +if (PLATFORM_MSYS) + FixMsysPath(PkgConfig::ENET) +endif() + if (enet_FOUND AND NOT TARGET enet::enet) add_library(enet::enet ALIAS PkgConfig::ENET) endif() diff --git a/CMakeModules/Findlibusb.cmake b/CMakeModules/Findlibusb.cmake index 0eadce9578..87b174c5b4 100644 --- a/CMakeModules/Findlibusb.cmake +++ b/CMakeModules/Findlibusb.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 Alexandre Bouvier # # SPDX-License-Identifier: GPL-3.0-or-later @@ -11,6 +14,10 @@ find_package_handle_standard_args(libusb VERSION_VAR LIBUSB_VERSION ) +if (PLATFORM_MSYS) + FixMsysPath(PkgConfig::LIBUSB) +endif() + if (libusb_FOUND AND NOT TARGET libusb::usb) add_library(libusb::usb ALIAS PkgConfig::LIBUSB) endif() diff --git a/CMakeModules/Findlz4.cmake b/CMakeModules/Findlz4.cmake index 7a9a02d4e8..af230166eb 100644 --- a/CMakeModules/Findlz4.cmake +++ b/CMakeModules/Findlz4.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2022 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -9,6 +12,11 @@ if (lz4_CONSIDERED_CONFIGS) else() find_package(PkgConfig QUIET) pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4) + + if (PLATFORM_MSYS) + FixMsysPath(PkgConfig::LZ4) + endif() + find_package_handle_standard_args(lz4 REQUIRED_VARS LZ4_LINK_LIBRARIES VERSION_VAR LZ4_VERSION diff --git a/CMakeModules/Findzstd.cmake b/CMakeModules/Findzstd.cmake index abcdbc2a3e..2afdb56a8c 100644 --- a/CMakeModules/Findzstd.cmake +++ b/CMakeModules/Findzstd.cmake @@ -6,22 +6,34 @@ include(FindPackageHandleStandardArgs) -find_package(PkgConfig QUIET) -pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) -find_package_handle_standard_args(zstd - REQUIRED_VARS ZSTD_LINK_LIBRARIES - VERSION_VAR ZSTD_VERSION -) +find_package(zstd QUIET CONFIG) +if (zstd_CONSIDERED_CONFIGS) + find_package_handle_standard_args(zstd CONFIG_MODE) +else() + find_package(PkgConfig QUIET) + pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) + find_package_handle_standard_args(zstd + REQUIRED_VARS ZSTD_LINK_LIBRARIES + VERSION_VAR ZSTD_VERSION + ) +endif() if (zstd_FOUND AND NOT TARGET zstd::zstd) - if (TARGET zstd::libzstd_shared) + if (TARGET zstd::libzstd_shared AND NOT YUZU_STATIC_BUILD) add_library(zstd::zstd ALIAS zstd::libzstd_shared) - add_library(zstd::libzstd ALIAS zstd::libzstd_shared) elseif (TARGET zstd::libzstd_static) add_library(zstd::zstd ALIAS zstd::libzstd_static) - add_library(zstd::libzstd ALIAS zstd::libzstd_static) else() add_library(zstd::zstd ALIAS PkgConfig::ZSTD) - add_library(zstd::libzstd ALIAS PkgConfig::ZSTD) + endif() +endif() + +get_target_property(ZSTD_TARGET zstd::zstd ALIASED_TARGET) + +if (NOT TARGET zstd::libzstd) + if (ZSTD_TARGET) + add_library(zstd::libzstd ALIAS ${ZSTD_TARGET}) + else() + add_library(zstd::libzstd ALIAS zstd::zstd) endif() endif() diff --git a/CMakeModules/FixMsysPaths.cmake b/CMakeModules/FixMsysPaths.cmake new file mode 100644 index 0000000000..81520ca3f7 --- /dev/null +++ b/CMakeModules/FixMsysPaths.cmake @@ -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() diff --git a/CMakeModules/MinGWClangCross.cmake b/CMakeModules/MinGWClangCross.cmake deleted file mode 100644 index 286a59a7ad..0000000000 --- a/CMakeModules/MinGWClangCross.cmake +++ /dev/null @@ -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() diff --git a/CMakeModules/MinGWCross.cmake b/CMakeModules/MinGWCross.cmake deleted file mode 100644 index 61464f7dae..0000000000 --- a/CMakeModules/MinGWCross.cmake +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-FileCopyrightText: 2018 tech4me -# 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() diff --git a/dist/eden.ico b/dist/eden.ico index f34d31d29e..4dc347af28 100644 Binary files a/dist/eden.ico and b/dist/eden.ico differ diff --git a/dist/icon_variations/README.md b/dist/icon_variations/README.md new file mode 100644 index 0000000000..7c444a7e04 --- /dev/null +++ b/dist/icon_variations/README.md @@ -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. diff --git a/dist/icon_variations/base_small.svg b/dist/icon_variations/base_small.svg new file mode 100644 index 0000000000..41db18afc1 --- /dev/null +++ b/dist/icon_variations/base_small.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + diff --git a/dist/yuzu.bmp b/dist/yuzu.bmp index 45de9b13eb..a548aaf7e6 100644 Binary files a/dist/yuzu.bmp and b/dist/yuzu.bmp differ diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 096760925f..51980dfffe 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -160,13 +160,6 @@ if (YUZU_USE_BUNDLED_SIRIT) AddJsonPackage(sirit-ci) else() AddJsonPackage(sirit) - # Change to old-but-more-cacheable debug info on Windows - if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) - get_target_property(sirit_opts sirit COMPILE_OPTIONS) - list(FILTER sirit_opts EXCLUDE REGEX "/Zi") - list(APPEND sirit_opts "/Z7") - set_target_properties(sirit PROPERTIES COMPILE_OPTIONS "${sirit_opts}") - endif() if(MSVC AND CXX_CLANG) target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument) endif() diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 995b25a2c7..58461d8934 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -25,18 +25,26 @@ if (UNIX AND NOT ANDROID) if (NOT APPLE) # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so if(PLATFORM_SUN) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - X11 - "/usr/lib/xorg/amd64/libdrm.so") + find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib) + if(LIBDRM_LIB) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + X11 + "${LIBDRM_LIB}") + message(STATUS "Found libdrm at: ${LIBDRM_LIB}") + else() + message(WARNING "libdrm not found, disabling libdrm support") + list(APPEND FFmpeg_HWACCEL_FLAGS + --disable-libdrm) + endif() else() pkg_check_modules(LIBDRM libdrm REQUIRED) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBDRM_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBDRM_INCLUDE_DIRS}) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-libdrm) endif() - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-libdrm) endif() if(LIBVA_FOUND) @@ -89,7 +97,7 @@ if (UNIX AND NOT ANDROID) endif(CUDA_FOUND) endif() - if (VDPAU_FOUND) + if (VDPAU_FOUND AND NOT APPLE) list(APPEND FFmpeg_HWACCEL_FLAGS --enable-vdpau --enable-hwaccel=h264_vdpau @@ -247,11 +255,19 @@ else() SYSTEM_THREADS) set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) + + # BSD make or Solaris make don't support ffmpeg make-j8 + if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD) + set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS}) + else() + set(FFmpeg_MAKE_ARGS "") + endif() + add_custom_command( OUTPUT ${FFmpeg_BUILD_LIBRARIES} COMMAND - make -j${SYSTEM_THREADS} + make ${FFmpeg_MAKE_ARGS} WORKING_DIRECTORY ${FFmpeg_BUILD_DIR} ) diff --git a/externals/ffmpeg/cpmfile.json b/externals/ffmpeg/cpmfile.json index 6337e083a9..9f7f0bea68 100644 --- a/externals/ffmpeg/cpmfile.json +++ b/externals/ffmpeg/cpmfile.json @@ -15,8 +15,7 @@ "disabled_platforms": [ "freebsd-amd64", "solaris-amd64", - "openbsd-amd64", - "macos-universal" + "openbsd-amd64" ] } } diff --git a/externals/nx_tzdb/cpmfile.json b/externals/nx_tzdb/cpmfile.json index 00507a85e3..908201564f 100644 --- a/externals/nx_tzdb/cpmfile.json +++ b/externals/nx_tzdb/cpmfile.json @@ -5,7 +5,7 @@ "git_host": "git.crueter.xyz", "artifact": "%VERSION%.tar.gz", "tag": "%VERSION%", - "hash": "87abb2aeca716d5d77b05317086dbc2f8acfc2f3f76ce4778345ee3df19973e6cd8ecbf16cfab5ad94c9636a6c44fd3588f9aadd3cba89403cfd56c8bec645c5", - "version": "091025" + "hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6", + "version": "121125" } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c25229cb40..5387de6191 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,7 +35,6 @@ if (MSVC AND NOT CXX_CLANG) # /W4 - Level 4 warnings # /MP - Multi-threaded compilation - # /Zi - Output debugging information # /Zm - Specifies the precompiled header memory allocation limit # /Zo - Enhanced debug info for optimized builds # /permissive- - Enables stricter C++ standards conformance checks @@ -98,11 +97,6 @@ if (MSVC AND NOT CXX_CLANG) ) endif() - if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - endif() - if (ARCHITECTURE_x86_64) add_compile_options(/QIntel-jcc-erratum) endif() @@ -176,16 +170,28 @@ else() add_compile_definitions(_FILE_OFFSET_BITS=64) endif() + if (YUZU_STATIC_BUILD) + add_compile_definitions(QT_STATICPLUGIN) + + # macos doesn't even let you make static executables... wtf? + if (NOT APPLE) + add_compile_options(-static) + if (YUZU_STATIC_BUILD) + # yuzu-cmd requires us to explicitly link libpthread, libgcc, and libstdc++ as static + # At a guess, it's probably because Qt handles the Qt executable for us, whereas this does not + add_link_options(-static -lpthread) + add_link_options(-static-libgcc -static-libstdc++) + endif() + endif() + endif() + if (MINGW) add_compile_definitions(MINGW_HAS_SECURE_API) + # Only windows has this requirement, thanks windows - if (WIN32) + if (WIN32 AND ARCHITECTURE_x86_64) add_compile_options("-msse4.1") endif() - if (MINGW_STATIC_BUILD) - add_compile_definitions(QT_STATICPLUGIN) - add_compile_options("-static") - endif() endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt index 8fcc6a055c..0ba8519f92 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt @@ -16,11 +16,15 @@ import java.io.FileOutputStream import java.security.KeyStore import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager +import android.content.res.Configuration +import android.os.LocaleList +import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.PowerStateUpdater +import java.util.Locale fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir @@ -73,5 +77,38 @@ class YuzuApplication : Application() { val appContext: Context get() = application.applicationContext + + private val LANGUAGE_CODES = arrayOf( + "system", "en", "es", "fr", "de", "it", "pt", "pt-BR", "ru", "ja", "ko", + "zh-CN", "zh-TW", "pl", "cs", "nb", "hu", "uk", "vi", "id", "ar", "ckb", "fa", "he", "sr" + ) + + fun applyLanguage(context: Context): Context { + val languageIndex = IntSetting.APP_LANGUAGE.getInt() + val langCode = if (languageIndex in LANGUAGE_CODES.indices) { + LANGUAGE_CODES[languageIndex] + } else { + "system" + } + + if (langCode == "system") { + return context + } + + val locale = when { + langCode.contains("-") -> { + val parts = langCode.split("-") + Locale.Builder().setLanguage(parts[0]).setRegion(parts[1]).build() + } + else -> Locale.Builder().setLanguage(langCode).build() + } + + Locale.setDefault(locale) + + val config = Configuration(context.resources.configuration) + config.setLocales(LocaleList(locale)) + + return context.createConfigurationContext(config) + } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 8079e9b782..58598ccdc4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -86,6 +86,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { private var foregroundService: Intent? = null + override fun attachBaseContext(base: Context) { + super.attachBaseContext(YuzuApplication.applyLanguage(base)) + } + override fun onCreate(savedInstanceState: Bundle?) { Log.gameLaunched = true ThemeHelper.setTheme(this) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index d5556a337b..3bccc97607 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -32,6 +32,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { MAX_ANISOTROPY("max_anisotropy"), THEME("theme"), THEME_MODE("theme_mode"), + APP_LANGUAGE("app_language"), OVERLAY_SCALE("control_scale"), OVERLAY_OPACITY("control_opacity"), LOCK_DRAWER("lock_drawer"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 6dc5d66c7b..716d3aae56 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -667,10 +667,11 @@ abstract class SettingsItem( ) ) put( - SliderSetting( + SpinBoxSetting( IntSetting.CPU_TICKS, titleId = R.string.cpu_ticks, descriptionId = 0, + valueHint = R.string.cpu_ticks, min = 77, max = 65535 ) @@ -756,6 +757,15 @@ abstract class SettingsItem( titleId = R.string.enable_update_checks, ) ) + put( + SingleChoiceSetting( + IntSetting.APP_LANGUAGE, + titleId = R.string.app_language, + descriptionId = R.string.app_language_description, + choicesId = R.array.appLanguageNames, + valuesId = R.array.appLanguageValues + ) + ) put( SwitchSetting( BooleanSetting.RENDERER_DEBUG, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index 455b3b5ff1..dd932fcafb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later package org.yuzu.yuzu_emu.features.settings.ui +import android.content.Context +import org.yuzu.yuzu_emu.YuzuApplication import android.os.Bundle import android.view.View import android.view.ViewGroup.MarginLayoutParams @@ -24,6 +29,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment import org.yuzu.yuzu_emu.utils.* +import org.yuzu.yuzu_emu.utils.collect class SettingsActivity : AppCompatActivity() { private lateinit var binding: ActivitySettingsBinding @@ -32,6 +38,10 @@ class SettingsActivity : AppCompatActivity() { private val settingsViewModel: SettingsViewModel by viewModels() + override fun attachBaseContext(base: Context) { + super.attachBaseContext(YuzuApplication.applyLanguage(base)) + } + override fun onCreate(savedInstanceState: Bundle?) { ThemeHelper.setTheme(this) @@ -125,6 +135,16 @@ class SettingsActivity : AppCompatActivity() { NativeConfig.savePerGameConfig() NativeConfig.unloadPerGameConfig() } + + if (settingsViewModel.shouldRecreateForLanguageChange.value) { + settingsViewModel.setShouldRecreateForLanguageChange(false) + val relaunchIntent = packageManager?.getLaunchIntentForPackage(packageName) + if (relaunchIntent != null) { + relaunchIntent.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK or android.content.Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(relaunchIntent) + android.os.Process.killProcess(android.os.Process.myPid()) + } + } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt index bdc51b7070..71a3e54cb3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt @@ -425,6 +425,14 @@ class SettingsAdapter( position ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) + // reset language if detected + if (item.setting.key == "app_language") { + // recreate page apply language change instantly + fragment.requireActivity().recreate() + + settingsViewModel.setShouldRecreateForLanguageChange(true) + } + return true } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index 2a97f15892..51d0455fd5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt @@ -14,6 +14,9 @@ import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.MotionEvent +import android.os.Handler +import android.os.Looper import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment @@ -197,6 +200,54 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener updateValidity(newValue) } + fun attachRepeat(button: View, delta: Int) { + val handler = Handler(Looper.getMainLooper()) + var runnable: Runnable? = null + val initialDelay = 400L + val minDelay = 40L + val accelerationFactor = 0.75f + + button.setOnTouchListener { v, event -> + when (event.action) { + MotionEvent.ACTION_DOWN -> { + val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue + val newValue = (current + delta) + spinboxBinding.editValue.setText(newValue.toString()) + updateValidity(newValue) + + var delay = initialDelay + runnable = object : Runnable { + override fun run() { + val curr = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue + val next = curr + delta + spinboxBinding.editValue.setText(next.toString()) + updateValidity(next) + // accelerate + delay = (delay * accelerationFactor).toLong().coerceAtLeast(minDelay) + handler.postDelayed(this, delay) + } + } + handler.postDelayed(runnable!!, initialDelay) + true + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + if (runnable != null) { + handler.removeCallbacks(runnable!!) + runnable = null + } + v.performClick() + true + } + + else -> false + } + } + } + + attachRepeat(spinboxBinding.buttonDecrement, -1) + attachRepeat(spinboxBinding.buttonIncrement, 1) + spinboxBinding.editValue.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} @@ -336,6 +387,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener .show() } scSetting.setSelectedValue(value) + + if (scSetting.setting.key == "app_language") { + settingsViewModel.setShouldRecreateForLanguageChange(true) + // recreate page apply language change instantly + requireActivity().recreate() + } } is StringSingleChoiceSetting -> { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 8a0bea158e..b495206bb2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -1030,8 +1030,10 @@ class SettingsFragmentPresenter( override fun reset() = IntSetting.THEME.setInt(defaultValue) } + add(HeaderSetting(R.string.app_settings)) + add(IntSetting.APP_LANGUAGE.key) + if (NativeLibrary.isUpdateCheckerEnabled()) { - add(HeaderSetting(R.string.app_settings)) add(BooleanSetting.ENABLE_UPDATE_CHECKS.key) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt index fbdca04e9c..d47e33244e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -54,6 +57,8 @@ class SettingsViewModel : ViewModel() { private val _shouldShowResetInputDialog = MutableStateFlow(false) val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow() + private val _shouldRecreateForLanguageChange = MutableStateFlow(false) + val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow() fun setShouldRecreate(value: Boolean) { _shouldRecreate.value = value } @@ -103,6 +108,10 @@ class SettingsViewModel : ViewModel() { _shouldShowResetInputDialog.value = value } + fun setShouldRecreateForLanguageChange(value: Boolean) { + _shouldRecreateForLanguageChange.value = value + } + fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage = try { InputHandler.registeredControllers[currentDevice] diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 126d85d715..da790a4fc4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -4,6 +4,7 @@ package org.yuzu.yuzu_emu.ui.main import android.content.Intent +import android.content.Context import android.net.Uri import android.os.Bundle import android.view.View @@ -53,6 +54,7 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity import kotlin.text.compareTo import androidx.core.net.toUri import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting +import org.yuzu.yuzu_emu.YuzuApplication class MainActivity : AppCompatActivity(), ThemeProvider { private lateinit var binding: ActivityMainBinding @@ -68,6 +70,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private val CHECKED_DECRYPTION = "CheckedDecryption" private var checkedDecryption = false + override fun attachBaseContext(base: Context) { + super.attachBaseContext(YuzuApplication.applyLanguage(base)) + } + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 53fdab8b4a..8a46a22df1 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -62,6 +62,7 @@ namespace AndroidSettings { Settings::Setting theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; Settings::Setting black_backgrounds{linkage, false, "black_backgrounds", Settings::Category::Android}; + Settings::Setting app_language{linkage, 0, "app_language", Settings::Category::Android}; Settings::Setting enable_update_checks{linkage, true, "enable_update_checks", Settings::Category::Android}; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index eebc4d5841..1350bccf2e 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" #include #include diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 3cd1e1d0ab..12dec24219 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -391,6 +391,61 @@ 2 + + @string/app_language_system + @string/app_language_english + @string/app_language_spanish + @string/app_language_french + @string/app_language_german + @string/app_language_italian + @string/app_language_portuguese + @string/app_language_brazilian_portuguese + @string/app_language_russian + @string/app_language_japanese + @string/app_language_korean + @string/app_language_simplified_chinese + @string/app_language_traditional_chinese + @string/app_language_polish + @string/app_language_czech + @string/app_language_norwegian + @string/app_language_hungarian + @string/app_language_ukrainian + @string/app_language_vietnamese + @string/app_language_indonesian + @string/app_language_arabic + @string/app_language_central_kurdish + @string/app_language_persian + @string/app_language_hebrew + @string/app_language_serbian + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + + @string/auto @string/oboe diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 03f546333a..fb80eaf053 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1028,6 +1028,35 @@ Black backgrounds When using the dark theme, apply black backgrounds. + + App Language + Change the language of the app interface + Follow System + English + Español + Français + Deutsch + Italiano + Português + Português do Brasil + Русский + 日本語 + 한국어 + 简体中文 + 繁體中文 + Polski + Čeština + Norsk bokmål + Magyar + Українська + Tiếng Việt + Bahasa Indonesia + العربية + کوردیی ناوەندی + فارسی + עברית + Српски + Theme Color Eden (Default) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b07778be28..999b380595 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -252,7 +252,7 @@ if(CXX_CLANG) endif() 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() target_link_libraries(common PUBLIC Boost::headers) endif() diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index 9bf6f2f81c..c4cd549893 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -103,46 +106,60 @@ template <> #else +// Some architectures lack u128, there is no definitive way to check them all without even more macro magic +// so let's just... do this; add your favourite arches once they get u128 support :) +#if (defined(__clang__) || defined(__GNUC__)) && (defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)) +using RealU128 = unsigned __int128; +# define SYNC_VAL_COMPARE_AND_SWAP(p, e, v) __sync_val_compare_and_swap(p, e, v) +# define SYNC_BOOL_COMPARE_AND_SWAP(p, e, v) __sync_bool_compare_and_swap(p, e, v) +# define U128_ZERO_INIT 0 +#else +using RealU128 = u128; +# define SYNC_VAL_COMPARE_AND_SWAP(p, e, v) ((*p == e) ? *p = v : *p) +# define SYNC_BOOL_COMPARE_AND_SWAP(p, e, v) ((*p == e) ? (void)(*p = v) : (void)0), true +# define U128_ZERO_INIT {} +#endif + template [[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected) { - return __sync_bool_compare_and_swap(pointer, expected, value); + return SYNC_BOOL_COMPARE_AND_SWAP(pointer, expected, value); } [[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected) { - unsigned __int128 value_a; - unsigned __int128 expected_a; + RealU128 value_a; + RealU128 expected_a; std::memcpy(&value_a, value.data(), sizeof(u128)); std::memcpy(&expected_a, expected.data(), sizeof(u128)); - return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); + return SYNC_BOOL_COMPARE_AND_SWAP((RealU128*)pointer, expected_a, value_a); } template [[nodiscard]] inline bool AtomicCompareAndSwap(T* pointer, T value, T expected, T& actual) { - actual = __sync_val_compare_and_swap(pointer, expected, value); + actual = SYNC_VAL_COMPARE_AND_SWAP(pointer, expected, value); return actual == expected; } -[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected, - u128& actual) { - unsigned __int128 value_a; - unsigned __int128 expected_a; - unsigned __int128 actual_a; +[[nodiscard]] inline bool AtomicCompareAndSwap(u64* pointer, u128 value, u128 expected, u128& actual) { + RealU128 value_a; + RealU128 expected_a; + RealU128 actual_a; std::memcpy(&value_a, value.data(), sizeof(u128)); std::memcpy(&expected_a, expected.data(), sizeof(u128)); - actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); + actual_a = SYNC_VAL_COMPARE_AND_SWAP((RealU128*)pointer, expected_a, value_a); std::memcpy(actual.data(), &actual_a, sizeof(u128)); return actual_a == expected_a; } [[nodiscard]] inline u128 AtomicLoad128(u64* pointer) { - unsigned __int128 zeros_a = 0; - unsigned __int128 result_a = - __sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a); - + RealU128 zeros_a = U128_ZERO_INIT; + RealU128 result_a = SYNC_VAL_COMPARE_AND_SWAP((RealU128*)pointer, zeros_a, zeros_a); u128 result; std::memcpy(result.data(), &result_a, sizeof(u128)); return result; } +#undef U128_ZERO_INIT +#undef SYNC_VAL_COMPARE_AND_SWAP +#undef SYNC_BOOL_COMPARE_AND_SWAP #endif diff --git a/src/common/logging/formatter.h b/src/common/logging/formatter.h index 07efba9c27..343174a0c7 100644 --- a/src/common/logging/formatter.h +++ b/src/common/logging/formatter.h @@ -1,11 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include - #include +#include "common/swap.h" // adapted from https://github.com/fmtlib/fmt/issues/2704 // a generic formatter for enum classes @@ -20,3 +23,14 @@ struct fmt::formatter, char>> } }; #endif + +template +struct fmt::formatter> { + constexpr auto parse(format_parse_context& ctx) { + return ctx.begin(); + } + template + auto format(const SwapStructT& reg, FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "{}", T(reg)); + } +}; diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 6800c20f69..56b65c527c 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -359,6 +359,9 @@ void RestoreGlobalState(bool is_powered_on) { for (const auto& reset : values.linkage.restore_functions) { reset(); } + + // Reset per-game flags + values.use_squashed_iterated_blend = false; } static bool configuring_global = true; diff --git a/src/common/settings.h b/src/common/settings.h index 360a49c6c6..2e16e4bc59 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -759,6 +759,9 @@ struct Values { // Add-Ons std::map> disabled_addons; + + // Per-game overrides + bool use_squashed_iterated_blend; }; extern Values values; diff --git a/src/common/swap.h b/src/common/swap.h index fde343e452..1cf8a6ba39 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2012 PPSSPP Project // SPDX-FileCopyrightText: 2012 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -17,7 +20,17 @@ namespace Common { -#ifdef _MSC_VER +#if defined(__Bitrig__) || defined(__OpenBSD__) +// We'll redefine swap16, swap32, swap64 as inline functions +// but OpenBSD is like "wow I bring my own stuff" +// It would be nice if we could use them without C++ namespace shenanigans +// But alas :) +#undef swap16 +#undef swap32 +#undef swap64 +#endif + +#if defined(_MSC_VER) [[nodiscard]] inline u16 swap16(u16 data) noexcept { return _byteswap_ushort(data); } @@ -28,12 +41,6 @@ namespace Common { return _byteswap_uint64(data); } #elif defined(__clang__) || defined(__GNUC__) -#if defined(__Bitrig__) || defined(__OpenBSD__) -// redefine swap16, swap32, swap64 as inline functions -#undef swap16 -#undef swap32 -#undef swap64 -#endif [[nodiscard]] inline u16 swap16(u16 data) noexcept { return __builtin_bswap16(data); } @@ -44,7 +51,9 @@ namespace Common { return __builtin_bswap64(data); } #else -// Generic implementation. +// Generic implementation - compiler will optimise these into their respective +// __builtin_byteswapXX() and such; if not, the compiler is stupid and we probably +// have bigger problems to worry about :) [[nodiscard]] inline u16 swap16(u16 data) noexcept { return (data >> 8) | (data << 8); } @@ -62,33 +71,27 @@ namespace Common { [[nodiscard]] inline float swapf(float f) noexcept { static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t."); - u32 value; std::memcpy(&value, &f, sizeof(u32)); - value = swap32(value); std::memcpy(&f, &value, sizeof(u32)); - return f; } [[nodiscard]] inline double swapd(double f) noexcept { static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t."); - u64 value; std::memcpy(&value, &f, sizeof(u64)); - value = swap64(value); std::memcpy(&f, &value, sizeof(u64)); - return f; } } // Namespace Common template -struct swap_struct_t { - using swapped_t = swap_struct_t; +struct SwapStructT { + using SwappedT = SwapStructT; protected: T value; @@ -101,137 +104,137 @@ public: T swap() const { return swap(value); } - swap_struct_t() = default; - swap_struct_t(const T& v) : value(swap(v)) {} + SwapStructT() = default; + SwapStructT(const T& v) : value(swap(v)) {} template - swapped_t& operator=(const S& source) { - value = swap(static_cast(source)); + SwappedT& operator=(const S& source) { + value = swap(T(source)); return *this; } operator s8() const { - return static_cast(swap()); + return s8(swap()); } operator u8() const { - return static_cast(swap()); + return u8(swap()); } operator s16() const { - return static_cast(swap()); + return s16(swap()); } operator u16() const { - return static_cast(swap()); + return u16(swap()); } operator s32() const { - return static_cast(swap()); + return s32(swap()); } operator u32() const { - return static_cast(swap()); + return u32(swap()); } operator s64() const { - return static_cast(swap()); + return s64(swap()); } operator u64() const { - return static_cast(swap()); + return u64(swap()); } operator float() const { - return static_cast(swap()); + return float(swap()); } operator double() const { - return static_cast(swap()); + return double(swap()); } // +v - swapped_t operator+() const { + SwappedT operator+() const { return +swap(); } // -v - swapped_t operator-() const { + SwappedT operator-() const { return -swap(); } // v / 5 - swapped_t operator/(const swapped_t& i) const { + SwappedT operator/(const SwappedT& i) const { return swap() / i.swap(); } template - swapped_t operator/(const S& i) const { + SwappedT operator/(const S& i) const { return swap() / i; } // v * 5 - swapped_t operator*(const swapped_t& i) const { + SwappedT operator*(const SwappedT& i) const { return swap() * i.swap(); } template - swapped_t operator*(const S& i) const { + SwappedT operator*(const S& i) const { return swap() * i; } // v + 5 - swapped_t operator+(const swapped_t& i) const { + SwappedT operator+(const SwappedT& i) const { return swap() + i.swap(); } template - swapped_t operator+(const S& i) const { - return swap() + static_cast(i); + SwappedT operator+(const S& i) const { + return swap() + T(i); } // v - 5 - swapped_t operator-(const swapped_t& i) const { + SwappedT operator-(const SwappedT& i) const { return swap() - i.swap(); } template - swapped_t operator-(const S& i) const { - return swap() - static_cast(i); + SwappedT operator-(const S& i) const { + return swap() - T(i); } // v += 5 - swapped_t& operator+=(const swapped_t& i) { + SwappedT& operator+=(const SwappedT& i) { value = swap(swap() + i.swap()); return *this; } template - swapped_t& operator+=(const S& i) { - value = swap(swap() + static_cast(i)); + SwappedT& operator+=(const S& i) { + value = swap(swap() + T(i)); return *this; } // v -= 5 - swapped_t& operator-=(const swapped_t& i) { + SwappedT& operator-=(const SwappedT& i) { value = swap(swap() - i.swap()); return *this; } template - swapped_t& operator-=(const S& i) { - value = swap(swap() - static_cast(i)); + SwappedT& operator-=(const S& i) { + value = swap(swap() - T(i)); return *this; } // ++v - swapped_t& operator++() { + SwappedT& operator++() { value = swap(swap() + 1); return *this; } // --v - swapped_t& operator--() { + SwappedT& operator--() { value = swap(swap() - 1); return *this; } // v++ - swapped_t operator++(int) { - swapped_t old = *this; + SwappedT operator++(int) { + SwappedT old = *this; value = swap(swap() + 1); return old; } // v-- - swapped_t operator--(int) { - swapped_t old = *this; + SwappedT operator--(int) { + SwappedT old = *this; value = swap(swap() - 1); return old; } // Comparison // v == i - bool operator==(const swapped_t& i) const { + bool operator==(const SwappedT& i) const { return swap() == i.swap(); } template @@ -240,7 +243,7 @@ public: } // v != i - bool operator!=(const swapped_t& i) const { + bool operator!=(const SwappedT& i) const { return swap() != i.swap(); } template @@ -249,7 +252,7 @@ public: } // v > i - bool operator>(const swapped_t& i) const { + bool operator>(const SwappedT& i) const { return swap() > i.swap(); } template @@ -258,7 +261,7 @@ public: } // v < i - bool operator<(const swapped_t& i) const { + bool operator<(const SwappedT& i) const { return swap() < i.swap(); } template @@ -267,7 +270,7 @@ public: } // v >= i - bool operator>=(const swapped_t& i) const { + bool operator>=(const SwappedT& i) const { return swap() >= i.swap(); } template @@ -276,7 +279,7 @@ public: } // v <= i - bool operator<=(const swapped_t& i) const { + bool operator<=(const SwappedT& i) const { return swap() <= i.swap(); } template @@ -285,82 +288,82 @@ public: } // logical - swapped_t operator!() const { + SwappedT operator!() const { return !swap(); } // bitmath - swapped_t operator~() const { + SwappedT operator~() const { return ~swap(); } - swapped_t operator&(const swapped_t& b) const { + SwappedT operator&(const SwappedT& b) const { return swap() & b.swap(); } template - swapped_t operator&(const S& b) const { + SwappedT operator&(const S& b) const { return swap() & b; } - swapped_t& operator&=(const swapped_t& b) { + SwappedT& operator&=(const SwappedT& b) { value = swap(swap() & b.swap()); return *this; } template - swapped_t& operator&=(const S b) { + SwappedT& operator&=(const S b) { value = swap(swap() & b); return *this; } - swapped_t operator|(const swapped_t& b) const { + SwappedT operator|(const SwappedT& b) const { return swap() | b.swap(); } template - swapped_t operator|(const S& b) const { + SwappedT operator|(const S& b) const { return swap() | b; } - swapped_t& operator|=(const swapped_t& b) { + SwappedT& operator|=(const SwappedT& b) { value = swap(swap() | b.swap()); return *this; } template - swapped_t& operator|=(const S& b) { + SwappedT& operator|=(const S& b) { value = swap(swap() | b); return *this; } - swapped_t operator^(const swapped_t& b) const { + SwappedT operator^(const SwappedT& b) const { return swap() ^ b.swap(); } template - swapped_t operator^(const S& b) const { + SwappedT operator^(const S& b) const { return swap() ^ b; } - swapped_t& operator^=(const swapped_t& b) { + SwappedT& operator^=(const SwappedT& b) { value = swap(swap() ^ b.swap()); return *this; } template - swapped_t& operator^=(const S& b) { + SwappedT& operator^=(const S& b) { value = swap(swap() ^ b); return *this; } template - swapped_t operator<<(const S& b) const { + SwappedT operator<<(const S& b) const { return swap() << b; } template - swapped_t& operator<<=(const S& b) const { + SwappedT& operator<<=(const S& b) const { value = swap(swap() << b); return *this; } template - swapped_t operator>>(const S& b) const { + SwappedT operator>>(const S& b) const { return swap() >> b; } template - swapped_t& operator>>=(const S& b) const { + SwappedT& operator>>=(const S& b) const { value = swap(swap() >> b); return *this; } @@ -370,167 +373,167 @@ public: // Arithmetic template - friend S operator+(const S& p, const swapped_t v); + friend S operator+(const S& p, const SwappedT v); template - friend S operator-(const S& p, const swapped_t v); + friend S operator-(const S& p, const SwappedT v); template - friend S operator/(const S& p, const swapped_t v); + friend S operator/(const S& p, const SwappedT v); template - friend S operator*(const S& p, const swapped_t v); + friend S operator*(const S& p, const SwappedT v); template - friend S operator%(const S& p, const swapped_t v); + friend S operator%(const S& p, const SwappedT v); // Arithmetic + assignments template - friend S operator+=(const S& p, const swapped_t v); + friend S operator+=(const S& p, const SwappedT v); template - friend S operator-=(const S& p, const swapped_t v); + friend S operator-=(const S& p, const SwappedT v); // Bitmath template - friend S operator&(const S& p, const swapped_t v); + friend S operator&(const S& p, const SwappedT v); // Comparison template - friend bool operator<(const S& p, const swapped_t v); + friend bool operator<(const S& p, const SwappedT v); template - friend bool operator>(const S& p, const swapped_t v); + friend bool operator>(const S& p, const SwappedT v); template - friend bool operator<=(const S& p, const swapped_t v); + friend bool operator<=(const S& p, const SwappedT v); template - friend bool operator>=(const S& p, const swapped_t v); + friend bool operator>=(const S& p, const SwappedT v); template - friend bool operator!=(const S& p, const swapped_t v); + friend bool operator!=(const S& p, const SwappedT v); template - friend bool operator==(const S& p, const swapped_t v); + friend bool operator==(const S& p, const SwappedT v); }; // Arithmetic template -S operator+(const S& i, const swap_struct_t v) { +S operator+(const S& i, const SwapStructT v) { return i + v.swap(); } template -S operator-(const S& i, const swap_struct_t v) { +S operator-(const S& i, const SwapStructT v) { return i - v.swap(); } template -S operator/(const S& i, const swap_struct_t v) { +S operator/(const S& i, const SwapStructT v) { return i / v.swap(); } template -S operator*(const S& i, const swap_struct_t v) { +S operator*(const S& i, const SwapStructT v) { return i * v.swap(); } template -S operator%(const S& i, const swap_struct_t v) { +S operator%(const S& i, const SwapStructT v) { return i % v.swap(); } // Arithmetic + assignments template -S& operator+=(S& i, const swap_struct_t v) { +S& operator+=(S& i, const SwapStructT v) { i += v.swap(); return i; } template -S& operator-=(S& i, const swap_struct_t v) { +S& operator-=(S& i, const SwapStructT v) { i -= v.swap(); return i; } // Logical template -S operator&(const S& i, const swap_struct_t v) { +S operator&(const S& i, const SwapStructT v) { return i & v.swap(); } // Comparison template -bool operator<(const S& p, const swap_struct_t v) { +bool operator<(const S& p, const SwapStructT v) { return p < v.swap(); } template -bool operator>(const S& p, const swap_struct_t v) { +bool operator>(const S& p, const SwapStructT v) { return p > v.swap(); } template -bool operator<=(const S& p, const swap_struct_t v) { +bool operator<=(const S& p, const SwapStructT v) { return p <= v.swap(); } template -bool operator>=(const S& p, const swap_struct_t v) { +bool operator>=(const S& p, const SwapStructT v) { return p >= v.swap(); } template -bool operator!=(const S& p, const swap_struct_t v) { +bool operator!=(const S& p, const SwapStructT v) { return p != v.swap(); } template -bool operator==(const S& p, const swap_struct_t v) { +bool operator==(const S& p, const SwapStructT v) { return p == v.swap(); } template -struct swap_64_t { +struct Swap64T { static T swap(T x) { - return static_cast(Common::swap64(x)); + return T(Common::swap64(x)); } }; template -struct swap_32_t { +struct Swap32T { static T swap(T x) { - return static_cast(Common::swap32(x)); + return T(Common::swap32(x)); } }; template -struct swap_16_t { +struct Swap16T { static T swap(T x) { - return static_cast(Common::swap16(x)); + return T(Common::swap16(x)); } }; template -struct swap_float_t { +struct SwapFloatT { static T swap(T x) { - return static_cast(Common::swapf(x)); + return T(Common::swapf(x)); } }; template -struct swap_double_t { +struct SwapDoubleT { static T swap(T x) { - return static_cast(Common::swapd(x)); + return T(Common::swapd(x)); } }; template -struct swap_enum_t { +struct SwapEnumT { static_assert(std::is_enum_v); using base = std::underlying_type_t; public: - swap_enum_t() = default; - swap_enum_t(const T& v) : value(swap(v)) {} + SwapEnumT() = default; + SwapEnumT(const T& v) : value(swap(v)) {} - swap_enum_t& operator=(const T& v) { + SwapEnumT& operator=(const T& v) { value = swap(v); return *this; } @@ -540,22 +543,20 @@ public: } explicit operator base() const { - return static_cast(swap(value)); + return base(swap(value)); } protected: T value{}; - // clang-format off using swap_t = std::conditional_t< - std::is_same_v, swap_16_t, std::conditional_t< - std::is_same_v, swap_16_t, std::conditional_t< - std::is_same_v, swap_32_t, std::conditional_t< - std::is_same_v, swap_32_t, std::conditional_t< - std::is_same_v, swap_64_t, std::conditional_t< - std::is_same_v, swap_64_t, void>>>>>>; - // clang-format on + std::is_same_v, Swap16T, std::conditional_t< + std::is_same_v, Swap16T, std::conditional_t< + std::is_same_v, Swap32T, std::conditional_t< + std::is_same_v, Swap32T, std::conditional_t< + std::is_same_v, Swap64T, std::conditional_t< + std::is_same_v, Swap64T, void>>>>>>; static T swap(T x) { - return static_cast(swap_t::swap(static_cast(x))); + return T(swap_t::swap(base(x))); } }; @@ -581,17 +582,17 @@ struct AddEndian { template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> @@ -601,33 +602,33 @@ struct AddEndian { template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template <> struct AddEndian { - using type = swap_struct_t>; + using type = SwapStructT>; }; template struct AddEndian { static_assert(std::is_enum_v); - using type = swap_enum_t; + using type = SwapEnumT; }; // Alias LETag/BETag as KeepTag/SwapTag depending on the system diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 452e5f42e4..ad886b4300 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1199,10 +1199,10 @@ else() target_link_libraries(core PUBLIC Boost::headers) endif() -target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto MbedTLS::mbedtls) -if (MINGW) - target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi) -endif() +target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX}) +# if (MINGW) +# target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi) +# endif() if (ENABLE_WEB_SERVICE) target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE) diff --git a/src/core/core.cpp b/src/core/core.cpp index 7315f35e0c..6c321afdbb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -297,6 +297,9 @@ struct System::Impl { std::string vendor = gpu_core->Renderer().GetDeviceVendor(); LOG_INFO(Core, "GPU Vendor: {}", vendor); + // Reset all per-game flags + Settings::values.use_squashed_iterated_blend = false; + // Insert PC overrides here #ifdef ANDROID @@ -322,6 +325,13 @@ struct System::Impl { #endif + // Ninja Gaiden Ragebound + constexpr u64 ngr = 0x0100781020710000ULL; + + if (programId == ngr) { + LOG_INFO(Core, "Enabling game specifc override: use_squashed_iterated_blend"); + Settings::values.use_squashed_iterated_blend = true; + } } SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, @@ -425,6 +435,9 @@ struct System::Impl { void ShutdownMainProcess() { SetShuttingDown(true); + // Reset per-game flags + Settings::values.use_squashed_iterated_blend = false; + is_powered_on = false; exit_locked = false; exit_requested = false; diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp index 9786f5a99a..8246b3e88e 100644 --- a/src/core/hle/service/am/frontend/applet_web_browser.cpp +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp @@ -237,7 +237,6 @@ WebBrowser::~WebBrowser() = default; void WebBrowser::Initialize() { if (Settings::values.disable_web_applet) { - LOG_INFO(Service_AM, "Web Browser Applet disabled, skipping."); return; } @@ -305,6 +304,7 @@ void WebBrowser::ExecuteInteractive() { void WebBrowser::Execute() { if (Settings::values.disable_web_applet) { + LOG_WARNING(Service_AM, "(STUBBED) called, Web Browser Applet is disabled"); WebBrowserExit(WebExitReason::EndButtonPressed); return; } diff --git a/src/core/hle/service/am/frontend/applets.cpp b/src/core/hle/service/am/frontend/applets.cpp index bb69869ade..a25b7e3aa2 100644 --- a/src/core/hle/service/am/frontend/applets.cpp +++ b/src/core/hle/service/am/frontend/applets.cpp @@ -229,8 +229,7 @@ std::shared_ptr FrontendAppletHolder::GetApplet(std::shared_ptr< case AppletId::ProfileSelect: return std::make_shared(system, applet, mode, *frontend.profile_select); case AppletId::SoftwareKeyboard: - return std::make_shared(system, applet, mode, - *frontend.software_keyboard); + return std::make_shared(system, applet, mode, *frontend.software_keyboard); case AppletId::MiiEdit: return std::make_shared(system, applet, mode, *frontend.mii_edit); case AppletId::Web: @@ -244,9 +243,7 @@ std::shared_ptr FrontendAppletHolder::GetApplet(std::shared_ptr< case AppletId::NetConnect: return std::make_shared(system, applet, mode, *frontend.net_connect); default: - UNIMPLEMENTED_MSG( - "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", - static_cast(id)); + LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X}. Falling back to stub applet", static_cast(id)); return std::make_shared(system, applet, id, mode); } } diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 3e0658a1fb..e74168a5d5 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -4,9 +4,6 @@ # SPDX-FileCopyrightText: 2017 Citra Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - add_library(yuzu-room STATIC EXCLUDE_FROM_ALL yuzu_room.cpp yuzu_room.h @@ -19,7 +16,7 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(yuzu-room PRIVATE web_service) endif() -target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto MbedTLS::mbedtls) +target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX}) if (MSVC) target_link_libraries(yuzu-room PRIVATE getopt) endif() diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index 03532c3344..5f9506273f 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -81,11 +81,6 @@ if (MSVC) /bigobj # Increase number of sections in .obj files /DNOMINMAX) - if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") - endif() - if (CXX_CLANG) list(APPEND DYNARMIC_CXX_FLAGS -Qunused-arguments diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 4f19e00ee4..c385951318 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -81,14 +81,12 @@ add_library(shader_recompiler STATIC environment.h exception.h frontend/ir/abstract_syntax_list.h - frontend/ir/attribute.cpp frontend/ir/attribute.h frontend/ir/basic_block.cpp frontend/ir/basic_block.h frontend/ir/breadth_first_search.h frontend/ir/condition.cpp frontend/ir/condition.h - frontend/ir/flow_test.cpp frontend/ir/flow_test.h frontend/ir/ir_emitter.cpp frontend/ir/ir_emitter.h diff --git a/src/shader_recompiler/frontend/ir/attribute.cpp b/src/shader_recompiler/frontend/ir/attribute.cpp deleted file mode 100644 index 97f253602d..0000000000 --- a/src/shader_recompiler/frontend/ir/attribute.cpp +++ /dev/null @@ -1,459 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#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(attribute) - static_cast(Attribute::Generic0X)) / 4u; -} - -u32 GenericAttributeElement(Attribute attribute) { - if (!IsGeneric(attribute)) { - throw InvalidArgument("Attribute is not generic {}", attribute); - } - return static_cast(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("", static_cast(attribute)); -} - -} // namespace Shader::IR diff --git a/src/shader_recompiler/frontend/ir/attribute.h b/src/shader_recompiler/frontend/ir/attribute.h index 7a06713803..943c8d673f 100644 --- a/src/shader_recompiler/frontend/ir/attribute.h +++ b/src/shader_recompiler/frontend/ir/attribute.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -6,240 +9,261 @@ #include #include "common/common_types.h" +#include "shader_recompiler/exception.h" namespace Shader::IR { enum class Attribute : u64 { - PrimitiveId = 24, - Layer = 25, - ViewportIndex = 26, - PointSize = 27, - PositionX = 28, - PositionY = 29, - PositionZ = 30, - PositionW = 31, - Generic0X = 32, - Generic0Y = 33, - Generic0Z = 34, - Generic0W = 35, - Generic1X = 36, - Generic1Y = 37, - Generic1Z = 38, - Generic1W = 39, - Generic2X = 40, - Generic2Y = 41, - Generic2Z = 42, - Generic2W = 43, - Generic3X = 44, - Generic3Y = 45, - Generic3Z = 46, - Generic3W = 47, - Generic4X = 48, - Generic4Y = 49, - Generic4Z = 50, - Generic4W = 51, - Generic5X = 52, - Generic5Y = 53, - Generic5Z = 54, - Generic5W = 55, - Generic6X = 56, - Generic6Y = 57, - Generic6Z = 58, - Generic6W = 59, - Generic7X = 60, - Generic7Y = 61, - Generic7Z = 62, - Generic7W = 63, - Generic8X = 64, - Generic8Y = 65, - Generic8Z = 66, - Generic8W = 67, - Generic9X = 68, - Generic9Y = 69, - Generic9Z = 70, - Generic9W = 71, - Generic10X = 72, - Generic10Y = 73, - Generic10Z = 74, - Generic10W = 75, - Generic11X = 76, - Generic11Y = 77, - Generic11Z = 78, - Generic11W = 79, - Generic12X = 80, - Generic12Y = 81, - Generic12Z = 82, - Generic12W = 83, - Generic13X = 84, - Generic13Y = 85, - Generic13Z = 86, - Generic13W = 87, - Generic14X = 88, - Generic14Y = 89, - Generic14Z = 90, - Generic14W = 91, - Generic15X = 92, - Generic15Y = 93, - Generic15Z = 94, - Generic15W = 95, - Generic16X = 96, - Generic16Y = 97, - Generic16Z = 98, - Generic16W = 99, - Generic17X = 100, - Generic17Y = 101, - Generic17Z = 102, - Generic17W = 103, - Generic18X = 104, - Generic18Y = 105, - Generic18Z = 106, - Generic18W = 107, - Generic19X = 108, - Generic19Y = 109, - Generic19Z = 110, - Generic19W = 111, - Generic20X = 112, - Generic20Y = 113, - Generic20Z = 114, - Generic20W = 115, - Generic21X = 116, - Generic21Y = 117, - Generic21Z = 118, - Generic21W = 119, - Generic22X = 120, - Generic22Y = 121, - Generic22Z = 122, - Generic22W = 123, - Generic23X = 124, - Generic23Y = 125, - Generic23Z = 126, - Generic23W = 127, - Generic24X = 128, - Generic24Y = 129, - Generic24Z = 130, - Generic24W = 131, - Generic25X = 132, - Generic25Y = 133, - Generic25Z = 134, - Generic25W = 135, - Generic26X = 136, - Generic26Y = 137, - Generic26Z = 138, - Generic26W = 139, - Generic27X = 140, - Generic27Y = 141, - Generic27Z = 142, - Generic27W = 143, - Generic28X = 144, - Generic28Y = 145, - Generic28Z = 146, - Generic28W = 147, - Generic29X = 148, - Generic29Y = 149, - Generic29Z = 150, - Generic29W = 151, - Generic30X = 152, - Generic30Y = 153, - Generic30Z = 154, - Generic30W = 155, - Generic31X = 156, - Generic31Y = 157, - Generic31Z = 158, - Generic31W = 159, - ColorFrontDiffuseR = 160, - ColorFrontDiffuseG = 161, - ColorFrontDiffuseB = 162, - ColorFrontDiffuseA = 163, - ColorFrontSpecularR = 164, - ColorFrontSpecularG = 165, - ColorFrontSpecularB = 166, - ColorFrontSpecularA = 167, - ColorBackDiffuseR = 168, - ColorBackDiffuseG = 169, - ColorBackDiffuseB = 170, - ColorBackDiffuseA = 171, - ColorBackSpecularR = 172, - ColorBackSpecularG = 173, - ColorBackSpecularB = 174, - ColorBackSpecularA = 175, - ClipDistance0 = 176, - ClipDistance1 = 177, - ClipDistance2 = 178, - ClipDistance3 = 179, - ClipDistance4 = 180, - ClipDistance5 = 181, - ClipDistance6 = 182, - ClipDistance7 = 183, - PointSpriteS = 184, - PointSpriteT = 185, - FogCoordinate = 186, - TessellationEvaluationPointU = 188, - TessellationEvaluationPointV = 189, - InstanceId = 190, - VertexId = 191, - FixedFncTexture0S = 192, - FixedFncTexture0T = 193, - FixedFncTexture0R = 194, - FixedFncTexture0Q = 195, - FixedFncTexture1S = 196, - FixedFncTexture1T = 197, - FixedFncTexture1R = 198, - FixedFncTexture1Q = 199, - FixedFncTexture2S = 200, - FixedFncTexture2T = 201, - FixedFncTexture2R = 202, - FixedFncTexture2Q = 203, - FixedFncTexture3S = 204, - FixedFncTexture3T = 205, - FixedFncTexture3R = 206, - FixedFncTexture3Q = 207, - FixedFncTexture4S = 208, - FixedFncTexture4T = 209, - FixedFncTexture4R = 210, - FixedFncTexture4Q = 211, - FixedFncTexture5S = 212, - FixedFncTexture5T = 213, - FixedFncTexture5R = 214, - FixedFncTexture5Q = 215, - FixedFncTexture6S = 216, - FixedFncTexture6T = 217, - FixedFncTexture6R = 218, - FixedFncTexture6Q = 219, - FixedFncTexture7S = 220, - FixedFncTexture7T = 221, - FixedFncTexture7R = 222, - FixedFncTexture7Q = 223, - FixedFncTexture8S = 224, - FixedFncTexture8T = 225, - FixedFncTexture8R = 226, - FixedFncTexture8Q = 227, - FixedFncTexture9S = 228, - FixedFncTexture9T = 229, - FixedFncTexture9R = 230, - FixedFncTexture9Q = 231, - ViewportMask = 232, - FrontFace = 255, - - // Implementation attributes - BaseInstance = 256, - BaseVertex = 257, - DrawID = 258, +#define SRIR_ATTRIBUTE_LIST \ + SRIR_ATTRIBUTE_ELEM(PrimitiveId, 24) \ + SRIR_ATTRIBUTE_ELEM(Layer, 25) \ + SRIR_ATTRIBUTE_ELEM(ViewportIndex, 26) \ + SRIR_ATTRIBUTE_ELEM(PointSize, 27) \ + SRIR_ATTRIBUTE_ELEM(PositionX, 28) \ + SRIR_ATTRIBUTE_ELEM(PositionY, 29) \ + SRIR_ATTRIBUTE_ELEM(PositionZ, 30) \ + SRIR_ATTRIBUTE_ELEM(PositionW, 31) \ + SRIR_ATTRIBUTE_ELEM(Generic0X, 32) \ + SRIR_ATTRIBUTE_ELEM(Generic0Y, 33) \ + SRIR_ATTRIBUTE_ELEM(Generic0Z, 34) \ + SRIR_ATTRIBUTE_ELEM(Generic0W, 35) \ + SRIR_ATTRIBUTE_ELEM(Generic1X, 36) \ + SRIR_ATTRIBUTE_ELEM(Generic1Y, 37) \ + SRIR_ATTRIBUTE_ELEM(Generic1Z, 38) \ + SRIR_ATTRIBUTE_ELEM(Generic1W, 39) \ + SRIR_ATTRIBUTE_ELEM(Generic2X, 40) \ + SRIR_ATTRIBUTE_ELEM(Generic2Y, 41) \ + SRIR_ATTRIBUTE_ELEM(Generic2Z, 42) \ + SRIR_ATTRIBUTE_ELEM(Generic2W, 43) \ + SRIR_ATTRIBUTE_ELEM(Generic3X, 44) \ + SRIR_ATTRIBUTE_ELEM(Generic3Y, 45) \ + SRIR_ATTRIBUTE_ELEM(Generic3Z, 46) \ + SRIR_ATTRIBUTE_ELEM(Generic3W, 47) \ + SRIR_ATTRIBUTE_ELEM(Generic4X, 48) \ + SRIR_ATTRIBUTE_ELEM(Generic4Y, 49) \ + SRIR_ATTRIBUTE_ELEM(Generic4Z, 50) \ + SRIR_ATTRIBUTE_ELEM(Generic4W, 51) \ + SRIR_ATTRIBUTE_ELEM(Generic5X, 52) \ + SRIR_ATTRIBUTE_ELEM(Generic5Y, 53) \ + SRIR_ATTRIBUTE_ELEM(Generic5Z, 54) \ + SRIR_ATTRIBUTE_ELEM(Generic5W, 55) \ + SRIR_ATTRIBUTE_ELEM(Generic6X, 56) \ + SRIR_ATTRIBUTE_ELEM(Generic6Y, 57) \ + SRIR_ATTRIBUTE_ELEM(Generic6Z, 58) \ + SRIR_ATTRIBUTE_ELEM(Generic6W, 59) \ + SRIR_ATTRIBUTE_ELEM(Generic7X, 60) \ + SRIR_ATTRIBUTE_ELEM(Generic7Y, 61) \ + SRIR_ATTRIBUTE_ELEM(Generic7Z, 62) \ + SRIR_ATTRIBUTE_ELEM(Generic7W, 63) \ + SRIR_ATTRIBUTE_ELEM(Generic8X, 64) \ + SRIR_ATTRIBUTE_ELEM(Generic8Y, 65) \ + SRIR_ATTRIBUTE_ELEM(Generic8Z, 66) \ + SRIR_ATTRIBUTE_ELEM(Generic8W, 67) \ + SRIR_ATTRIBUTE_ELEM(Generic9X, 68) \ + SRIR_ATTRIBUTE_ELEM(Generic9Y, 69) \ + SRIR_ATTRIBUTE_ELEM(Generic9Z, 70) \ + SRIR_ATTRIBUTE_ELEM(Generic9W, 71) \ + SRIR_ATTRIBUTE_ELEM(Generic10X, 72) \ + SRIR_ATTRIBUTE_ELEM(Generic10Y, 73) \ + SRIR_ATTRIBUTE_ELEM(Generic10Z, 74) \ + SRIR_ATTRIBUTE_ELEM(Generic10W, 75) \ + SRIR_ATTRIBUTE_ELEM(Generic11X, 76) \ + SRIR_ATTRIBUTE_ELEM(Generic11Y, 77) \ + SRIR_ATTRIBUTE_ELEM(Generic11Z, 78) \ + SRIR_ATTRIBUTE_ELEM(Generic11W, 79) \ + SRIR_ATTRIBUTE_ELEM(Generic12X, 80) \ + SRIR_ATTRIBUTE_ELEM(Generic12Y, 81) \ + SRIR_ATTRIBUTE_ELEM(Generic12Z, 82) \ + SRIR_ATTRIBUTE_ELEM(Generic12W, 83) \ + SRIR_ATTRIBUTE_ELEM(Generic13X, 84) \ + SRIR_ATTRIBUTE_ELEM(Generic13Y, 85) \ + SRIR_ATTRIBUTE_ELEM(Generic13Z, 86) \ + SRIR_ATTRIBUTE_ELEM(Generic13W, 87) \ + SRIR_ATTRIBUTE_ELEM(Generic14X, 88) \ + SRIR_ATTRIBUTE_ELEM(Generic14Y, 89) \ + SRIR_ATTRIBUTE_ELEM(Generic14Z, 90) \ + SRIR_ATTRIBUTE_ELEM(Generic14W, 91) \ + SRIR_ATTRIBUTE_ELEM(Generic15X, 92) \ + SRIR_ATTRIBUTE_ELEM(Generic15Y, 93) \ + SRIR_ATTRIBUTE_ELEM(Generic15Z, 94) \ + SRIR_ATTRIBUTE_ELEM(Generic15W, 95) \ + SRIR_ATTRIBUTE_ELEM(Generic16X, 96) \ + SRIR_ATTRIBUTE_ELEM(Generic16Y, 97) \ + SRIR_ATTRIBUTE_ELEM(Generic16Z, 98) \ + SRIR_ATTRIBUTE_ELEM(Generic16W, 99) \ + SRIR_ATTRIBUTE_ELEM(Generic17X, 100) \ + SRIR_ATTRIBUTE_ELEM(Generic17Y, 101) \ + SRIR_ATTRIBUTE_ELEM(Generic17Z, 102) \ + SRIR_ATTRIBUTE_ELEM(Generic17W, 103) \ + SRIR_ATTRIBUTE_ELEM(Generic18X, 104) \ + SRIR_ATTRIBUTE_ELEM(Generic18Y, 105) \ + SRIR_ATTRIBUTE_ELEM(Generic18Z, 106) \ + SRIR_ATTRIBUTE_ELEM(Generic18W, 107) \ + SRIR_ATTRIBUTE_ELEM(Generic19X, 108) \ + SRIR_ATTRIBUTE_ELEM(Generic19Y, 109) \ + SRIR_ATTRIBUTE_ELEM(Generic19Z, 110) \ + SRIR_ATTRIBUTE_ELEM(Generic19W, 111) \ + SRIR_ATTRIBUTE_ELEM(Generic20X, 112) \ + SRIR_ATTRIBUTE_ELEM(Generic20Y, 113) \ + SRIR_ATTRIBUTE_ELEM(Generic20Z, 114) \ + SRIR_ATTRIBUTE_ELEM(Generic20W, 115) \ + SRIR_ATTRIBUTE_ELEM(Generic21X, 116) \ + SRIR_ATTRIBUTE_ELEM(Generic21Y, 117) \ + SRIR_ATTRIBUTE_ELEM(Generic21Z, 118) \ + SRIR_ATTRIBUTE_ELEM(Generic21W, 119) \ + SRIR_ATTRIBUTE_ELEM(Generic22X, 120) \ + SRIR_ATTRIBUTE_ELEM(Generic22Y, 121) \ + SRIR_ATTRIBUTE_ELEM(Generic22Z, 122) \ + SRIR_ATTRIBUTE_ELEM(Generic22W, 123) \ + SRIR_ATTRIBUTE_ELEM(Generic23X, 124) \ + SRIR_ATTRIBUTE_ELEM(Generic23Y, 125) \ + SRIR_ATTRIBUTE_ELEM(Generic23Z, 126) \ + SRIR_ATTRIBUTE_ELEM(Generic23W, 127) \ + SRIR_ATTRIBUTE_ELEM(Generic24X, 128) \ + SRIR_ATTRIBUTE_ELEM(Generic24Y, 129) \ + SRIR_ATTRIBUTE_ELEM(Generic24Z, 130) \ + SRIR_ATTRIBUTE_ELEM(Generic24W, 131) \ + SRIR_ATTRIBUTE_ELEM(Generic25X, 132) \ + SRIR_ATTRIBUTE_ELEM(Generic25Y, 133) \ + SRIR_ATTRIBUTE_ELEM(Generic25Z, 134) \ + SRIR_ATTRIBUTE_ELEM(Generic25W, 135) \ + SRIR_ATTRIBUTE_ELEM(Generic26X, 136) \ + SRIR_ATTRIBUTE_ELEM(Generic26Y, 137) \ + SRIR_ATTRIBUTE_ELEM(Generic26Z, 138) \ + SRIR_ATTRIBUTE_ELEM(Generic26W, 139) \ + SRIR_ATTRIBUTE_ELEM(Generic27X, 140) \ + SRIR_ATTRIBUTE_ELEM(Generic27Y, 141) \ + SRIR_ATTRIBUTE_ELEM(Generic27Z, 142) \ + SRIR_ATTRIBUTE_ELEM(Generic27W, 143) \ + SRIR_ATTRIBUTE_ELEM(Generic28X, 144) \ + SRIR_ATTRIBUTE_ELEM(Generic28Y, 145) \ + SRIR_ATTRIBUTE_ELEM(Generic28Z, 146) \ + SRIR_ATTRIBUTE_ELEM(Generic28W, 147) \ + SRIR_ATTRIBUTE_ELEM(Generic29X, 148) \ + SRIR_ATTRIBUTE_ELEM(Generic29Y, 149) \ + SRIR_ATTRIBUTE_ELEM(Generic29Z, 150) \ + SRIR_ATTRIBUTE_ELEM(Generic29W, 151) \ + SRIR_ATTRIBUTE_ELEM(Generic30X, 152) \ + SRIR_ATTRIBUTE_ELEM(Generic30Y, 153) \ + SRIR_ATTRIBUTE_ELEM(Generic30Z, 154) \ + SRIR_ATTRIBUTE_ELEM(Generic30W, 155) \ + SRIR_ATTRIBUTE_ELEM(Generic31X, 156) \ + SRIR_ATTRIBUTE_ELEM(Generic31Y, 157) \ + SRIR_ATTRIBUTE_ELEM(Generic31Z, 158) \ + SRIR_ATTRIBUTE_ELEM(Generic31W, 159) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseR, 160) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseG, 161) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseB, 162) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontDiffuseA, 163) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularR, 164) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularG, 165) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularB, 166) \ + SRIR_ATTRIBUTE_ELEM(ColorFrontSpecularA, 167) \ + SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseR, 168) \ + SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseG, 169) \ + SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseB, 170) \ + SRIR_ATTRIBUTE_ELEM(ColorBackDiffuseA, 171) \ + SRIR_ATTRIBUTE_ELEM(ColorBackSpecularR, 172) \ + SRIR_ATTRIBUTE_ELEM(ColorBackSpecularG, 173) \ + SRIR_ATTRIBUTE_ELEM(ColorBackSpecularB, 174) \ + SRIR_ATTRIBUTE_ELEM(ColorBackSpecularA, 175) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance0, 176) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance1, 177) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance2, 178) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance3, 179) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance4, 180) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance5, 181) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance6, 182) \ + SRIR_ATTRIBUTE_ELEM(ClipDistance7, 183) \ + SRIR_ATTRIBUTE_ELEM(PointSpriteS, 184) \ + SRIR_ATTRIBUTE_ELEM(PointSpriteT, 185) \ + SRIR_ATTRIBUTE_ELEM(FogCoordinate, 186) \ + SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointU, 188) \ + SRIR_ATTRIBUTE_ELEM(TessellationEvaluationPointV, 189) \ + SRIR_ATTRIBUTE_ELEM(InstanceId, 190) \ + SRIR_ATTRIBUTE_ELEM(VertexId, 191) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture0S, 192) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture0T, 193) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture0R, 194) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture0Q, 195) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture1S, 196) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture1T, 197) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture1R, 198) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture1Q, 199) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture2S, 200) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture2T, 201) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture2R, 202) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture2Q, 203) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture3S, 204) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture3T, 205) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture3R, 206) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture3Q, 207) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture4S, 208) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture4T, 209) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture4R, 210) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture4Q, 211) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture5S, 212) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture5T, 213) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture5R, 214) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture5Q, 215) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture6S, 216) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture6T, 217) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture6R, 218) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture6Q, 219) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture7S, 220) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture7T, 221) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture7R, 222) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture7Q, 223) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture8S, 224) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture8T, 225) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture8R, 226) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture8Q, 227) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture9S, 228) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture9T, 229) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture9R, 230) \ + SRIR_ATTRIBUTE_ELEM(FixedFncTexture9Q, 231) \ + SRIR_ATTRIBUTE_ELEM(ViewportMask, 232) \ + SRIR_ATTRIBUTE_ELEM(FrontFace, 255) \ + /* Implementation attributes */ \ + SRIR_ATTRIBUTE_ELEM(BaseInstance, 256) \ + SRIR_ATTRIBUTE_ELEM(BaseVertex, 257) \ + SRIR_ATTRIBUTE_ELEM(DrawID, 258) +#define SRIR_ATTRIBUTE_ELEM(n, v) n = v, + SRIR_ATTRIBUTE_LIST +#undef SRIR_ATTRIBUTE_ELEM }; constexpr size_t NUM_GENERICS = 32; - constexpr size_t NUM_FIXEDFNCTEXTURE = 10; -[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept; +[[nodiscard]] inline bool IsGeneric(Attribute attribute) noexcept { + return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X; +} -[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute); +[[nodiscard]] inline u32 GenericAttributeIndex(Attribute attribute) { + if (!IsGeneric(attribute)) + throw InvalidArgument("Attribute is not generic {}", attribute); + return (u32(attribute) - u32(Attribute::Generic0X)) / 4u; +} -[[nodiscard]] u32 GenericAttributeElement(Attribute attribute); +[[nodiscard]] inline u32 GenericAttributeElement(Attribute attribute) { + if (!IsGeneric(attribute)) + throw InvalidArgument("Attribute is not generic {}", attribute); + return u32(attribute) % 4; +} -[[nodiscard]] std::string NameOf(Attribute attribute); +[[nodiscard]] inline std::string NameOf(Attribute attribute) { + switch (attribute) { +#define SRIR_ATTRIBUTE_ELEM(n, v) case Attribute::n: return #n; + SRIR_ATTRIBUTE_LIST +#undef SRIR_ATTRIBUTE_ELEM + default: + return fmt::format("", int(attribute)); + } +} [[nodiscard]] constexpr IR::Attribute operator+(IR::Attribute attribute, size_t value) noexcept { - return static_cast(static_cast(attribute) + value); + return IR::Attribute(size_t(attribute) + value); } } // namespace Shader::IR diff --git a/src/shader_recompiler/frontend/ir/flow_test.cpp b/src/shader_recompiler/frontend/ir/flow_test.cpp deleted file mode 100644 index c2dbe2690f..0000000000 --- a/src/shader_recompiler/frontend/ir/flow_test.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#include - -#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("", static_cast(flow_test)); -} - -} // namespace Shader::IR diff --git a/src/shader_recompiler/frontend/ir/flow_test.h b/src/shader_recompiler/frontend/ir/flow_test.h index 014ae6b659..0bb9666538 100644 --- a/src/shader_recompiler/frontend/ir/flow_test.h +++ b/src/shader_recompiler/frontend/ir/flow_test.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -7,45 +10,58 @@ #include #include "common/common_types.h" +#include "shader_recompiler/exception.h" namespace Shader::IR { enum class FlowTest : u64 { - F, - LT, - EQ, - LE, - GT, - NE, - GE, - NUM, - NaN, - LTU, - EQU, - LEU, - GTU, - NEU, - GEU, - T, - OFF, - LO, - SFF, - LS, - HI, - SFT, - HS, - OFT, - CSM_TA, - CSM_TR, - CSM_MX, - FCSM_TA, - FCSM_TR, - FCSM_MX, - RLE, - RGT, +#define SRIR_FLOW_TEST_LIST \ + SRIR_FLOW_TEST_ELEM(F) \ + SRIR_FLOW_TEST_ELEM(LT) \ + SRIR_FLOW_TEST_ELEM(EQ) \ + SRIR_FLOW_TEST_ELEM(LE) \ + SRIR_FLOW_TEST_ELEM(GT) \ + SRIR_FLOW_TEST_ELEM(NE) \ + SRIR_FLOW_TEST_ELEM(GE) \ + SRIR_FLOW_TEST_ELEM(NUM) \ + SRIR_FLOW_TEST_ELEM(NaN) \ + SRIR_FLOW_TEST_ELEM(LTU) \ + SRIR_FLOW_TEST_ELEM(EQU) \ + SRIR_FLOW_TEST_ELEM(LEU) \ + SRIR_FLOW_TEST_ELEM(GTU) \ + SRIR_FLOW_TEST_ELEM(NEU) \ + SRIR_FLOW_TEST_ELEM(GEU) \ + SRIR_FLOW_TEST_ELEM(T) \ + SRIR_FLOW_TEST_ELEM(OFF) \ + SRIR_FLOW_TEST_ELEM(LO) \ + SRIR_FLOW_TEST_ELEM(SFF) \ + SRIR_FLOW_TEST_ELEM(LS) \ + SRIR_FLOW_TEST_ELEM(HI) \ + SRIR_FLOW_TEST_ELEM(SFT) \ + SRIR_FLOW_TEST_ELEM(HS) \ + SRIR_FLOW_TEST_ELEM(OFT) \ + SRIR_FLOW_TEST_ELEM(CSM_TA) \ + SRIR_FLOW_TEST_ELEM(CSM_TR) \ + SRIR_FLOW_TEST_ELEM(CSM_MX) \ + SRIR_FLOW_TEST_ELEM(FCSM_TA) \ + SRIR_FLOW_TEST_ELEM(FCSM_TR) \ + SRIR_FLOW_TEST_ELEM(FCSM_MX) \ + SRIR_FLOW_TEST_ELEM(RLE) \ + SRIR_FLOW_TEST_ELEM(RGT) +#define SRIR_FLOW_TEST_ELEM(n) n, + SRIR_FLOW_TEST_LIST +#undef SRIR_FLOW_TEST_ELEM }; -[[nodiscard]] std::string NameOf(FlowTest flow_test); +[[nodiscard]] inline std::string NameOf(FlowTest flow_test) { + switch (flow_test) { +#define SRIR_FLOW_TEST_ELEM(n) case FlowTest::n: return #n; + SRIR_FLOW_TEST_LIST +#undef SRIR_FLOW_TEST_ELEM + default: + return fmt::format("", int(flow_test)); + } +} } // namespace Shader::IR diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp index b7d9d468b6..e75cdf7c0f 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_atomic_operations.cpp @@ -145,7 +145,7 @@ bool IsSizeInt32(Size size) { } void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg, - IR::Reg bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type, + std::optional bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type, u64 bound_offset, bool is_bindless, bool write_result) { if (clamp != Clamp::IGN) { throw NotImplementedException("Clamp {}", clamp); @@ -158,8 +158,7 @@ void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR const TextureType tex_type{GetType(type)}; const IR::Value coords{MakeCoords(v, coord_reg, type)}; - const IR::U32 handle{is_bindless != 0 ? v.X(bindless_reg) - : v.ir.Imm32(static_cast(bound_offset * 4))}; + const IR::U32 handle = is_bindless ? v.X(*bindless_reg) : v.ir.Imm32(u32(bound_offset * 4)); IR::TextureInstInfo info{}; info.type.Assign(tex_type); info.image_format.Assign(format); @@ -185,7 +184,7 @@ void TranslatorVisitor::SUATOM(u64 insn) { BitField<0, 8, IR::Reg> dest_reg; BitField<8, 8, IR::Reg> coord_reg; BitField<20, 8, IR::Reg> operand_reg; - BitField<36, 13, u64> bound_offset; // !is_bindless + BitField<36, 13, u64> bound_offset; // !is_bindless BitField<39, 8, IR::Reg> bindless_reg; // is_bindless } const suatom{insn}; @@ -196,21 +195,20 @@ void TranslatorVisitor::SUATOM(u64 insn) { void TranslatorVisitor::SURED(u64 insn) { // TODO: confirm offsets + // SURED unlike SUATOM does NOT have a binded register union { u64 raw; - BitField<51, 1, u64> is_bound; - BitField<21, 3, AtomicOp> op; - BitField<33, 3, Type> type; - BitField<20, 3, Size> size; - BitField<49, 2, Clamp> clamp; - BitField<0, 8, IR::Reg> operand_reg; - BitField<8, 8, IR::Reg> coord_reg; - BitField<36, 13, u64> bound_offset; // is_bound - BitField<39, 8, IR::Reg> bindless_reg; // !is_bound + BitField<24, 3, AtomicOp> op; //OK - 24 (SURedOp) + BitField<33, 3, Type> type; //OK? - 33 (Dim) + BitField<20, 3, Size> size; //? + BitField<49, 2, Clamp> clamp; //OK - 49 (Clamp4) + BitField<0, 8, IR::Reg> operand_reg; //RA? + BitField<8, 8, IR::Reg> coord_reg; //RB? + BitField<36, 13, u64> bound_offset; //OK 33 (TidB) } const sured{insn}; - ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, sured.bindless_reg, + ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, std::nullopt, sured.op, sured.clamp, sured.size, sured.type, sured.bound_offset, - sured.is_bound == 0, false); + false, false); } } // namespace Shader::Maxwell diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index b6af1fa750..236010ed38 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -27,3 +27,12 @@ target_link_libraries(tests PRIVATE common core input_common video_core) target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2WithMain Threads::Threads) add_test(NAME tests COMMAND tests) + +# needed for vma +if (NOT MSVC) + target_compile_options(tests PRIVATE + -Wno-conversion + -Wno-unused-variable + -Wno-unused-parameter + -Wno-missing-field-initializers) +endif() diff --git a/src/tests/common/bit_field.cpp b/src/tests/common/bit_field.cpp index 75e990ecd9..2d23ade06e 100644 --- a/src/tests/common/bit_field.cpp +++ b/src/tests/common/bit_field.cpp @@ -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-License-Identifier: GPL-2.0-or-later +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" + #include #include #include diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f437663963..94599532b3 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -312,7 +312,6 @@ add_library(video_core STATIC vulkan_common/vulkan_wrapper.h vulkan_common/nsight_aftermath_tracker.cpp vulkan_common/nsight_aftermath_tracker.h - vulkan_common/vma.cpp vulkan_common/vma.h vulkan_common/vulkan.h ) @@ -369,9 +368,6 @@ else() # xbyak 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 if (CXX_GCC AND CMAKE_BUILD_TYPE MATCHES "Debug") set_source_files_properties(host1x/vic.cpp PROPERTIES COMPILE_OPTIONS "-O2") diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 718958fc11..6f25267a8f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1142,6 +1142,14 @@ void RasterizerOpenGL::SyncBlendState() { glDisable(GL_BLEND); 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); glBlendFuncSeparate(MaxwellToGL::BlendFunc(regs.blend.color_source), MaxwellToGL::BlendFunc(regs.blend.color_dest), diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 453a3d942b..e643e98ead 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -11,6 +11,7 @@ #include #include "common/cityhash.h" #include "common/common_types.h" +#include "common/settings.h" #include "video_core/engines/draw_manager.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.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) { + // 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); return; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 10ee14773f..0532df05d8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -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_3_blend = device.IsExtExtendedDynamicState3BlendingSupported() && 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() { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6bad5eca0b..134327fa8d 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -956,38 +956,24 @@ void RasterizerVulkan::UpdateDynamicStates() { const u8 dynamic_state = Settings::values.dyna_state.GetValue(); - auto features = DynamicFeatures{ - .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) { + if (device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0) { UpdateCullMode(regs); UpdateDepthCompareOp(regs); UpdateFrontFace(regs); UpdateStencilOp(regs); - if (state_tracker.TouchStateEnable()) { UpdateDepthBoundsTestEnable(regs); UpdateDepthTestEnable(regs); UpdateDepthWriteEnable(regs); UpdateStencilTestEnable(regs); - - if (features.has_extended_dynamic_state_2) { + if (device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1) { UpdatePrimitiveRestartEnable(regs); UpdateRasterizerDiscardEnable(regs); UpdateDepthBiasEnable(regs); } - - if (features.has_extended_dynamic_state_3_enables) { + if (device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2) { 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 { const Maxwell3D::Regs::VertexAttribute::Type d; In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} @@ -995,33 +981,28 @@ void RasterizerVulkan::UpdateDynamicStates() { 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)); - - if (regs.logic_op.enable) + auto has_float = std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), In(Maxwell3D::Regs::VertexAttribute::Type::Float)); + if (regs.logic_op.enable) { regs.logic_op.enable = static_cast(!has_float); - + } UpdateLogicOpEnable(regs); } else { UpdateLogicOpEnable(regs); - } + } UpdateDepthClampEnable(regs); + UpdateLineStippleEnable(regs); + UpdateConservativeRasterizationMode(regs); } } - if (features.has_extended_dynamic_state_2_extra) { + if (device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1) { UpdateLogicOp(regs); } - if (features.has_extended_dynamic_state_3_enables) { + if (device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2) { UpdateBlending(regs); - UpdateLineStippleEnable(regs); - UpdateConservativeRasterizationMode(regs); } } - if (features.has_dynamic_vertex_input) { - if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); - gp && gp->HasDynamicVertexInput()) { + if (device.IsExtVertexInputDynamicStateSupported() && dynamic_state > 2) { + if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) { UpdateVertexInput(regs); } } @@ -1557,22 +1538,41 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) { if (state_tracker.TouchBlendEquations()) { std::array setup_blends{}; - for (size_t index = 0; index < Maxwell::NumRenderTargets; index++) { - const auto blend_setup = [&](const T& guest_blend) { - auto& host_blend = setup_blends[index]; - host_blend.srcColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_source); - host_blend.dstColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_dest); - host_blend.colorBlendOp = MaxwellToVK::BlendEquation(guest_blend.color_op); - host_blend.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_source); - host_blend.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_dest); - host_blend.alphaBlendOp = MaxwellToVK::BlendEquation(guest_blend.alpha_op); - }; - if (!regs.blend_per_target_enabled) { - blend_setup(regs.blend); - continue; + + const auto blend_setup = [&](auto& host_blend, const auto& guest_blend) { + host_blend.srcColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_source); + host_blend.dstColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_dest); + host_blend.colorBlendOp = MaxwellToVK::BlendEquation(guest_blend.color_op); + host_blend.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_source); + host_blend.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_dest); + host_blend.alphaBlendOp = MaxwellToVK::BlendEquation(guest_blend.alpha_op); + }; + + // Single blend equation for all targets + if (!regs.blend_per_target_enabled) { + // 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) { cmdbuf.SetColorBlendEquationEXT(0, setup_blends); }); diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index db340efdae..de12d795c8 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -59,7 +59,7 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en case Tegra::Texture::TextureType::TextureCubeArray: return Shader::TextureType::ColorArrayCube; default: - LOG_ERROR(Shader, "Invalid texture_type={}, falling back to texture_type={}", static_cast(entry.texture_type.Value()), Shader::TextureType::Color2D); + LOG_ERROR(Shader, "Invalid texture_type={}. Falling back to texture_type={}", static_cast(entry.texture_type.Value()), Shader::TextureType::Color2D); return Shader::TextureType::Color2D; } } diff --git a/src/video_core/vulkan_common/vma.cpp b/src/video_core/vulkan_common/vma.cpp deleted file mode 100644 index addf107628..0000000000 --- a/src/video_core/vulkan_common/vma.cpp +++ /dev/null @@ -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" diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index fc04647199..84dfef6c5b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -810,21 +810,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (Settings::values.dyna_state.GetValue() == 0) { 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.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.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.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); dynamic_state3_blending = false; dynamic_state3_enables = false; LOG_INFO(Render_Vulkan, "All dynamic state extensions and features have been disabled"); } else { 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); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 79453e4570..d0f2121a65 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -370,15 +370,18 @@ if (APPLE) if (YUZU_USE_BUNDLED_MOLTENVK) set(MOLTENVK_PLATFORM "macOS") - set(MOLTENVK_VERSION "v1.3.0") + set(MOLTENVK_VERSION "v1.4.0") download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION}) endif() + + set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED) 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) # compile as a win32 gui application instead of a console application target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate) @@ -447,4 +450,39 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE Qt6::Widgets) 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) diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 70fd90734f..db8956474c 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -75,9 +75,10 @@ void ConfigureDebug::SetConfiguration() { ui->disable_loop_safety_checks->setChecked(Settings::values.disable_shader_loop_safety_checks.GetValue()); ui->extended_logging->setChecked(Settings::values.extended_logging.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()); - -#ifndef YUZU_USE_QT_WEB_ENGINE +#else + ui->disable_web_applet->setChecked(true); ui->disable_web_applet->setVisible(false); #endif } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bcf5932e73..621c74a618 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -6,10 +6,11 @@ #if YUZU_ROOM #include "dedicated_room/yuzu_room.h" -#include #include #endif +#include + #ifdef __unix__ #include "qt_common/gui_settings.h" #endif diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index b26baf7202..1547c96dd7 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -1,6 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // 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 "main_window.h" #include "network/network.h" @@ -44,6 +49,7 @@ // Qt Stuff // #define QT_NO_OPENGL + #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) #include #endif @@ -263,7 +269,14 @@ using namespace Common::Literals; #endif #ifdef QT_STATICPLUGIN +#include + +#if defined(_WIN32) Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#elif defined(__APPLE__) +Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) +#endif + #endif #ifdef _WIN32 @@ -4897,3 +4910,8 @@ void VolumeButton::ResetMultiplier() { #ifdef main #undef main #endif + +#if !defined(QT_STATICPLUGIN) || defined(__APPLE__) +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" +#endif diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index b26628e074..458eaafc4c 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -56,3 +56,12 @@ if(WIN32) endif() 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() diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index de16ba7815..6ec6f973bb 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -4,12 +4,10 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include #include #include #include -#include #include @@ -17,7 +15,6 @@ #include "common/logging/backend.h" #include "common/logging/log.h" #include "common/scm_rev.h" -#include "common/scope_exit.h" #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" @@ -453,3 +450,6 @@ int main(int argc, char** argv) { detached_tasks.WaitForAllTasks(); return 0; } + +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" diff --git a/src/yuzu_room_standalone/CMakeLists.txt b/src/yuzu_room_standalone/CMakeLists.txt index a0e688d4a8..f1db470495 100644 --- a/src/yuzu_room_standalone/CMakeLists.txt +++ b/src/yuzu_room_standalone/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + add_executable(yuzu_room_standalone yuzu_room_standalone.cpp ) @@ -9,3 +12,5 @@ target_link_libraries(yuzu_room_standalone PRIVATE yuzu-room) if(UNIX AND NOT APPLE) install(TARGETS yuzu_room_standalone RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() + +create_target_directory_groups(yuzu_room_standalone) diff --git a/tools/translations/lupdate.sh b/tools/translations/lupdate.sh deleted file mode 100755 index 0442d25d02..0000000000 --- a/tools/translations/lupdate.sh +++ /dev/null @@ -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 diff --git a/tools/translations/qt-source.sh b/tools/translations/qt-source.sh index 3480070624..89c881d8c0 100755 --- a/tools/translations/qt-source.sh +++ b/tools/translations/qt-source.sh @@ -3,10 +3,7 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -SRC=en_US -TARGET=en_US +SOURCES=$(find src/yuzu src/qt_common -type f \( -name "*.ui" -o -name "*.cpp" -o -name "*.h" -o -name "*.plist" \)) -# 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 dist/languages/en.ts +# shellcheck disable=SC2086 +lupdate -source-language en_US -target-language en_US $SOURCES -ts dist/languages/en.ts \ No newline at end of file diff --git a/tools/update-icons.sh b/tools/update-icons.sh index 132e62da86..5fff11d6c5 100755 --- a/tools/update-icons.sh +++ b/tools/update-icons.sh @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/sh -ex # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later @@ -8,20 +8,21 @@ #which png2icns || (which yay && yay libicns) || exit which magick || exit -EDEN_SVG_ICO="dist/dev.eden_emu.eden.svg" -EALT_SVG_ICO="dist/eden_named.svg" +EDEN_BASE_SVG="dist/icon_variations/base.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 -convert -density 256x256 -resize 256x256 -background transparent $EDEN_SVG_ICO dist/yuzu.bmp || 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_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 $EALT_SVG_ICO dist/qt_themes/default/icons/256x256/eden_named.png || exit +magick -size 256x256 -background transparent $EDEN_BASE_SVG dist/qt_themes/default/icons/256x256/eden.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_named.png -resize 256x256! dist/qt_themes/default/icons/256x256/eden_named.png || exit # Now do more fancy things (like composition) 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 \ src/android/app/src/main/res/drawable/ic_icon_bg_orig.png \ 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.png -png2icns dist/eden.icns $TMP_PNG +png2icns dist/eden.icns $TMP_PNG || echo 'non fatal' cp dist/eden.icns dist/yuzu.icns rm $TMP_PNG