From 7764cdd57ec8a6d97eed904e6e125c0c5fda2f79 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Mon, 10 Nov 2025 23:32:50 +0100 Subject: [PATCH 01/34] [am] Improve some error messages (#2996) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2996 Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/core/hle/service/am/frontend/applet_web_browser.cpp | 2 +- src/core/hle/service/am/frontend/applets.cpp | 7 ++----- src/video_core/shader_environment.cpp | 2 +- src/yuzu/configuration/configure_debug.cpp | 5 +++-- 4 files changed, 7 insertions(+), 9 deletions(-) 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/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/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 } From 7ca657d22f59a66879e7fe8fea710949c38f4d0a Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 11 Nov 2025 06:22:33 +0100 Subject: [PATCH 02/34] [cmake] allow static MinGW/macOS builds; fix clangarm64 (#2994) Requires qt6-static, obviously... at least for eden. eden-cli also can be built fully static Notable challenges n such: 1. VkMemAlloc conflicts with Qt, since it embeds vk_mem_alloc.h in qrhivulkan; we can get around this by conditionally defining VMA_IMPLEMENTATION; that is, define it in the SDL2 frontend and undef it in the Qt frontend. It's not ideal, but I mean... it works, no? 2. find_library, pkgconfig, and some Config modules will always look for a .dll, so we have to tell CMake to look for .a 3. In spite of this, some will end up using .dll.a (implib) as their link targets; this is, well, bad, so we create a find_library hook that rejects dll.a 4. Some libraries have specific configs (boost lol) 5. Some libraries use _static targets (zstd, mbedtls) 6. Some extra libraries need to be linked, i.e. jbig, lzma, etc 7. QuaZip is sad Needs testing on all platforms, and for both frontends on desktop, to ensure Vulkan still works as expected. (also: CI). Resulting executables are: - 71MB for eden.exe - 39MB for eden-cli.exe Considering the entire libicudt is included (thanks Qt), that's a great size all things considered. No need to bundle all those plugins and translation files too. Theoretically, this lays the groundwork towards fully static executables for other platforms too; though Linux doesn't have a huge benefit since AppImages are needed regardless. eden-room though maybe? Fixes comp for clangarm64 because -msse4.1 Also allows macOS to build with qt6-static. macOS can't build static executables, but with these changes it ONLY relies on system libraries like libc and frameworks. So in theory we don't even need macdeployqt. Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2994 --- CMakeLists.txt | 99 ++++++++++++++++++++++++- CMakeModules/CPMUtil.cmake | 5 +- CMakeModules/FindOpus.cmake | 7 ++ CMakeModules/FindSPIRV-Tools.cmake | 7 ++ CMakeModules/Findenet.cmake | 7 ++ CMakeModules/Findlibusb.cmake | 7 ++ CMakeModules/Findlz4.cmake | 8 ++ CMakeModules/Findzstd.cmake | 32 +++++--- CMakeModules/FixMsysPaths.cmake | 21 ++++++ externals/ffmpeg/CMakeLists.txt | 2 +- externals/ffmpeg/cpmfile.json | 3 +- src/CMakeLists.txt | 22 ++++-- src/android/app/src/main/jni/native.cpp | 2 + src/common/CMakeLists.txt | 2 +- src/core/CMakeLists.txt | 8 +- src/dedicated_room/CMakeLists.txt | 5 +- src/tests/CMakeLists.txt | 9 +++ src/tests/common/bit_field.cpp | 6 ++ src/video_core/CMakeLists.txt | 4 - src/video_core/vulkan_common/vma.cpp | 6 -- src/yuzu/CMakeLists.txt | 46 +++++++++++- src/yuzu/main_window.cpp | 18 +++++ src/yuzu_cmd/CMakeLists.txt | 9 +++ src/yuzu_cmd/yuzu.cpp | 6 +- src/yuzu_room_standalone/CMakeLists.txt | 5 ++ 25 files changed, 296 insertions(+), 50 deletions(-) create mode 100644 CMakeModules/FixMsysPaths.cmake delete mode 100644 src/video_core/vulkan_common/vma.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae534444e..ff0667d8e8 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 # ======================================================================= @@ -582,6 +670,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 +723,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 +744,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/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 995b25a2c7..1289c53c99 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -89,7 +89,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 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/src/CMakeLists.txt b/src/CMakeLists.txt index 81c2f81292..5f2d076899 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -176,16 +176,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/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/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/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/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/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/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/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/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) From f32f356c40b4b074dda7c64e7d8949644110e68d Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 11 Nov 2025 07:44:14 +0100 Subject: [PATCH 03/34] [desktop] always include common/detached_tasks.h (#3002) Co-authored-by: Pabel Sobolev Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3002 --- src/yuzu/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From b7584cb2c3ba211595ceb86de416edb8f04617e5 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 12 Nov 2025 04:38:32 +0100 Subject: [PATCH 04/34] [ci] push sources on every master push (#3007) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3007 --- .github/workflows/sources.yml | 19 +++++++++++++++++++ tools/translations/lupdate.sh | 14 -------------- tools/translations/qt-source.sh | 9 +++------ 3 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/sources.yml delete mode 100755 tools/translations/lupdate.sh diff --git a/.github/workflows/sources.yml b/.github/workflows/sources.yml new file mode 100644 index 0000000000..20cb03c449 --- /dev/null +++ b/.github/workflows/sources.yml @@ -0,0 +1,19 @@ +name: tx-src + +on: + push: + branches: [ master ] + +jobs: + license-header: + 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/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 From 87c4f658ce7e471c6b7ce33c92d1973460af6091 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 12 Nov 2025 05:21:49 +0100 Subject: [PATCH 05/34] [ci] tx update ci (#3008) Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3008 --- .github/workflows/sources.yml | 2 +- .github/workflows/translations.yml | 61 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/translations.yml diff --git a/.github/workflows/sources.yml b/.github/workflows/sources.yml index 20cb03c449..8e98419cba 100644 --- a/.github/workflows/sources.yml +++ b/.github/workflows/sources.yml @@ -5,7 +5,7 @@ on: branches: [ master ] jobs: - license-header: + sources: runs-on: source steps: - uses: actions/checkout@v4 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 + From d89df63a287b75ed4402cfac43c23261d778a9bb Mon Sep 17 00:00:00 2001 From: MaranBr Date: Thu, 13 Nov 2025 03:04:00 +0100 Subject: [PATCH 06/34] [video_core] Clean up the code and fix some inconsistences (#3015) This cleans up the code and fixes some inconsistencies in the EDS settings. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3015 Co-authored-by: MaranBr Co-committed-by: MaranBr --- .../renderer_vulkan/vk_pipeline_cache.cpp | 7 +-- .../renderer_vulkan/vk_rasterizer.cpp | 47 ++++++------------- .../vulkan_common/vulkan_device.cpp | 7 ++- 3 files changed, 18 insertions(+), 43 deletions(-) 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..530c7e8e41 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); } } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 7b7c4b0b78..81e60f1c6a 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -745,21 +745,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); From 028765867feae4a1cae77bfc3370c73381cfeb2d Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Thu, 13 Nov 2025 03:20:38 +0100 Subject: [PATCH 07/34] externals: Fix Debug builds and remove PCH leftover (#3000) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3000 Reviewed-by: Lizzie Reviewed-by: crueter Reviewed-by: MaranBr Co-authored-by: Caio Oliveira Co-committed-by: Caio Oliveira --- CMakeLists.txt | 34 ++++++++++-------- CMakeModules/MinGWClangCross.cmake | 58 ------------------------------ CMakeModules/MinGWCross.cmake | 57 ----------------------------- externals/CMakeLists.txt | 7 ---- src/CMakeLists.txt | 6 ---- src/dynarmic/CMakeLists.txt | 5 --- 6 files changed, 20 insertions(+), 147 deletions(-) delete mode 100644 CMakeModules/MinGWClangCross.cmake delete mode 100644 CMakeModules/MinGWCross.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ff0667d8e8..6f099834c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,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) @@ -332,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) @@ -372,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? @@ -443,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) 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/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/src/CMakeLists.txt b/src/CMakeLists.txt index 5f2d076899..2510458812 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() 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 From 7832afc5dd23d4a4343ac356b8864386cb9ad064 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 13 Nov 2025 03:25:55 +0100 Subject: [PATCH 08/34] [externals] update nx-tzdb to 121125 (#3011) real gzipped archive Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3011 Reviewed-by: Caio Oliveira --- externals/nx_tzdb/cpmfile.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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" } } From ba9e03a612f4d4d50ad619ab3135bcb04b0fc29d Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 03:40:29 +0100 Subject: [PATCH 09/34] [shared_recompiler/maxwell] fix SURED() wrong encodings (#2983) SURED does NOT have a binding register and stuff, it is strictly just a binding-offset * 4 Signed-off-by: lizzie lizzie@eden-emu.dev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2983 Reviewed-by: MaranBr Reviewed-by: Caio Oliveira Co-authored-by: lizzie Co-committed-by: lizzie --- .../impl/surface_atomic_operations.cpp | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) 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 From f51d61e4a41218780815bfa7d2c13ccc5e2744b5 Mon Sep 17 00:00:00 2001 From: kleidis Date: Thu, 13 Nov 2025 03:45:41 +0100 Subject: [PATCH 10/34] [android] Use spinbox setting type for CPU_TICKS (#2952) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2952 Reviewed-by: crueter Reviewed-by: MaranBr Reviewed-by: Caio Oliveira Co-authored-by: kleidis Co-committed-by: kleidis --- .../settings/model/view/SettingsItem.kt | 3 +- .../settings/ui/SettingsDialogFragment.kt | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) 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..bbcfe3da45 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 ) 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..eb1b0a4257 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) {} From cfbef5c487005077224f0c5d26317680243cadfc Mon Sep 17 00:00:00 2001 From: kleidis Date: Thu, 13 Nov 2025 03:45:58 +0100 Subject: [PATCH 11/34] [android] Setting to manually set app language (#2951) It is on the app settings section Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2951 Reviewed-by: crueter Reviewed-by: MaranBr Co-authored-by: kleidis Co-committed-by: kleidis --- .../java/org/yuzu/yuzu_emu/YuzuApplication.kt | 37 +++++++++++++ .../yuzu_emu/activities/EmulationActivity.kt | 4 ++ .../features/settings/model/IntSetting.kt | 1 + .../settings/model/view/SettingsItem.kt | 9 +++ .../features/settings/ui/SettingsActivity.kt | 20 +++++++ .../features/settings/ui/SettingsAdapter.kt | 8 +++ .../settings/ui/SettingsDialogFragment.kt | 6 ++ .../settings/ui/SettingsFragmentPresenter.kt | 4 +- .../features/settings/ui/SettingsViewModel.kt | 9 +++ .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 6 ++ .../app/src/main/jni/android_settings.h | 1 + .../app/src/main/res/values/arrays.xml | 55 +++++++++++++++++++ .../app/src/main/res/values/strings.xml | 29 ++++++++++ 13 files changed, 188 insertions(+), 1 deletion(-) 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 bbcfe3da45..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 @@ -757,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 eb1b0a4257..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 @@ -387,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/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) From 9a046190c77905c278b2ec7e9c299d15cbb855bb Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 13:22:02 +0100 Subject: [PATCH 12/34] [shader_recompiler] macro-ify flow_test and attribute (#2900) Of course - macros my beloved :) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2900 Reviewed-by: crueter Reviewed-by: MaranBr Reviewed-by: Caio Oliveira Co-authored-by: lizzie Co-committed-by: lizzie --- src/shader_recompiler/CMakeLists.txt | 2 - .../frontend/ir/attribute.cpp | 459 ----------------- src/shader_recompiler/frontend/ir/attribute.h | 464 +++++++++--------- .../frontend/ir/flow_test.cpp | 82 ---- src/shader_recompiler/frontend/ir/flow_test.h | 82 ++-- 5 files changed, 293 insertions(+), 796 deletions(-) delete mode 100644 src/shader_recompiler/frontend/ir/attribute.cpp delete mode 100644 src/shader_recompiler/frontend/ir/flow_test.cpp 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 From 66db2613b52233ac9841ab3aafb212312d8c9f8f Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 13:23:46 +0100 Subject: [PATCH 13/34] [common] fix formatting of swapped u32_le/u64_le for BE targets (#2998) Fixes a bunch of errors :) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2998 Reviewed-by: Caio Oliveira Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/logging/formatter.h | 16 +- src/common/swap.h | 279 +++++++++++++++++---------------- 2 files changed, 155 insertions(+), 140 deletions(-) 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/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 From 450c483de0e9779153db1de3dfe1238dcc9055c2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 13:26:40 +0100 Subject: [PATCH 14/34] [cmake, externals/ffmpeg]: fix Solaris and BSD* builds with troubling makes (#3014) Partial backport of https://github.com/pflyly/eden-nightly/blob/main/patches/solaris.patch Signed-off-by: lizzie lizzie@eden-emu.dev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3014 Reviewed-by: Caio Oliveira Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- externals/ffmpeg/CMakeLists.txt | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 1289c53c99..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) @@ -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} ) From 3edfcabdea14fd7e9e8e2baa66d372cffac7ffbf Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 13:27:03 +0100 Subject: [PATCH 15/34] [dist] small low-fi version of the icon w/o antialias artifacts (#3006) This version of the icon is mainly so the main one doesn't look like it has been compressed like a JPEG when shown on the taskbar :) Signed-off-by: lizzie lizzie@eden-emu.dev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3006 Reviewed-by: Caio Oliveira Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- dist/eden.ico | Bin 322147 -> 395668 bytes dist/icon_variations/README.md | 9 ++++ dist/icon_variations/base_small.svg | 80 ++++++++++++++++++++++++++++ dist/yuzu.bmp | Bin 262282 -> 262282 bytes tools/update-icons.sh | 19 +++---- 5 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 dist/icon_variations/README.md create mode 100644 dist/icon_variations/base_small.svg diff --git a/dist/eden.ico b/dist/eden.ico index f34d31d29ea486d92ea77f4d49a9c4ad71502df5..4dc347af283d60b43fd626d208609a382cb54047 100644 GIT binary patch literal 395668 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
KV3qi_JE`lx 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 VhGMo^Z~$ufBnV^iMEFC0{{~B5vv&Xh literal 322147 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�ieXhLk3wRzb!fv#9XU_b2=o06{T*&45b_w_loGU#0@_EMf=h-(CThBk@HyU1B zn!9ZT&$j%b1o#!LvcFwUG^Qrz_i|PJ}(Nu^!6Xlky}8ck}G+Z0qC9NX82=d{lw`$79ER%&z1DITI|oY?^y<$;Un;wp&q9bMEzlApH-Cn b)=9cAQfGNJ{1CK1{E}r#@>@jzZa?%t4|r=Y 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 45de9b13ebf2d213634281b61c4f1b870ed094c6..a548aaf7e6da5425b2ab520be6fc9ed756dd7ff8 100644 GIT binary patch literal 262282 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 literal 262282 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 AA^-pY 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 From 8eaa7c28ce3cfea76d64af54334ac4971659085a Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 13 Nov 2025 13:27:32 +0100 Subject: [PATCH 16/34] [common] provide fallback for lack of atomic u128 support (#2999) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2999 Reviewed-by: Caio Oliveira Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/atomic_ops.h | 47 ++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) 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 From 32db6c18779a3e69b065ecbd68be2b61cb2a9c4d Mon Sep 17 00:00:00 2001 From: xbzk Date: Thu, 13 Nov 2025 14:01:32 +0100 Subject: [PATCH 17/34] [renderer] NG ragebound workaround via LoadOverrides + vk_rasterizer UpdateBlending TouchBlendequations Rework (#2934) this pull should impact ninja gaiden ragebound only! it makes it playable past stage 4-1. it contains a workaround for missing maxwell_3d's iterated_blend functionality, which fixes several graphics all over the game. the issue causes transparency enabled blends (mostly lighting fx) to be wrongly blended into destination, turning textures into black frames. in stage 4-1 there are lighthing layers in the foreground, causing sprites layer to become overlapped by these opaque black frames, including entire screen in a mid boss fight, making it unplayable* (players maneuvered by turning immortal option on and swinging sword all around until defeating it). also only in stage 4-1 the fix has a short drawback: when you buff up next attack these problematique blends will be drawn back as black frames, but only for a split second, so no big deal. this workaround was already discovered and available in PR 302, but in an unconventional way for a game specific override, so we did forbidden it. now it uses classic game specific override solution exampled in core.cpp's System::Impl::LoadOverrides method, so now i guess it's worth to merge it and deliver this to players until we harness iterated_blend control. additionally I've slightly reworked vk_rasterizer.cpp's RasterizerVulkan::UpdateBlending, if (state_tracker.TouchBlendEquations()) {...} session. it was made in a way that for a single blend, it exhaustly calls 48 (6 x 8) MaxwellToVK redundant functions, and declared a lambda function inside a 8 laps loop. reworked it so that instead of 48 calls it makes only the necessary 6 calls, and then merely safely copy the result for the other 7 times. Co-authored-by: Allison Cunha Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2934 Reviewed-by: MaranBr Reviewed-by: Shinmegumi Reviewed-by: Maufeat Co-authored-by: xbzk Co-committed-by: xbzk --- src/common/settings.cpp | 3 ++ src/common/settings.h | 3 ++ src/core/core.cpp | 13 +++++ .../renderer_opengl/gl_rasterizer.cpp | 8 ++++ .../renderer_vulkan/fixed_pipeline_state.cpp | 14 ++++++ .../renderer_vulkan/vk_rasterizer.cpp | 47 +++++++++++++------ 6 files changed, 74 insertions(+), 14 deletions(-) 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/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/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_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 530c7e8e41..134327fa8d 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1538,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); }); From d6b5a3e18105ca523e29db3421221020cca045c7 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 8 Nov 2025 01:09:05 -0400 Subject: [PATCH 18/34] Giving maintance to driver features and unused extensions --- .../renderer_vulkan/vk_swapchain.cpp | 36 +++++++++++++++- src/video_core/renderer_vulkan/vk_swapchain.h | 2 + src/video_core/vulkan_common/vulkan.h | 28 +++++++++++++ .../vulkan_common/vulkan_device.cpp | 42 +++++++++++++++++-- src/video_core/vulkan_common/vulkan_device.h | 17 ++++++++ 5 files changed, 121 insertions(+), 4 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index fdd2de2379..cb2b3d7520 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -171,6 +171,10 @@ void Swapchain::Create( resource_ticks.clear(); resource_ticks.resize(image_count); + + // Initialize incremental-present probe flags for this swapchain. + incremental_present_usable = device.IsKhrIncrementalPresentSupported(); + incremental_present_probed = false; } bool Swapchain::AcquireNextImage() { @@ -202,7 +206,13 @@ bool Swapchain::AcquireNextImage() { void Swapchain::Present(VkSemaphore render_semaphore) { const auto present_queue{device.GetPresentQueue()}; - const VkPresentInfoKHR present_info{ + // If the device advertises VK_KHR_incremental_present, we attempt a one-time probe + // on the first present to validate the driver/compositor accepts present-region info. + VkPresentRegionsKHR present_regions{}; + VkPresentRegionKHR region{}; + VkRect2D rect{}; + + VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = nullptr, .waitSemaphoreCount = render_semaphore ? 1U : 0U, @@ -212,6 +222,20 @@ void Swapchain::Present(VkSemaphore render_semaphore) { .pImageIndices = &image_index, .pResults = nullptr, }; + + if (incremental_present_usable && !incremental_present_probed) { + // Build a minimal present-region describing a single 1x1 dirty rect at (0,0). + rect.offset = {0, 0}; + rect.extent = {1, 1}; + region.rectangleCount = 1; + region.pRectangles = ▭ + present_regions.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR; + present_regions.pNext = nullptr; + present_regions.swapchainCount = 1; + present_regions.pRegions = ®ion; + + present_info.pNext = &present_regions; + } std::scoped_lock lock{scheduler.submit_mutex}; switch (const VkResult result = present_queue.Present(present_info)) { case VK_SUCCESS: @@ -227,8 +251,18 @@ void Swapchain::Present(VkSemaphore render_semaphore) { break; default: LOG_CRITICAL(Render_Vulkan, "Failed to present with error {}", string_VkResult(result)); + // If the first present with incremental-present pNext failed, disable future use. + if (incremental_present_usable && !incremental_present_probed) { + incremental_present_usable = false; + LOG_WARNING(Render_Vulkan, "Disabling VK_KHR_incremental_present for this swapchain due to present failure: {}", string_VkResult(result)); + } break; } + if (incremental_present_usable && !incremental_present_probed) { + // Mark probe as completed if we reached here (success or handled failure above). + incremental_present_probed = true; + LOG_INFO(Render_Vulkan, "VK_KHR_incremental_present probe completed: usable={}", incremental_present_usable); + } ++frame_index; if (frame_index >= image_count) { frame_index = 0; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index b3e1c4f025..2c6055fba3 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -158,6 +158,8 @@ private: bool is_outdated{}; bool is_suboptimal{}; + bool incremental_present_usable{}; + bool incremental_present_probed{}; }; } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 13f679ff54..7092243f7f 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -22,6 +22,34 @@ #include +#ifndef VK_KHR_MAINTENANCE_1_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +#endif +#ifndef VK_KHR_MAINTENANCE_2_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +#endif +#ifndef VK_KHR_MAINTENANCE_3_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +#endif +#ifndef VK_KHR_MAINTENANCE_4_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +#endif +#ifndef VK_KHR_MAINTENANCE_5_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5" +#endif +#ifndef VK_KHR_MAINTENANCE_6_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6" +#endif +#ifndef VK_KHR_MAINTENANCE_7_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7" +#endif +#ifndef VK_KHR_MAINTENANCE_8_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8" +#endif +#ifndef VK_KHR_MAINTENANCE_9_EXTENSION_NAME +# define VK_KHR_MAINTENANCE_9_EXTENSION_NAME "VK_KHR_maintenance9" +#endif + // Sanitize macros #undef CreateEvent #undef CreateSemaphore diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 81e60f1c6a..dd794af70f 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -416,7 +416,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_suitable = GetSuitability(surface != nullptr); const VkDriverId driver_id = properties.driver.driverID; - const auto device_id = properties.properties.deviceID; const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; const bool is_amd_driver = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; @@ -681,9 +680,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR has_broken_compute = CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) && !Settings::values.enable_compute_pipelines.GetValue(); - if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { - LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); + must_emulate_bgr565 = false; // Default: assume emulation isn't required + + if (is_intel_anv) { + LOG_WARNING(Render_Vulkan, "Intel ANV driver does not support native BGR format"); must_emulate_bgr565 = true; + } else if (is_qualcomm) { + // Qualcomm driver version where VK_KHR_maintenance5 and A1B5G5R5 become reliable + constexpr uint32_t QUALCOMM_FIXED_DRIVER_VERSION = VK_MAKE_VERSION(512, 800, 1); + // Check if VK_KHR_maintenance5 is supported + if (extensions.maintenance5 && properties.properties.driverVersion >= QUALCOMM_FIXED_DRIVER_VERSION) { + LOG_INFO(Render_Vulkan, "Qualcomm driver supports VK_KHR_maintenance5, disabling BGR emulation"); + must_emulate_bgr565 = false; + } else { + LOG_WARNING(Render_Vulkan, "Qualcomm driver doesn't support native BGR, emulating formats"); + must_emulate_bgr565 = true; + } + } else if (is_turnip) { + // Mesa Turnip added support for maintenance5 in Mesa 25.0 + if (extensions.maintenance5) { + LOG_INFO(Render_Vulkan, "Turnip driver supports VK_KHR_maintenance5, disabling BGR emulation"); + must_emulate_bgr565 = false; + } else { + LOG_WARNING(Render_Vulkan, "Turnip driver doesn't support native BGR, emulating formats"); + must_emulate_bgr565 = true; + } } if (extensions.push_descriptor && is_intel_anv) { const u32 version = (properties.properties.driverVersion << 3) >> 3; @@ -1300,6 +1321,21 @@ void Device::RemoveUnsuitableExtensions() { RemoveExtensionFeatureIfUnsuitable(extensions.transform_feedback, features.transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); + // VK_EXT_robustness2 + extensions.robustness_2 = + features.robustness2.robustBufferAccess2 && features.robustness2.robustImageAccess2; + RemoveExtensionFeatureIfUnsuitable(extensions.robustness_2, features.robustness2, + VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); + + // VK_EXT_image_robustness + extensions.image_robustness = features.image_robustness.robustImageAccess; + RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness, + VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME); + + // VK_EXT_swapchain_maintenance1 + extensions.swapchain_maintenance1 = loaded_extensions.contains(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); + RemoveExtensionIfUnsuitable(extensions.swapchain_maintenance1, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); + // VK_EXT_vertex_input_dynamic_state extensions.vertex_input_dynamic_state = features.vertex_input_dynamic_state.vertexInputDynamicState; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index cb13f28523..6f60741fea 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -52,6 +52,7 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \ FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \ FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \ + FEATURE(EXT, ImageRobustness, IMAGE_ROBUSTNESS, image_robustness) \ FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \ primitive_topology_list_restart) \ FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \ @@ -82,7 +83,9 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \ EXTENSION(KHR, SPIRV_1_4, spirv_1_4) \ EXTENSION(KHR, SWAPCHAIN, swapchain) \ + EXTENSION(KHR, INCREMENTAL_PRESENT, incremental_present) \ EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \ + EXTENSION(EXT, SWAPCHAIN_MAINTENANCE_1, swapchain_maintenance1) \ EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \ EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \ EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \ @@ -91,6 +94,15 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(EXT, DESCRIPTOR_INDEXING, descriptor_indexing) \ EXTENSION(EXT, FILTER_CUBIC, filter_cubic) \ EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights) + EXTENSION(KHR, MAINTENANCE_1, maintenance1) \ + EXTENSION(KHR, MAINTENANCE_2, maintenance2) \ + EXTENSION(KHR, MAINTENANCE_3, maintenance3) \ + EXTENSION(KHR, MAINTENANCE_4, maintenance4) \ + EXTENSION(KHR, MAINTENANCE_5, maintenance5) \ + EXTENSION(KHR, MAINTENANCE_6, maintenance6) \ + EXTENSION(KHR, MAINTENANCE_7, maintenance7) \ + EXTENSION(KHR, MAINTENANCE_8, maintenance8) \ + EXTENSION(KHR, MAINTENANCE_9, maintenance9) \ // Define extensions which must be supported. #define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \ @@ -455,6 +467,11 @@ public: return extensions.image_format_list || instance_version >= VK_API_VERSION_1_2; } + /// Returns true if the device supports VK_KHR_incremental_present. + bool IsKhrIncrementalPresentSupported() const { + return extensions.incremental_present; + } + /// Returns true if the device supports VK_EXT_primitive_topology_list_restart. bool IsTopologyListPrimitiveRestartSupported() const { return features.primitive_topology_list_restart.primitiveTopologyListRestart; From b574e9c334a45bc56034c8bbc386eadec953e3a8 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 8 Nov 2025 01:28:35 -0400 Subject: [PATCH 19/34] attempt to fix building issues --- src/video_core/renderer_vulkan/present/fsr.cpp | 3 +++ src/video_core/renderer_vulkan/present/fxaa.cpp | 3 +++ src/video_core/renderer_vulkan/present/layer.cpp | 1 + src/video_core/renderer_vulkan/present/util.cpp | 1 + src/video_core/renderer_vulkan/vk_swapchain.h | 3 +++ 5 files changed, 11 insertions(+) diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp index 3f708be704..8422a00204 100644 --- a/src/video_core/renderer_vulkan/present/fsr.cpp +++ b/src/video_core/renderer_vulkan/present/fsr.cpp @@ -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 diff --git a/src/video_core/renderer_vulkan/present/fxaa.cpp b/src/video_core/renderer_vulkan/present/fxaa.cpp index bdafd1f4d0..d53fd29b9e 100644 --- a/src/video_core/renderer_vulkan/present/fxaa.cpp +++ b/src/video_core/renderer_vulkan/present/fxaa.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp index 5676dfe62a..a3bb5739cf 100644 --- a/src/video_core/renderer_vulkan/present/layer.cpp +++ b/src/video_core/renderer_vulkan/present/layer.cpp @@ -17,6 +17,7 @@ #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/textures/decoders.h" +#include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 29a1c34976..76ccc6c0e0 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include #include "video_core/renderer_vulkan/present/util.h" +#include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 2c6055fba3..2d619959b0 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From 35b4e34e09582351ecc1854fc3e16c33951f463b Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 8 Nov 2025 12:41:15 -0500 Subject: [PATCH 20/34] build Signed-off-by: crueter --- src/CMakeLists.txt | 2 +- .../renderer_vulkan/present/fsr.cpp | 3 --- .../renderer_vulkan/present/fxaa.cpp | 3 --- .../renderer_vulkan/present/layer.cpp | 1 - .../renderer_vulkan/present/util.cpp | 2 -- .../renderer_vulkan/vk_swapchain.cpp | 8 +++---- .../vulkan_common/vulkan_device.cpp | 4 +++- src/video_core/vulkan_common/vulkan_device.h | 22 +++++++++---------- 8 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2510458812..5387de6191 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -121,7 +121,7 @@ else() -Werror=unused -Wno-attributes - -Wno-invalid-offsetof + $<$:-Wno-invalid-offsetof> -Wno-unused-parameter -Wno-missing-field-initializers ) diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp index 8422a00204..3f708be704 100644 --- a/src/video_core/renderer_vulkan/present/fsr.cpp +++ b/src/video_core/renderer_vulkan/present/fsr.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/video_core/renderer_vulkan/present/fxaa.cpp b/src/video_core/renderer_vulkan/present/fxaa.cpp index d53fd29b9e..bdafd1f4d0 100644 --- a/src/video_core/renderer_vulkan/present/fxaa.cpp +++ b/src/video_core/renderer_vulkan/present/fxaa.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp index a3bb5739cf..5676dfe62a 100644 --- a/src/video_core/renderer_vulkan/present/layer.cpp +++ b/src/video_core/renderer_vulkan/present/layer.cpp @@ -17,7 +17,6 @@ #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/textures/decoders.h" -#include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 76ccc6c0e0..148e99b477 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp @@ -5,9 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" -#include #include "video_core/renderer_vulkan/present/util.h" -#include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index cb2b3d7520..d3fd0c340b 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -210,7 +210,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { // on the first present to validate the driver/compositor accepts present-region info. VkPresentRegionsKHR present_regions{}; VkPresentRegionKHR region{}; - VkRect2D rect{}; + VkRectLayerKHR layer{}; VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -225,10 +225,10 @@ void Swapchain::Present(VkSemaphore render_semaphore) { if (incremental_present_usable && !incremental_present_probed) { // Build a minimal present-region describing a single 1x1 dirty rect at (0,0). - rect.offset = {0, 0}; - rect.extent = {1, 1}; + layer.offset = {0, 0}; + layer.extent = {1, 1}; region.rectangleCount = 1; - region.pRectangles = ▭ + region.pRectangles = &layer; present_regions.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR; present_regions.pNext = nullptr; present_regions.swapchainCount = 1; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index dd794af70f..1f70093379 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -416,6 +416,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_suitable = GetSuitability(surface != nullptr); const VkDriverId driver_id = properties.driver.driverID; + // uncomment this if you want per-device overrides :P + // const u32 device_id = properties.properties.deviceID; + const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV; const bool is_amd_driver = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE; @@ -426,7 +429,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK; const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY; const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP; - const bool is_s8gen2 = device_id == 0x43050a01; const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 6f60741fea..71b431c9fc 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -83,7 +83,7 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(KHR, SHADER_FLOAT_CONTROLS, shader_float_controls) \ EXTENSION(KHR, SPIRV_1_4, spirv_1_4) \ EXTENSION(KHR, SWAPCHAIN, swapchain) \ - EXTENSION(KHR, INCREMENTAL_PRESENT, incremental_present) \ + EXTENSION(KHR, INCREMENTAL_PRESENT, incremental_present) \ EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \ EXTENSION(EXT, SWAPCHAIN_MAINTENANCE_1, swapchain_maintenance1) \ EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \ @@ -93,16 +93,16 @@ VK_DEFINE_HANDLE(VmaAllocator) EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle) \ EXTENSION(EXT, DESCRIPTOR_INDEXING, descriptor_indexing) \ EXTENSION(EXT, FILTER_CUBIC, filter_cubic) \ - EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights) - EXTENSION(KHR, MAINTENANCE_1, maintenance1) \ - EXTENSION(KHR, MAINTENANCE_2, maintenance2) \ - EXTENSION(KHR, MAINTENANCE_3, maintenance3) \ - EXTENSION(KHR, MAINTENANCE_4, maintenance4) \ - EXTENSION(KHR, MAINTENANCE_5, maintenance5) \ - EXTENSION(KHR, MAINTENANCE_6, maintenance6) \ - EXTENSION(KHR, MAINTENANCE_7, maintenance7) \ - EXTENSION(KHR, MAINTENANCE_8, maintenance8) \ - EXTENSION(KHR, MAINTENANCE_9, maintenance9) \ + EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights) \ + EXTENSION(KHR, MAINTENANCE_1, maintenance1) \ + EXTENSION(KHR, MAINTENANCE_2, maintenance2) \ + EXTENSION(KHR, MAINTENANCE_3, maintenance3) \ + EXTENSION(KHR, MAINTENANCE_4, maintenance4) \ + EXTENSION(KHR, MAINTENANCE_5, maintenance5) \ + EXTENSION(KHR, MAINTENANCE_6, maintenance6) \ + EXTENSION(KHR, MAINTENANCE_7, maintenance7) \ + EXTENSION(KHR, MAINTENANCE_8, maintenance8) \ + EXTENSION(KHR, MAINTENANCE_9, maintenance9) // Define extensions which must be supported. #define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \ From baddaf0040827f7899b9ba7d7ecb3796a7f869ff Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sat, 8 Nov 2025 16:13:24 -0400 Subject: [PATCH 21/34] Implement handling for texture cache flickering --- src/video_core/texture_cache/texture_cache.h | 27 +++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 2a44a5e8b2..3926fd87ac 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1491,7 +1491,32 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA for (const ImageId overlap_id : join_ignore_textures) { Image& overlap = slot_images[overlap_id]; if (True(overlap.flags & ImageFlagBits::GpuModified)) { - UNIMPLEMENTED(); + // Merge GPU-modified contents from the overlapping image into the newly + // created image to preserve guest-visible data. Compute shrink/scale + // copies and dispatch a GPU-side copy. This mirrors the behavior used + // for overlaps handled in join_copies_to_do above. + new_image.flags |= ImageFlagBits::GpuModified; + const auto& resolution = Settings::values.resolution_info; + const auto base_opt = new_image.TryFindBase(overlap.gpu_addr); + if (base_opt) { + const SubresourceBase base = base_opt.value(); + const u32 up_scale = can_rescale ? resolution.up_scale : 1; + const u32 down_shift = can_rescale ? resolution.down_shift : 0; + auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift); + if (overlap.info.num_samples != new_image.info.num_samples) { + runtime.CopyImageMSAA(new_image, overlap, FixSmallVectorADL(copies)); + } else { + runtime.CopyImage(new_image, overlap, FixSmallVectorADL(copies)); + } + new_image.modification_tick = overlap.modification_tick; + } else { + // If we cannot determine a base mapping, fallback to preserving the + // overlap (avoid deleting GPU-modified data) and log the event so + // it can be investigated, we're trying to pinpoint the issue of texture flickering. + LOG_WARNING(HW_GPU, "Could not map overlap gpu_addr {:#x} into new image; preserving overlap {}", + overlap.gpu_addr, overlap_id); + continue; + } } if (True(overlap.flags & ImageFlagBits::Tracked)) { UntrackImage(overlap, overlap_id); From aa8cc4da383171db76cc6e7e5ce04d94e7daebb6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 8 Nov 2025 22:48:36 +0000 Subject: [PATCH 22/34] fix --- src/video_core/texture_cache/texture_cache.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 3926fd87ac..8ac025f1df 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1513,8 +1513,7 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA // If we cannot determine a base mapping, fallback to preserving the // overlap (avoid deleting GPU-modified data) and log the event so // it can be investigated, we're trying to pinpoint the issue of texture flickering. - LOG_WARNING(HW_GPU, "Could not map overlap gpu_addr {:#x} into new image; preserving overlap {}", - overlap.gpu_addr, overlap_id); + LOG_WARNING(HW_GPU, "Could not map overlap gpu_addr {:#x} into new image; preserving overlap", u64(overlap.gpu_addr)); continue; } } From 2d85b703734521d995f1e7db433d133b1d3e2af8 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 01:22:15 -0400 Subject: [PATCH 23/34] Improved handling for Custom Border Color buggy impl on ARM/ QCOM and Turnip --- .../vulkan_common/vulkan_device.cpp | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 1f70093379..5d3fabbd43 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -495,11 +495,23 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR CollectPhysicalMemoryInfo(); CollectToolingInfo(); - if (is_qualcomm || is_turnip) { - LOG_WARNING(Render_Vulkan, - "Qualcomm and Turnip drivers have broken VK_EXT_custom_border_color"); - //RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, - //VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); + // Driver-specific handling for VK_EXT_custom_border_color + // On some Qualcomm/Turnip/ARM drivers the extension may be partially implemented. + // Enable it if ANY useful feature bit is reported; otherwise, let the removal pass drop it. + if (is_qualcomm || is_turnip || is_arm) { + const bool has_any_custom_border_color = + features.custom_border_color.customBorderColors || + features.custom_border_color.customBorderColorWithoutFormat; + if (!has_any_custom_border_color) { + LOG_WARNING(Render_Vulkan, + "Disabling VK_EXT_custom_border_color on '{}' — no usable custom border color features reported", + properties.driver.driverName); + // Do not clear here; final removal happens in RemoveUnsuitableExtensions based on bits. + } else { + LOG_INFO(Render_Vulkan, + "Partial VK_EXT_custom_border_color support detected on '{}' — enabling available features", + properties.driver.driverName); + } } if (is_qualcomm) { @@ -707,6 +719,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_WARNING(Render_Vulkan, "Turnip driver doesn't support native BGR, emulating formats"); must_emulate_bgr565 = true; } + } else if (is_arm) { + // ARM Mali: stop emulating BGR5 formats when VK_KHR_maintenance5 is available + if (extensions.maintenance5) { + LOG_INFO(Render_Vulkan, "ARM driver supports VK_KHR_maintenance5, disabling BGR emulation"); + must_emulate_bgr565 = false; + } else { + LOG_WARNING(Render_Vulkan, "ARM driver doesn't support native BGR, emulating formats"); + must_emulate_bgr565 = true; + } } if (extensions.push_descriptor && is_intel_anv) { const u32 version = (properties.properties.driverVersion << 3) >> 3; From a14cba7f11761d578332a867a60c1024eadcee32 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 02:23:53 -0400 Subject: [PATCH 24/34] TEST: Enabling TimelineSemaphores for QCOM and Turnip --- src/video_core/vulkan_common/vulkan_device.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 5d3fabbd43..5d59fdbc4d 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1017,13 +1017,6 @@ bool Device::ShouldBoostClocks() const { } bool Device::HasTimelineSemaphore() const { - if (GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || - GetDriverID() == VK_DRIVER_ID_MESA_TURNIP) { - // Timeline semaphores do not work properly on all Qualcomm drivers. - // They generally work properly with Turnip drivers, but are problematic on some devices - // (e.g. ZTE handsets with Snapdragon 870). - return false; - } return features.timeline_semaphore.timelineSemaphore; } From b066a6ffa08787fcd94e219a4820a5ea3c28cc1f Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 16:18:01 -0400 Subject: [PATCH 25/34] Changing checks in HostMemor for virtual memory mapping --- src/common/host_memory.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 5400b97018..ff7859a1f7 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -730,7 +730,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, ASSERT(virtual_offset % PageAlignment == 0); ASSERT(host_offset % PageAlignment == 0); ASSERT(length % PageAlignment == 0); - ASSERT(virtual_offset + length <= virtual_size); + if (impl && virtual_base) { + ASSERT(virtual_offset + length <= virtual_size); + } ASSERT(host_offset + length <= backing_size); if (length == 0 || !virtual_base || !impl) { return; @@ -741,7 +743,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { ASSERT(virtual_offset % PageAlignment == 0); ASSERT(length % PageAlignment == 0); - ASSERT(virtual_offset + length <= virtual_size); + if (impl && virtual_base) { + ASSERT(virtual_offset + length <= virtual_size); + } if (length == 0 || !virtual_base || !impl) { return; } @@ -751,7 +755,9 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) { ASSERT(virtual_offset % PageAlignment == 0); ASSERT(length % PageAlignment == 0); - ASSERT(virtual_offset + length <= virtual_size); + if (impl && virtual_base) { + ASSERT(virtual_offset + length <= virtual_size); + } if (length == 0 || !virtual_base || !impl) { return; } From a3f9d3b59c1bb08b85de59a30ad138340ffd4a41 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 19:54:03 -0400 Subject: [PATCH 26/34] [gl. vk] Extending impl for atomic floats operations --- .../backend/glsl/glsl_emit_context.cpp | 7 ++-- src/shader_recompiler/profile.h | 3 ++ src/video_core/renderer_opengl/gl_device.cpp | 3 ++ src/video_core/renderer_opengl/gl_device.h | 15 ++++++++ .../renderer_opengl/gl_shader_cache.cpp | 3 ++ .../vulkan_common/vulkan_device.cpp | 37 +++++++++++++++++++ src/video_core/vulkan_common/vulkan_device.h | 6 +++ 7 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 2bf7f4de13..579b6ceeeb 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp @@ -380,13 +380,14 @@ void EmitContext::SetupExtensions() { if (info.uses_int64 && profile.support_int64) { header += "#extension GL_ARB_gpu_shader_int64 : enable\n"; } - if (info.uses_int64_bit_atomics) { + if (info.uses_int64_bit_atomics && profile.support_gl_shader_atomic_int64) { header += "#extension GL_NV_shader_atomic_int64 : enable\n"; } - if (info.uses_atomic_f32_add) { + if (info.uses_atomic_f32_add && profile.support_gl_shader_atomic_float) { header += "#extension GL_NV_shader_atomic_float : enable\n"; } - if (info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) { + if ((info.uses_atomic_f16x2_add || info.uses_atomic_f16x2_min || info.uses_atomic_f16x2_max) && + profile.support_gl_shader_atomic_fp16_vector) { header += "#extension GL_NV_shader_atomic_fp16_vector : enable\n"; } if (info.uses_fp16) { diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 90e46bb1ba..c6851959f0 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -38,6 +38,9 @@ struct Profile { bool support_gl_nv_gpu_shader_5{}; bool support_gl_amd_gpu_shader_half_float{}; bool support_gl_texture_shadow_lod{}; + bool support_gl_shader_atomic_float{}; + bool support_gl_shader_atomic_fp16_vector{}; + bool support_gl_shader_atomic_int64{}; bool support_gl_warp_intrinsics{}; bool support_gl_variable_aoffi{}; bool support_gl_sparse_textures{}; diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index f5bf995d00..131808c25a 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -225,6 +225,9 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float; has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2; has_draw_texture = GLAD_GL_NV_draw_texture; + has_shader_atomic_float = GLAD_GL_NV_shader_atomic_float; + has_shader_atomic_fp16_vector = GLAD_GL_NV_shader_atomic_fp16_vector; + has_shader_atomic_int64 = GLAD_GL_NV_shader_atomic_int64; warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel; need_fastmath_off = is_nvidia; can_report_memory = GLAD_GL_NVX_gpu_memory_info; diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index a5a6bbbba7..a25daba8eb 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -152,6 +152,18 @@ public: return has_draw_texture; } + bool HasShaderAtomicFloat() const { + return has_shader_atomic_float; + } + + bool HasShaderAtomicFp16Vector() const { + return has_shader_atomic_fp16_vector; + } + + bool HasShaderAtomicInt64() const { + return has_shader_atomic_int64; + } + bool IsWarpSizePotentiallyLargerThanGuest() const { return warp_size_potentially_larger_than_guest; } @@ -235,6 +247,9 @@ private: bool has_amd_shader_half_float{}; bool has_sparse_texture_2{}; bool has_draw_texture{}; + bool has_shader_atomic_float{}; + bool has_shader_atomic_fp16_vector{}; + bool has_shader_atomic_int64{}; bool warp_size_potentially_larger_than_guest{}; bool need_fastmath_off{}; bool has_cbuf_ftou_bug{}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 45f729698e..881c906b79 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -215,6 +215,9 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, .support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(), .support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(), .support_gl_texture_shadow_lod = device.HasTextureShadowLod(), + .support_gl_shader_atomic_float = device.HasShaderAtomicFloat(), + .support_gl_shader_atomic_fp16_vector = device.HasShaderAtomicFp16Vector(), + .support_gl_shader_atomic_int64 = device.HasShaderAtomicInt64(), .support_gl_warp_intrinsics = false, .support_gl_variable_aoffi = device.HasVariableAoffi(), .support_gl_sparse_textures = device.HasSparseTexture2(), diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 5d59fdbc4d..44cd114bd3 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1304,6 +1304,43 @@ void Device::RemoveUnsuitableExtensions() { VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); } + // VK_KHR_shader_float16_int8 + const bool float16_int8_requested = extensions.shader_float16_int8; + const bool float16_int8_usable = + features.shader_float16_int8.shaderFloat16 || features.shader_float16_int8.shaderInt8; + if (float16_int8_requested && !float16_int8_usable) { + LOG_WARNING(Render_Vulkan, + "Disabling VK_KHR_shader_float16_int8 — no shaderFloat16/shaderInt8 features reported"); + } + extensions.shader_float16_int8 = float16_int8_requested && float16_int8_usable; + RemoveExtensionFeatureIfUnsuitable(float16_int8_usable, features.shader_float16_int8, + VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + + // VK_EXT_shader_atomic_float + const bool atomic_float_requested = extensions.shader_atomic_float; + const auto& atomic_float_features = features.shader_atomic_float; + const bool supports_buffer_f32 = atomic_float_features.shaderBufferFloat32Atomics || + atomic_float_features.shaderBufferFloat32AtomicAdd; + const bool supports_shared_f32 = atomic_float_features.shaderSharedFloat32Atomics || + atomic_float_features.shaderSharedFloat32AtomicAdd; + const bool supports_image_f32 = atomic_float_features.shaderImageFloat32Atomics || + atomic_float_features.shaderImageFloat32AtomicAdd; + const bool supports_sparse_f32 = atomic_float_features.sparseImageFloat32Atomics || + atomic_float_features.sparseImageFloat32AtomicAdd; + const bool supports_buffer_f64 = atomic_float_features.shaderBufferFloat64Atomics || + atomic_float_features.shaderBufferFloat64AtomicAdd; + const bool supports_shared_f64 = atomic_float_features.shaderSharedFloat64Atomics || + atomic_float_features.shaderSharedFloat64AtomicAdd; + const bool atomic_float_usable = supports_buffer_f32 || supports_shared_f32 || supports_image_f32 || + supports_sparse_f32 || supports_buffer_f64 || supports_shared_f64; + if (atomic_float_requested && !atomic_float_usable) { + LOG_WARNING(Render_Vulkan, + "Disabling VK_EXT_shader_atomic_float — no usable atomic float feature bits reported"); + } + extensions.shader_atomic_float = atomic_float_requested && atomic_float_usable; + RemoveExtensionFeatureIfUnsuitable(atomic_float_usable, features.shader_atomic_float, + VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME); + // VK_KHR_shader_atomic_int64 extensions.shader_atomic_int64 = features.shader_atomic_int64.shaderBufferInt64Atomics && features.shader_atomic_int64.shaderSharedInt64Atomics; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 71b431c9fc..a6f7d5fb07 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -49,6 +49,7 @@ VK_DEFINE_HANDLE(VmaAllocator) FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \ FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \ FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \ + FEATURE(EXT, ShaderAtomicFloat, SHADER_ATOMIC_FLOAT, shader_atomic_float) \ FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \ FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \ FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \ @@ -611,6 +612,11 @@ public: return extensions.shader_atomic_int64; } + /// Returns true if the device supports VK_EXT_shader_atomic_float. + bool IsExtShaderAtomicFloatSupported() const { + return extensions.shader_atomic_float; + } + bool IsExtConditionalRendering() const { return extensions.conditional_rendering; } From 6b05c164a15b299d21f5703f2d88ca40f94c9094 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 19:58:57 -0400 Subject: [PATCH 27/34] Fixing missing headers --- src/shader_recompiler/profile.h | 3 +++ src/video_core/renderer_opengl/gl_device.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index c6851959f0..48db64e162 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.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 diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index a25daba8eb..96a84bb874 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From 7f1369f9a836d0f7a384b18f4112fb604a8da48d Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 9 Nov 2025 23:14:51 -0400 Subject: [PATCH 28/34] [shader_recompiler, spir-v] Adding INT64 emulation path --- .../backend/spirv/emit_spirv_memory.cpp | 12 +- .../backend/spirv/spirv_emit_context.cpp | 195 ++++++++++++++++-- .../backend/spirv/spirv_emit_context.h | 9 + 3 files changed, 192 insertions(+), 24 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp index bdcbccfde9..0ac7086995 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp @@ -92,7 +92,7 @@ void EmitLoadGlobalS16(EmitContext&) { } Id EmitLoadGlobal32(EmitContext& ctx, Id address) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { return ctx.OpFunctionCall(ctx.U32[1], ctx.load_global_func_u32, address); } LOG_WARNING(Shader_SPIRV, "Int64 not supported, ignoring memory operation"); @@ -100,7 +100,7 @@ Id EmitLoadGlobal32(EmitContext& ctx, Id address) { } Id EmitLoadGlobal64(EmitContext& ctx, Id address) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { return ctx.OpFunctionCall(ctx.U32[2], ctx.load_global_func_u32x2, address); } LOG_WARNING(Shader_SPIRV, "Int64 not supported, ignoring memory operation"); @@ -108,7 +108,7 @@ Id EmitLoadGlobal64(EmitContext& ctx, Id address) { } Id EmitLoadGlobal128(EmitContext& ctx, Id address) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { return ctx.OpFunctionCall(ctx.U32[4], ctx.load_global_func_u32x4, address); } LOG_WARNING(Shader_SPIRV, "Int64 not supported, ignoring memory operation"); @@ -132,7 +132,7 @@ void EmitWriteGlobalS16(EmitContext&) { } void EmitWriteGlobal32(EmitContext& ctx, Id address, Id value) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32, address, value); return; } @@ -140,7 +140,7 @@ void EmitWriteGlobal32(EmitContext& ctx, Id address, Id value) { } void EmitWriteGlobal64(EmitContext& ctx, Id address, Id value) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32x2, address, value); return; } @@ -148,7 +148,7 @@ void EmitWriteGlobal64(EmitContext& ctx, Id address, Id value) { } void EmitWriteGlobal128(EmitContext& ctx, Id address, Id value) { - if (ctx.profile.support_int64) { + if (ctx.SupportsNativeInt64() || ctx.UsesInt64Emulation()) { ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32x4, address, value); return; } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 4c3e101433..c4b72b5888 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -460,9 +460,10 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_, IR::Program& program, Bindings& bindings) - : Sirit::Module(profile_.supported_spirv), profile{profile_}, runtime_info{runtime_info_}, - stage{program.stage}, texture_rescaling_index{bindings.texture_scaling_index}, - image_rescaling_index{bindings.image_scaling_index} { + : Sirit::Module(profile_.supported_spirv), profile{profile_}, runtime_info{runtime_info_}, + stage{program.stage}, emulate_int64{program.info.uses_int64 && !profile.support_int64}, + texture_rescaling_index{bindings.texture_scaling_index}, + image_rescaling_index{bindings.image_scaling_index} { const bool is_unified{profile.unified_descriptor_binding}; u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer}; u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer}; @@ -932,11 +933,163 @@ void EmitContext::DefineWriteStorageCasLoopFunction(const Info& info) { } void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { - if (!info.uses_global_memory || !profile.support_int64) { + if (!info.uses_global_memory) { return; } using DefPtr = Id StorageDefinitions::*; const Id zero{u32_zero_value}; + + if (SupportsNativeInt64()) { + const auto define_body{[&](DefPtr ssbo_member, Id addr, Id element_pointer, u32 shift, + auto&& callback) { + AddLabel(); + const size_t num_buffers{info.storage_buffers_descriptors.size()}; + for (size_t index = 0; index < num_buffers; ++index) { + if (!info.nvn_buffer_used[index]) { + continue; + } + const auto& ssbo{info.storage_buffers_descriptors[index]}; + const Id ssbo_addr_cbuf_offset{Const(ssbo.cbuf_offset / 8)}; + const Id ssbo_size_cbuf_offset{Const(ssbo.cbuf_offset / 4 + 2)}; + const Id ssbo_addr_pointer{OpAccessChain( + uniform_types.U32x2, cbufs[ssbo.cbuf_index].U32x2, zero, + ssbo_addr_cbuf_offset)}; + const Id ssbo_size_pointer{OpAccessChain( + uniform_types.U32, cbufs[ssbo.cbuf_index].U32, zero, ssbo_size_cbuf_offset)}; + + const u64 ssbo_align_mask{~(profile.min_ssbo_alignment - 1U)}; + const Id unaligned_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; + const Id ssbo_addr{OpBitwiseAnd(U64, unaligned_addr, Constant(U64, ssbo_align_mask))}; + const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; + const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; + const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), + OpULessThan(U1, addr, ssbo_end))}; + const Id then_label{OpLabel()}; + const Id else_label{OpLabel()}; + OpSelectionMerge(else_label, spv::SelectionControlMask::MaskNone); + OpBranchConditional(cond, then_label, else_label); + AddLabel(then_label); + const Id ssbo_id{ssbos[index].*ssbo_member}; + const Id ssbo_offset{OpUConvert(U32[1], OpISub(U64, addr, ssbo_addr))}; + const Id ssbo_index{OpShiftRightLogical(U32[1], ssbo_offset, Const(shift))}; + const Id ssbo_pointer{OpAccessChain(element_pointer, ssbo_id, zero, ssbo_index)}; + callback(ssbo_pointer); + AddLabel(else_label); + } + }}; + const auto define_load{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { + const Id function_type{TypeFunction(type, U64)}; + const Id func_id{OpFunction(type, spv::FunctionControlMask::MaskNone, function_type)}; + const Id addr{OpFunctionParameter(U64)}; + define_body(ssbo_member, addr, element_pointer, shift, + [&](Id ssbo_pointer) { OpReturnValue(OpLoad(type, ssbo_pointer)); }); + OpReturnValue(ConstantNull(type)); + OpFunctionEnd(); + return func_id; + }}; + const auto define_write{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { + const Id function_type{TypeFunction(void_id, U64, type)}; + const Id func_id{ + OpFunction(void_id, spv::FunctionControlMask::MaskNone, function_type)}; + const Id addr{OpFunctionParameter(U64)}; + const Id data{OpFunctionParameter(type)}; + define_body(ssbo_member, addr, element_pointer, shift, [&](Id ssbo_pointer) { + OpStore(ssbo_pointer, data); + OpReturn(); + }); + OpReturn(); + OpFunctionEnd(); + return func_id; + }}; + const auto define{ + [&](DefPtr ssbo_member, const StorageTypeDefinition& type_def, Id type, size_t size) { + const Id element_type{type_def.element}; + const u32 shift{static_cast(std::countr_zero(size))}; + const Id load_func{define_load(ssbo_member, element_type, type, shift)}; + const Id write_func{define_write(ssbo_member, element_type, type, shift)}; + return std::make_pair(load_func, write_func); + }}; + std::tie(load_global_func_u32, write_global_func_u32) = + define(&StorageDefinitions::U32, storage_types.U32, U32[1], sizeof(u32)); + std::tie(load_global_func_u32x2, write_global_func_u32x2) = + define(&StorageDefinitions::U32x2, storage_types.U32x2, U32[2], sizeof(u32[2])); + std::tie(load_global_func_u32x4, write_global_func_u32x4) = + define(&StorageDefinitions::U32x4, storage_types.U32x4, U32[4], sizeof(u32[4])); + return; + } + + if (!UsesInt64Emulation()) { + return; + } + + const auto make_pair = [&](Id lo, Id hi) { + return OpCompositeConstruct(U32[2], lo, hi); + }; + const auto split_pair = [&](Id value) { + return std::array{OpCompositeExtract(U32[1], value, 0U), + OpCompositeExtract(U32[1], value, 1U)}; + }; + const auto bool_to_u32 = [&](Id predicate) { + return OpSelect(U32[1], predicate, Const(1u), zero); + }; + const auto and_pair = [&](Id value, Id mask) { + const auto value_parts{split_pair(value)}; + const auto mask_parts{split_pair(mask)}; + return make_pair(OpBitwiseAnd(U32[1], value_parts[0], mask_parts[0]), + OpBitwiseAnd(U32[1], value_parts[1], mask_parts[1])); + }; + const auto add_pair = [&](Id lhs, Id rhs) { + const auto lhs_parts{split_pair(lhs)}; + const auto rhs_parts{split_pair(rhs)}; + const Id sum_lo{OpIAdd(U32[1], lhs_parts[0], rhs_parts[0])}; + const Id carry{OpULessThan(U1, sum_lo, lhs_parts[0])}; + Id sum_hi{OpIAdd(U32[1], lhs_parts[1], rhs_parts[1])}; + sum_hi = OpIAdd(U32[1], sum_hi, bool_to_u32(carry)); + return make_pair(sum_lo, sum_hi); + }; + const auto sub_pair = [&](Id lhs, Id rhs) { + const auto lhs_parts{split_pair(lhs)}; + const auto rhs_parts{split_pair(rhs)}; + const Id borrow{OpULessThan(U1, lhs_parts[0], rhs_parts[0])}; + const Id diff_lo{OpISub(U32[1], lhs_parts[0], rhs_parts[0])}; + Id diff_hi{OpISub(U32[1], lhs_parts[1], rhs_parts[1])}; + diff_hi = OpISub(U32[1], diff_hi, bool_to_u32(borrow)); + return make_pair(diff_lo, diff_hi); + }; + const auto shift_right_pair = [&](Id value, u32 shift) { + if (shift == 0) { + return value; + } + const auto parts{split_pair(value)}; + const Id shift_id{Const(shift)}; + const Id high_shifted{OpShiftRightLogical(U32[1], parts[1], shift_id)}; + Id low_shifted{OpShiftRightLogical(U32[1], parts[0], shift_id)}; + const Id carry_bits{OpShiftLeftLogical(U32[1], parts[1], Const(32u - shift))}; + low_shifted = OpBitwiseOr(U32[1], low_shifted, carry_bits); + return make_pair(low_shifted, high_shifted); + }; + const auto greater_equal_pair = [&](Id lhs, Id rhs) { + const auto lhs_parts{split_pair(lhs)}; + const auto rhs_parts{split_pair(rhs)}; + const Id hi_gt{OpUGreaterThan(U1, lhs_parts[1], rhs_parts[1])}; + const Id hi_eq{OpIEqual(U1, lhs_parts[1], rhs_parts[1])}; + const Id lo_ge{OpUGreaterThanEqual(U1, lhs_parts[0], rhs_parts[0])}; + return OpLogicalOr(U1, hi_gt, OpLogicalAnd(U1, hi_eq, lo_ge)); + }; + const auto less_than_pair = [&](Id lhs, Id rhs) { + const auto lhs_parts{split_pair(lhs)}; + const auto rhs_parts{split_pair(rhs)}; + const Id hi_lt{OpULessThan(U1, lhs_parts[1], rhs_parts[1])}; + const Id hi_eq{OpIEqual(U1, lhs_parts[1], rhs_parts[1])}; + const Id lo_lt{OpULessThan(U1, lhs_parts[0], rhs_parts[0])}; + return OpLogicalOr(U1, hi_lt, OpLogicalAnd(U1, hi_eq, lo_lt)); + }; + + const u64 ssbo_align_mask_value{~(profile.min_ssbo_alignment - 1U)}; + const Id ssbo_align_mask{ + Const(static_cast(ssbo_align_mask_value & 0xFFFFFFFFu), + static_cast(ssbo_align_mask_value >> 32))}; + const auto define_body{[&](DefPtr ssbo_member, Id addr, Id element_pointer, u32 shift, auto&& callback) { AddLabel(); @@ -953,40 +1106,44 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { const Id ssbo_size_pointer{OpAccessChain(uniform_types.U32, cbufs[ssbo.cbuf_index].U32, zero, ssbo_size_cbuf_offset)}; - const u64 ssbo_align_mask{~(profile.min_ssbo_alignment - 1U)}; - const Id unaligned_addr{OpBitcast(U64, OpLoad(U32[2], ssbo_addr_pointer))}; - const Id ssbo_addr{OpBitwiseAnd(U64, unaligned_addr, Constant(U64, ssbo_align_mask))}; - const Id ssbo_size{OpUConvert(U64, OpLoad(U32[1], ssbo_size_pointer))}; - const Id ssbo_end{OpIAdd(U64, ssbo_addr, ssbo_size)}; - const Id cond{OpLogicalAnd(U1, OpUGreaterThanEqual(U1, addr, ssbo_addr), - OpULessThan(U1, addr, ssbo_end))}; + const Id unaligned_addr_pair{OpLoad(U32[2], ssbo_addr_pointer)}; + const Id ssbo_addr_pair{and_pair(unaligned_addr_pair, ssbo_align_mask)}; + const Id ssbo_size_value{OpLoad(U32[1], ssbo_size_pointer)}; + const Id ssbo_size_pair{make_pair(ssbo_size_value, zero)}; + const Id ssbo_end_pair{add_pair(ssbo_addr_pair, ssbo_size_pair)}; + const Id cond{OpLogicalAnd(U1, greater_equal_pair(addr, ssbo_addr_pair), + less_than_pair(addr, ssbo_end_pair))}; const Id then_label{OpLabel()}; const Id else_label{OpLabel()}; OpSelectionMerge(else_label, spv::SelectionControlMask::MaskNone); OpBranchConditional(cond, then_label, else_label); AddLabel(then_label); const Id ssbo_id{ssbos[index].*ssbo_member}; - const Id ssbo_offset{OpUConvert(U32[1], OpISub(U64, addr, ssbo_addr))}; - const Id ssbo_index{OpShiftRightLogical(U32[1], ssbo_offset, Const(shift))}; + const Id ssbo_offset_pair{sub_pair(addr, ssbo_addr_pair)}; + const Id ssbo_index_pair{shift_right_pair(ssbo_offset_pair, shift)}; + const Id ssbo_index{OpCompositeExtract(U32[1], ssbo_index_pair, 0U)}; const Id ssbo_pointer{OpAccessChain(element_pointer, ssbo_id, zero, ssbo_index)}; callback(ssbo_pointer); AddLabel(else_label); } }}; + const auto define_load{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { - const Id function_type{TypeFunction(type, U64)}; + const Id function_type{TypeFunction(type, U32[2])}; const Id func_id{OpFunction(type, spv::FunctionControlMask::MaskNone, function_type)}; - const Id addr{OpFunctionParameter(U64)}; + const Id addr{OpFunctionParameter(U32[2])}; define_body(ssbo_member, addr, element_pointer, shift, [&](Id ssbo_pointer) { OpReturnValue(OpLoad(type, ssbo_pointer)); }); OpReturnValue(ConstantNull(type)); OpFunctionEnd(); return func_id; }}; + const auto define_write{[&](DefPtr ssbo_member, Id element_pointer, Id type, u32 shift) { - const Id function_type{TypeFunction(void_id, U64, type)}; - const Id func_id{OpFunction(void_id, spv::FunctionControlMask::MaskNone, function_type)}; - const Id addr{OpFunctionParameter(U64)}; + const Id function_type{TypeFunction(void_id, U32[2], type)}; + const Id func_id{ + OpFunction(void_id, spv::FunctionControlMask::MaskNone, function_type)}; + const Id addr{OpFunctionParameter(U32[2])}; const Id data{OpFunctionParameter(type)}; define_body(ssbo_member, addr, element_pointer, shift, [&](Id ssbo_pointer) { OpStore(ssbo_pointer, data); @@ -996,6 +1153,7 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { OpFunctionEnd(); return func_id; }}; + const auto define{ [&](DefPtr ssbo_member, const StorageTypeDefinition& type_def, Id type, size_t size) { const Id element_type{type_def.element}; @@ -1004,6 +1162,7 @@ void EmitContext::DefineGlobalMemoryFunctions(const Info& info) { const Id write_func{define_write(ssbo_member, element_type, type, shift)}; return std::make_pair(load_func, write_func); }}; + std::tie(load_global_func_u32, write_global_func_u32) = define(&StorageDefinitions::U32, storage_types.U32, U32[1], sizeof(u32)); std::tie(load_global_func_u32x2, write_global_func_u32x2) = diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 66cdb1d3db..2dbeeb0911 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -207,6 +207,15 @@ public: const Profile& profile; const RuntimeInfo& runtime_info; Stage stage{}; + const bool emulate_int64{}; + + bool SupportsNativeInt64() const { + return profile.support_int64; + } + + bool UsesInt64Emulation() const { + return emulate_int64; + } Id void_id{}; Id U1{}; From c28ae059e8bf38f3683c238a74af9495cf6e91b0 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 10 Nov 2025 00:22:08 -0400 Subject: [PATCH 29/34] [gl, vk, texture cache] Attempt to get correct MSAA image upload and download --- .../renderer_opengl/gl_texture_cache.h | 4 ++ .../renderer_vulkan/vk_texture_cache.h | 4 ++ src/video_core/texture_cache/image_base.cpp | 4 -- src/video_core/texture_cache/texture_cache.h | 50 ++++++++++++++++--- .../texture_cache/texture_cache_base.h | 2 + 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index d4165d8e4d..a673c4feef 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -97,6 +97,10 @@ public: return true; } + bool CanDownloadMSAA() const noexcept { + return true; + } + void CopyImage(Image& dst, Image& src, std::span copies); void CopyImageMSAA(Image& dst, Image& src, std::span copies); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index cd11cc8fc7..17db56bb43 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -85,6 +85,10 @@ public: return msaa_copy_pass.operator bool(); } + bool CanDownloadMSAA() const noexcept { + return msaa_copy_pass.operator bool(); + } + void AccelerateImageUpload(Image&, const StagingBufferRef&, std::span); diff --git a/src/video_core/texture_cache/image_base.cpp b/src/video_core/texture_cache/image_base.cpp index 077df28fb3..93abad3c5c 100644 --- a/src/video_core/texture_cache/image_base.cpp +++ b/src/video_core/texture_cache/image_base.cpp @@ -131,10 +131,6 @@ bool ImageBase::IsSafeDownload() const noexcept { if (True(flags & ImageFlagBits::CpuModified)) { return false; } - if (info.num_samples > 1) { - LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); - return false; - } return true; } diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 8ac025f1df..f1ac55555c 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -101,8 +101,12 @@ void TextureCache

::RunGarbageCollector() { if (!aggressive_mode && True(image.flags & ImageFlagBits::CostlyLoad)) { return false; } - const bool must_download = - image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap); + const bool supports_msaa_download = HasMsaaDownloadSupport(image.info); + if (!supports_msaa_download && image.info.num_samples > 1) { + LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); + } + const bool must_download = supports_msaa_download && image.IsSafeDownload() && + False(image.flags & ImageFlagBits::BadOverlap); if (!high_priority_mode && must_download) { return false; } @@ -548,10 +552,14 @@ void TextureCache

::WriteMemory(DAddr cpu_addr, size_t size) { template void TextureCache

::DownloadMemory(DAddr cpu_addr, size_t size) { boost::container::small_vector images; - ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { + ForEachImageInRegion(cpu_addr, size, [this, &images](ImageId image_id, ImageBase& image) { if (!image.IsSafeDownload()) { return; } + if (!HasMsaaDownloadSupport(image.info)) { + LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); + return; + } image.flags &= ~ImageFlagBits::GpuModified; images.push_back(image_id); }); @@ -930,6 +938,17 @@ ImageId TextureCache

::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo return NULL_IMAGE_ID; } auto& image = slot_images[dst_id]; + if (image.info.num_samples > 1) { + if (is_upload) { + if (!HasMsaaUploadSupport(image.info)) { + return NULL_IMAGE_ID; + } + } else { + if (!HasMsaaDownloadSupport(image.info)) { + return NULL_IMAGE_ID; + } + } + } if (False(image.flags & ImageFlagBits::GpuModified)) { // No need to waste time on an image that's synced with guest return NULL_IMAGE_ID; @@ -1056,7 +1075,7 @@ void TextureCache

::RefreshContents(Image& image, ImageId image_id) { image.flags &= ~ImageFlagBits::CpuModified; TrackImage(image, image_id); - if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) { + if (!HasMsaaUploadSupport(image.info)) { LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); runtime.TransitionImageLayout(image); return; @@ -1274,6 +1293,16 @@ u64 TextureCache

::GetScaledImageSizeBytes(const ImageBase& image) { return fitted_size; } +template +bool TextureCache

::HasMsaaUploadSupport(const ImageInfo& info) const noexcept { + return info.num_samples <= 1 || runtime.CanUploadMSAA(); +} + +template +bool TextureCache

::HasMsaaDownloadSupport(const ImageInfo& info) const noexcept { + return info.num_samples <= 1 || runtime.CanDownloadMSAA(); +} + template void TextureCache

::QueueAsyncDecode(Image& image, ImageId image_id) { UNIMPLEMENTED_IF(False(image.flags & ImageFlagBits::Converted)); @@ -1575,6 +1604,10 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA for (const auto& copy_object : join_copies_to_do) { Image& overlap = slot_images[copy_object.id]; if (copy_object.is_alias) { + if (!HasMsaaDownloadSupport(overlap.info)) { + LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); + continue; + } if (!overlap.IsSafeDownload()) { continue; } @@ -2491,8 +2524,13 @@ void TextureCache

::BindRenderTarget(ImageViewId* old_id, ImageViewId new_id) if (new_id) { const ImageViewBase& old_view = slot_image_views[new_id]; if (True(old_view.flags & ImageViewFlagBits::PreemtiveDownload)) { - const PendingDownload new_download{true, 0, old_view.image_id}; - uncommitted_downloads.emplace_back(new_download); + const ImageBase& image = slot_images[old_view.image_id]; + if (!HasMsaaDownloadSupport(image.info)) { + LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); + } else { + const PendingDownload new_download{true, 0, old_view.image_id}; + uncommitted_downloads.emplace_back(new_download); + } } } *old_id = new_id; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 01a9a6a3f1..2435f6fa75 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -426,6 +426,8 @@ private: bool ScaleUp(Image& image); bool ScaleDown(Image& image); u64 GetScaledImageSizeBytes(const ImageBase& image); + [[nodiscard]] bool HasMsaaUploadSupport(const ImageInfo& info) const noexcept; + [[nodiscard]] bool HasMsaaDownloadSupport(const ImageInfo& info) const noexcept; void QueueAsyncDecode(Image& image, ImageId image_id); void TickAsyncDecode(); From 7f8a507b795eadb3f3457406fb6548fbd2dd0b8d Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 10 Nov 2025 00:27:38 -0400 Subject: [PATCH 30/34] Adding missing headers --- src/video_core/renderer_opengl/gl_texture_cache.h | 1 + src/video_core/renderer_vulkan/vk_texture_cache.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index a673c4feef..7833de54a5 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 17db56bb43..437d082c4c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later From aaaa7c76013f7bec9a0543e01d157b4c0bebf2e3 Mon Sep 17 00:00:00 2001 From: PavelBARABANOV Date: Mon, 10 Nov 2025 18:52:31 +0300 Subject: [PATCH 31/34] Revert "TEST: Enabling TimelineSemaphores for QCOM and Turnip" This reverts commit 3cd33fce44cf0412d4f76f3cf601b73b881662cb. --- src/video_core/vulkan_common/vulkan_device.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 44cd114bd3..ddaca2669c 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1017,6 +1017,13 @@ bool Device::ShouldBoostClocks() const { } bool Device::HasTimelineSemaphore() const { + if (GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || + GetDriverID() == VK_DRIVER_ID_MESA_TURNIP) { + // Timeline semaphores do not work properly on all Qualcomm drivers. + // They generally work properly with Turnip drivers, but are problematic on some devices + // (e.g. ZTE handsets with Snapdragon 870). + return false; + } return features.timeline_semaphore.timelineSemaphore; } From 9d9530efe053f38bd734850a1aa6b9c0fd668676 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 13 Nov 2025 18:42:49 -0400 Subject: [PATCH 32/34] [shader_recompiler, spir-v] verifying int64 emulation path activation --- .../backend/spirv/emit_spirv_memory.cpp | 3 +++ .../backend/spirv/spirv_emit_context.cpp | 6 ++++- .../backend/spirv/spirv_emit_context.h | 3 +++ .../global_memory_to_storage_buffer_pass.cpp | 27 +++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp index 0ac7086995..88b3717498 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp @@ -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 diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index c4b72b5888..ccaa8da9e0 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -461,7 +461,11 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_, IR::Program& program, Bindings& bindings) : Sirit::Module(profile_.supported_spirv), profile{profile_}, runtime_info{runtime_info_}, - stage{program.stage}, emulate_int64{program.info.uses_int64 && !profile.support_int64}, + stage{program.stage}, + // Enable int64 emulation if host lacks int64 but we either use int64 ops + // or we need 64-bit addressing for global memory operations. + emulate_int64{!profile.support_int64 && + (program.info.uses_int64 || program.info.uses_global_memory)}, texture_rescaling_index{bindings.texture_scaling_index}, image_rescaling_index{bindings.image_scaling_index} { const bool is_unified{profile.unified_descriptor_binding}; diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 2dbeeb0911..c0c28e4e3f 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.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 diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 2d4feca02c..14ada93ac2 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -293,6 +296,14 @@ std::optional TrackLowAddress(IR::Inst* inst) { } // This address is expected to either be a PackUint2x32, a IAdd64, or a CompositeConstructU32x2 IR::Inst* addr_inst{addr.InstRecursive()}; + // Unwrap Identity ops introduced by lowerings (e.g., PackUint2x32 -> Identity) + while (addr_inst->GetOpcode() == IR::Opcode::Identity) { + const IR::Value id_arg{addr_inst->Arg(0)}; + if (id_arg.IsImmediate()) { + return std::nullopt; + } + addr_inst = id_arg.InstRecursive(); + } s32 imm_offset{0}; if (addr_inst->GetOpcode() == IR::Opcode::IAdd64) { // If it's an IAdd64, get the immediate offset it is applying and grab the address @@ -308,6 +319,14 @@ std::optional TrackLowAddress(IR::Inst* inst) { return std::nullopt; } addr_inst = iadd_addr.InstRecursive(); + // Unwrap Identity again if present after folding IAdd64 + while (addr_inst->GetOpcode() == IR::Opcode::Identity) { + const IR::Value id_arg{addr_inst->Arg(0)}; + if (id_arg.IsImmediate()) { + return std::nullopt; + } + addr_inst = id_arg.InstRecursive(); + } } // With IAdd64 handled, now PackUint2x32 is expected if (addr_inst->GetOpcode() == IR::Opcode::PackUint2x32) { @@ -317,6 +336,14 @@ std::optional TrackLowAddress(IR::Inst* inst) { return std::nullopt; } addr_inst = vector.InstRecursive(); + // Unwrap Identity that may replace PackUint2x32 + while (addr_inst->GetOpcode() == IR::Opcode::Identity) { + const IR::Value id_arg{addr_inst->Arg(0)}; + if (id_arg.IsImmediate()) { + return std::nullopt; + } + addr_inst = id_arg.InstRecursive(); + } } // The vector is expected to be a CompositeConstructU32x2 if (addr_inst->GetOpcode() != IR::Opcode::CompositeConstructU32x2) { From 3228cffd2345848d21ff10162ef21dcd11c1a765 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 13 Nov 2025 20:37:47 -0400 Subject: [PATCH 33/34] [texture_cache, gl, vk] Initial implementation for HDR + MSAA detection on QCOM drivers. --- .../renderer_opengl/gl_texture_cache.h | 2 + .../renderer_vulkan/maxwell_to_vk.cpp | 2 +- .../renderer_vulkan/vk_texture_cache.cpp | 18 +++++ .../renderer_vulkan/vk_texture_cache.h | 2 + .../vulkan_common/vulkan_device.cpp | 70 +++++++++++++++++-- 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 7833de54a5..695ca9833b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -1,4 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index a7a878f18c..24da3591ec 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -214,7 +214,7 @@ struct FormatTuple { {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5_UNORM {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB - {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9_FLOAT + {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, Attachable | Storage}, // E5B9G9R9_FLOAT // Depth formats {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 136a11f78d..1b0619afad 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1549,6 +1549,24 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32); } } + + // Proactive warning for problematic HDR format + MSAA combinations on Android + // These combinations commonly cause texture flickering/black screens across multiple game engines + // Note: MSAA is native Switch rendering technique, cannot be disabled by emulator + if (info.num_samples > 1) { + const auto vk_format = MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, + false, info.format).format; + const bool is_hdr_format = vk_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || + vk_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + + if (is_hdr_format) { + LOG_WARNING(Render_Vulkan, + "Creating MSAA image ({}x samples) with HDR format {} (Maxwell: {}). " + "Driver support may be limited on Android (Qualcomm < 800, Mali pre-maintenance5). " + "Format fallback to RGBA16F should prevent issues.", + info.num_samples, vk_format, info.format); + } + } } Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {} diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 437d082c4c..be4b246b79 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -1,4 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index ddaca2669c..f73365fd97 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -90,6 +90,31 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{ VK_FORMAT_UNDEFINED, }; +// B10G11R11_UFLOAT (R11G11B10 float) is used by Unreal Engine 5 for HDR textures +// Some Android drivers (Qualcomm pre-800, Mali pre-maintenance5) have issues with this format +// when used with MSAA or certain tiling modes, causing texture flickering/black screens +constexpr std::array B10G11R11_UFLOAT_PACK32{ + VK_FORMAT_R16G16B16A16_SFLOAT, // Fallback: RGBA16F (more memory, but widely supported) + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, // Alternative: E5B9G9R9 shared exponent format + VK_FORMAT_UNDEFINED, +}; + +// E5B9G9R9_UFLOAT (shared exponent RGB9E5) used by various engines (Unity, custom engines) +// Also problematic on some Android drivers, especially with MSAA and as render target +constexpr std::array E5B9G9R9_UFLOAT_PACK32{ + VK_FORMAT_R16G16B16A16_SFLOAT, // Fallback: RGBA16F (safest option) + VK_FORMAT_B10G11R11_UFLOAT_PACK32, // Alternative: might work if E5B9G9R9 fails + VK_FORMAT_UNDEFINED, +}; + +/// Helper function to detect HDR formats that commonly fail with MSAA on some Android drivers +[[nodiscard]] constexpr bool IsProblematicHDRFormat(VkFormat format) { + // These formats are known to cause texture flickering/black screens across multiple game engines + // when combined with MSAA on certain Android drivers (Qualcomm < 800, Mali pre-maintenance5) + return format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || // UE5, custom engines + format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; // Unity, RE Engine, others +} + } // namespace Alternatives template @@ -122,6 +147,10 @@ constexpr const VkFormat* GetFormatAlternatives(VkFormat format) { return Alternatives::VK_FORMAT_R32G32B32_SFLOAT.data(); case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: return Alternatives::VK_FORMAT_A4B4G4R4_UNORM_PACK16.data(); + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + return Alternatives::B10G11R11_UFLOAT_PACK32.data(); + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return Alternatives::E5B9G9R9_UFLOAT_PACK32.data(); default: return nullptr; } @@ -844,15 +873,33 @@ Device::~Device() { VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, FormatType format_type) const { if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { - return wanted_format; + // CRITICAL FIX: Even if format is "supported", check for STORAGE + HDR + no MSAA support + // Driver may report STORAGE_IMAGE_BIT but shaderStorageImageMultisample=false means + // it will fail at runtime when used with MSAA (CopyImageMSAA silently fails) + const bool requests_storage = (wanted_usage & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; + const bool is_hdr_format = wanted_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || + wanted_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; + + // If driver doesn't support shader storage image with MSAA, and we're requesting storage + // for an HDR format (which will likely be used with MSAA), force fallback + if (requests_storage && is_hdr_format && !features.features.shaderStorageImageMultisample) { + LOG_WARNING(Render_Vulkan, + "Format {} reports STORAGE_IMAGE_BIT but driver doesn't support " + "shaderStorageImageMultisample. Forcing fallback for MSAA compatibility.", + wanted_format); + // Continue to alternatives search below + } else { + return wanted_format; + } } // The wanted format is not supported by hardware, search for alternatives const VkFormat* alternatives = GetFormatAlternatives(wanted_format); if (alternatives == nullptr) { LOG_ERROR(Render_Vulkan, - "Format={} with usage={} and type={} has no defined alternatives and host " - "hardware does not support it", - wanted_format, wanted_usage, format_type); + "Format={} (0x{:X}) with usage={} and type={} has no defined alternatives and host " + "hardware does not support it. Driver: {} Device: {}", + wanted_format, static_cast(wanted_format), wanted_usage, format_type, + GetDriverName(), properties.properties.deviceName); return wanted_format; } @@ -861,9 +908,22 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags if (!IsFormatSupported(alternative, wanted_usage, format_type)) { continue; } - LOG_DEBUG(Render_Vulkan, + // Special logging for HDR formats (common across multiple engines) on problematic drivers + if (wanted_format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) { + LOG_WARNING(Render_Vulkan, + "Emulating B10G11R11_UFLOAT (HDR format: UE5, custom engines) with {} on {}. " + "Native format not supported by driver, using fallback.", + alternative, properties.properties.deviceName); + } else if (wanted_format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) { + LOG_WARNING(Render_Vulkan, + "Emulating E5B9G9R9_UFLOAT (HDR format: Unity, RE Engine) with {} on {}. " + "Native format not supported by driver, using fallback.", + alternative, properties.properties.deviceName); + } else { + LOG_DEBUG(Render_Vulkan, "Emulating format={} with alternative format={} with usage={} and type={}", wanted_format, alternative, wanted_usage, format_type); + } return alternative; } From 6eff1779a2c37e5daaf29190625e2923627d3758 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 13 Nov 2025 21:30:19 -0400 Subject: [PATCH 34/34] Fix building issues --- src/video_core/vulkan_common/vulkan_device.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index f73365fd97..84dfef6c5b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -107,14 +107,6 @@ constexpr std::array E5B9G9R9_UFLOAT_PACK32{ VK_FORMAT_UNDEFINED, }; -/// Helper function to detect HDR formats that commonly fail with MSAA on some Android drivers -[[nodiscard]] constexpr bool IsProblematicHDRFormat(VkFormat format) { - // These formats are known to cause texture flickering/black screens across multiple game engines - // when combined with MSAA on certain Android drivers (Qualcomm < 800, Mali pre-maintenance5) - return format == VK_FORMAT_B10G11R11_UFLOAT_PACK32 || // UE5, custom engines - format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; // Unity, RE Engine, others -} - } // namespace Alternatives template