Compare commits

...

17 Commits

Author SHA1 Message Date
lizzie 2ccf9addc9 2026-09-28 14:38:09
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 14:38:09 +00:00
lizzie 75b3bba0d6 address comments 2026-09-28 11:20:55 +00:00
lizzie d2d426b82b extra fixups for cross compile 2026-09-28 11:20:55 +00:00
lizzie 763248bf9b force rebase 2026-09-28 11:20:55 +00:00
lizzie 0cfb9b5d75 fix pkgconfig stuff 2026-09-28 11:20:55 +00:00
lizzie cd7eb3cfe0 fix debian?? 2026-09-28 11:20:55 +00:00
lizzie d8d2d0fb25 DISABLE FUCKING ICONV 2026-09-28 11:20:55 +00:00
lizzie dfc36bdae7 extra x11 notes 2026-09-28 11:20:54 +00:00
lizzie dd40b7c955 fix x11 not enabling vdpau 2026-09-28 11:20:54 +00:00
lizzie 16ea5f6ab9 fix defined threads 2026-09-28 11:20:54 +00:00
lizzie f40e520869 fx 2026-09-28 11:20:54 +00:00
lizzie 4a9da34dc2 fine apple 2026-09-28 11:20:54 +00:00
lizzie 644dc705df [externals] update ffmpeg to May 16th release, fix externals build
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 11:20:54 +00:00
PavelBARABANOV 815325ccec [loader] add ZBIC (zstd variant) NSO decompression support for Switch 22.0+ (#4482)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
A new NSO compression method was introduced in Switch 22.0.0. This is a
customized variant of zstd and is used when NSO flags have bit 7 set.

Key characteristics:
  - ZSTD_MAGICNUMBER is set to 0x4349425A (b'ZBIC') instead of 0xFD2FB528
  - ZSTD_LEGACY_SUPPORT is set to 0
  - ZSTD_TRACE is set to 1, zstd version used is 1.5.7 (10507)
  - FSE_readNCount is replaced with a BIC (Binary Interpolative Coding)
    version which improves compression of entropy tables significantly

Source: https://switchbrew.org/wiki/22.0.0

Implementation:
  - Detect ZBIC segments via NSO flag bit 7 (NsoFlags_UseZbicCompression)
    and/or ZBIC magic scan in nso.cpp
  - Fall back to LZ4 when ZBIC is not detected or returns unexpected size
  - Handle segment 0 alternate offset (0x100 vs 0x108) for both ZBIC and LZ4

References:
  - Atmosphère loader/strat zstd-zbic integration:
    https://github.com/Atmosphere-NX/Atmosphere/commit/082115187a0509cb6b8a757de639a4e4741b8712
  - nxdumptool ZBIC segment compression support:
    https://github.com/DarkMatterCore/nxdumptool/commit/441e5c0904f29427987433be4eb057a2843d222a
  - STORM_SWITCH ZBIC implementation:
    https://github.com/ReiKatari/STORM_SWITCH/commit/1e09eb82b760aaf340b810031400991c0740c091

Tested with firmware 23.0.0 and ZBIC-compressed NSOs.

Co-authored-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4482
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-27 12:48:45 +02:00
Exverge 37fe911952 [common/sparse_large_vector] correct Win32 exception handler (#4481)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Adds mutex to prevent multiple threads from accessing the vector at the same time and corrects the Windows exception handler to use the correct faulting address used by the exception handler (previously used the instruction address instead of the fault address) and properly shifts the stored values for the handler.
Fixes weird compiler-specific bugs on Windows

Co-authored-by: bruno <protoxseven@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4481
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-26 16:02:35 +02:00
MaranBr f273423b2b [buffer_cache] Simplify GPU fence synchronization and remove GPU buffer readback (#4477)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

This is understood to improve GPU synchronization within the buffer cache in certain edge cases.

GPU Fence Strict is no longer necessary. We now apply the stronger synchronization only in the specific case that actually requires it.

The GPU Buffer Readback has been removed, as it is no longer needed following PR #4473.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4477
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-26 05:01:27 +02:00
MaranBr 87d2f03c39 [hid_core] Code cleanup (#4461)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
This is just a code cleanup. This is no longer necessary due to commit #4457.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4461
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-26 02:21:45 +02:00
33 changed files with 409 additions and 299 deletions
+5
View File
@@ -333,6 +333,11 @@
"repo": "herumi/xbyak", "repo": "herumi/xbyak",
"version": "v7.40.1" "version": "v7.40.1"
}, },
"zbic": {
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
"repo": "kinnay/zbic",
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
},
"zlib": { "zlib": {
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4", "hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
"min_version": "1.2", "min_version": "1.2",
+5
View File
@@ -48,6 +48,11 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb) add_library(stb::headers ALIAS stb)
endif() endif()
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
set(ZBIC_INCLUDE_DIR
"${zbic_SOURCE_DIR}/src"
PARENT_SCOPE)
# ItaniumDemangle (Windows only) # ItaniumDemangle (Windows only)
if (WIN32 AND NOT TARGET LLVM::Demangle) if (WIN32 AND NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp) add_library(demangle demangle/ItaniumDemangle.cpp)
+168 -127
View File
@@ -11,9 +11,11 @@ set(FFmpeg_HWACCEL_LDFLAGS)
if (NOT YUZU_USE_BUNDLED_FFMPEG) if (NOT YUZU_USE_BUNDLED_FFMPEG)
set(FFmpeg_CROSS_COMPILE_FLAGS "") set(FFmpeg_CROSS_COMPILE_FLAGS "")
if (ANDROID) if (CMAKE_CROSSCOMPILING)
message(STATUS "ffmpeg: Enabling cross compilation ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
# TODO: Maybe use CMAKE_SYSROOT? and probably provide a toolchain file for android # TODO: Maybe use CMAKE_SYSROOT? and probably provide a toolchain file for android
# I mean isn't that the "proper" way anyways? # I mean isn't that the "proper" way anyways?
if (ANDROID)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME) string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
set(SYSROOT "${TOOLCHAIN}/sysroot") set(SYSROOT "${TOOLCHAIN}/sysroot")
@@ -26,16 +28,14 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
--sysroot="${SYSROOT}" --sysroot="${SYSROOT}"
--target-os=android --target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib" --extra-ldflags="-nostdlib")
)
set(FFmpeg_IS_CROSS_COMPILING TRUE) set(FFmpeg_IS_CROSS_COMPILING TRUE)
# User attempts to do a FFmpeg cross compilation because... else()
# Here we just quickly test against host/system processors not matching
# TODO: Test for versions not matching as well?
elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME) string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis" OR FFmpeg_SYSTEM_NAME STREQUAL "managarm") # systems FFmpeg natively supports
if (NOT (NETBSD OR SOLARIS OR FREEBSD
OR OPENBSD OR DRAGONFLYBSD OR HAIKU
OR LINUX OR MSYS OR WIN32 OR ANDROID OR APPLE))
set(FFmpeg_SYSTEM_NAME "none") set(FFmpeg_SYSTEM_NAME "none")
endif() endif()
# TODO: Can we really do better? Auto-detection? Something clever? # TODO: Can we really do better? Auto-detection? Something clever?
@@ -43,78 +43,117 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
--enable-cross-compile --enable-cross-compile
--arch="${CMAKE_SYSTEM_PROCESSOR}" --arch="${CMAKE_SYSTEM_PROCESSOR}"
--target-os="${FFmpeg_SYSTEM_NAME}" --target-os="${FFmpeg_SYSTEM_NAME}"
--sysroot="${CMAKE_SYSROOT}" --sysroot="${CMAKE_SYSROOT}")
)
if (DEFINED FFmpeg_CROSS_PREFIX) if (DEFINED FFmpeg_CROSS_PREFIX)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}") list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}")
else() else()
message(WARNING "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-") message(FATAL_ERROR "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-")
endif() endif()
set(FFmpeg_IS_CROSS_COMPILING TRUE) set(FFmpeg_IS_CROSS_COMPILING TRUE)
endif() endif()
endif() endif()
endif()
if (OPENORBIS OR MANAGARM) if (WIN32)
# Doesn't support VA-API, don't go thru the embarrassment of trying to enable it list(APPEND FFmpeg_HWACCEL_FLAGS
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) --enable-d3d11va
--enable-d3d12va
--enable-dxva2
--enable-hwaccel=d3d11va_h264
--enable-hwaccel=d3d11va2_h264
--enable-hwaccel=d3d12va_h264
--enable-hwaccel=dxva2_h264
--enable-hwaccel=d3d11va_vp9
--enable-hwaccel=d3d11va2_vp9
--enable-hwaccel=d3d12va_vp9
--enable-hwaccel=dxva2_vp9)
elseif (ANDROID) elseif (ANDROID)
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-mediacodec --enable-mediacodec
--enable-jni --enable-jni
) --enable-decoder=h264_mediacodec
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID) --enable-decoder=vp8_mediacodec
find_package(PkgConfig REQUIRED) --enable-decoder=vp9_mediacodec)
pkg_check_modules(LIBVA libva) elseif (APPLE)
pkg_check_modules(CUDA cuda) list(APPEND FFmpeg_HWACCEL_FLAGS
pkg_check_modules(FFNVCODEC ffnvcodec) --enable-videotoolbox
pkg_check_modules(VDPAU vdpau) --enable-hwaccel=videotoolbox_h264
--enable-hwaccel=videotoolbox_vp9)
endif()
find_package(X11) find_package(X11)
if(X11_FOUND) if(X11_FOUND)
if (NOT APPLE) # Include X11 if possible, VDPAU lists it as complementary
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so list(APPEND FFmpeg_HWACCEL_LIBRARIES ${X11_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${X11_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${X11_LDFLAGS})
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
endif()
message(STATUS "ffmpeg: X11 ${X11_FOUND} ${X11_VERSION}")
find_package(PkgConfig)
if (PkgConfig_FOUND)
pkg_check_modules(LIBDRM libdrm)
if (LIBDRM_FOUND)
# Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
if(SOLARIS) if(SOLARIS)
list(APPEND FFmpeg_HWACCEL_LIBRARIES list(APPEND FFmpeg_HWACCEL_LIBRARIES
X11 X11
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so") "${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
else() else()
pkg_check_modules(LIBDRM libdrm REQUIRED) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_LIBRARIES list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBDRM_INCLUDE_DIRS})
${LIBDRM_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBDRM_LDFLAGS})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS})
endif() endif()
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS --enable-libdrm)
--enable-libdrm)
endif() endif()
pkg_check_modules(LIBVA libva)
if(LIBVA_FOUND) if(LIBVA_FOUND)
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA_LIBRARIES})
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LIBRARIES list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA_LDFLAGS})
${X11_LIBRARIES}
${LIBVA-DRM_LIBRARIES}
${LIBVA-X11_LIBRARIES}
${LIBVA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-vaapi
--enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vaapi
--enable-hwaccel=vp8_vaapi --enable-hwaccel=vp8_vaapi
--enable-hwaccel=vp9_vaapi) --enable-hwaccel=vp9_vaapi)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS # Logically, they can only exist if libva itself exists
${X11_INCLUDE_DIRS} pkg_check_modules(LIBVA-DRM libva-drm)
${LIBVA-DRM_INCLUDE_DIRS} if (LIBVA-DRM_FOUND)
${LIBVA-X11_INCLUDE_DIRS} list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-DRM_LIBRARIES})
${LIBVA_INCLUDE_DIRS} list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-DRM_INCLUDE_DIRS})
) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-DRM_LDFLAGS})
message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found") endif()
message(STATUS "ffmpeg: LIBVA-DRM ${LIBVA-DRM_FOUND} ${LIBVA-DRM_VERSION}")
pkg_check_modules(LIBVA-X11 libva-x11)
if (LIBVA-X11_FOUND)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-X11_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-X11_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-X11_LDFLAGS})
endif()
message(STATUS "ffmpeg: LIBVA-X11 ${LIBVA-X11_FOUND} ${LIBVA-X11_VERSION}")
else() else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...")
endif()
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: X11 libraries not found, disabling VA-API...")
endif() endif()
message(STATUS "ffmpeg: LIBVA ${LIBVA_FOUND} ${LIBVA_VERSION}")
pkg_check_modules(VDPAU vdpau)
if (VDPAU_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-vdpau
--enable-hwaccel=h264_vdpau
--enable-hwaccel=vp9_vdpau)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
endif()
message(STATUS "ffmpeg: VDPAU ${VDPAU_FOUND} ${VDPAU_VERSION}")
pkg_check_modules(FFNVCODEC ffnvcodec)
if (FFNVCODEC_FOUND) if (FFNVCODEC_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-cuvid --enable-cuvid
@@ -122,39 +161,42 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
--enable-nvdec --enable-nvdec
--enable-hwaccel=h264_nvdec --enable-hwaccel=h264_nvdec
--enable-hwaccel=vp8_nvdec --enable-hwaccel=vp8_nvdec
--enable-hwaccel=vp9_nvdec --enable-hwaccel=vp9_nvdec)
)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS})
message(STATUS "ffmpeg: ffnvcodec libraries version ${FFNVCODEC_VERSION} found")
# ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress
# here we handle the hard-linking scenario where CUDA is linked during compilation # here we handle the hard-linking scenario where CUDA is linked during compilation
if (CUDA_FOUND) find_package(CUDAToolkit)
# This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value if (CUDAToolkit_FOUND)
#list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDAToolkit_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDAToolkit_LDFLAGS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
message(STATUS "ffmpeg: CUDA libraries version ${CUDA_VERSION} found, hard-linking will be performed")
endif(CUDA_FOUND)
endif() endif()
message(STATUS "ffmpeg: CUDAToolkit ${CUDAToolkit_FOUND} ${CUDAToolkit_VERSION}")
endif()
message(STATUS "ffmpeg: FFNVCODEC ${FFNVCODEC_FOUND} ${FFNVCODEC_VERSION}")
endif()
message(STATUS "ffmpeg: PkgConfig ${PkgConfig_FOUND} ${PkgConfig_VERSION}")
if (VDPAU_FOUND AND NOT APPLE) find_package(Vulkan)
if (Vulkan_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-vdpau --enable-vulkan
--enable-hwaccel=h264_vdpau --enable-hwaccel=h264_vulkan
--enable-hwaccel=vp9_vdpau --enable-hwaccel=vp9_vulkan)
) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${Vulkan_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${Vulkan_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
message(STATUS "ffmpeg: vdpau libraries version ${VDPAU_VERSION} found")
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
message(WARNING "ffmpeg: libvdpau-dev not found, disabling Video Decode and Presentation API for Unix (VDPAU)...")
endif() endif()
message(STATUS "ffmpeg: Vulkan ${Vulkan_FOUND} ${Vulkan_VERSION}")
find_package(spirv-headers)
if (spirv-headers_FOUND)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${spirv-headers_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${spirv-headers_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${spirv-headers_LDFLAGS})
endif() endif()
message(STATUS "ffmpeg: spirv-headers ${spirv-headers_FOUND} ${spirv-headers_VERSION}")
if (OPENORBIS) if (OPENORBIS)
list(APPEND FFmpeg_CROSS_COMPILE_LIBS list(APPEND FFmpeg_CROSS_COMPILE_LIBS
@@ -162,20 +204,28 @@ if (OPENORBIS)
-lSceUserService -lSceUserService
-lSceSysmodule -lSceSysmodule
-lSceNet -lSceNet
-lSceLibcInternal -lSceLibcInternal)
)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--disable-pthreads --disable-pthreads
--extra-cflags=${CMAKE_SYSROOT}/usr/include --extra-cflags=${CMAKE_SYSROOT}/usr/include
--extra-cxxflags=${CMAKE_SYSROOT}/usr/include --extra-cxxflags=${CMAKE_SYSROOT}/usr/include
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}" --extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
)
elseif (MANAGARM) elseif (MANAGARM)
# Required for proper stuff # Required for proper stuff
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--disable-pthreads --disable-pthreads
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}" --extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
) endif()
# Usually used by Emscripten
if (DEFINED CMAKE_AR)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ar=${CMAKE_AR})
endif()
if (DEFINED CMAKE_NM)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --nm=${CMAKE_NM})
endif()
if (DEFINED CMAKE_RANLIB)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ranlib=${CMAKE_RANLIB})
endif() endif()
if (YUZU_USE_BUNDLED_FFMPEG) if (YUZU_USE_BUNDLED_FFMPEG)
@@ -183,44 +233,33 @@ if (YUZU_USE_BUNDLED_FFMPEG)
set(FFmpeg_INCLUDE_DIR set(FFmpeg_INCLUDE_DIR
"${FFmpeg_SOURCE_DIR}/include;${FFmpeg_HWACCEL_INCLUDE_DIRS}" "${FFmpeg_SOURCE_DIR}/include;${FFmpeg_HWACCEL_INCLUDE_DIRS}"
PARENT_SCOPE PARENT_SCOPE)
)
set(FFmpeg_PATH set(FFmpeg_PATH
"${FFmpeg_SOURCE_DIR}" "${FFmpeg_SOURCE_DIR}"
PARENT_SCOPE PARENT_SCOPE)
)
set(FFmpeg_LIBRARY_DIR set(FFmpeg_LIBRARY_DIR
"${FFmpeg_SOURCE_DIR}/bin" "${FFmpeg_SOURCE_DIR}/bin"
PARENT_SCOPE PARENT_SCOPE)
)
set(FFmpeg_LIBRARIES set(FFmpeg_LIBRARIES
FFmpeg::FFmpeg FFmpeg::FFmpeg
${FFmpeg_HWACCEL_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES}
PARENT_SCOPE PARENT_SCOPE)
)
set(FFmpeg_FOUND YES)
else() else()
# Build FFmpeg from externals # Build FFmpeg from externals
message(STATUS "Using FFmpeg from externals") message(STATUS "Using FFmpeg from externals")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
# FFmpeg has source that requires one of nasm or yasm to assemble it.
# REQUIRED throws an error if not found here during configuration rather than during compilation.
find_program(ASSEMBLER NAMES nasm yasm)
if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND")
message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.")
endif()
endif()
find_program(AUTOCONF autoconf)
if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
message(FATAL_ERROR "Required program `autoconf` not found.")
endif()
AddJsonPackage(ffmpeg) AddJsonPackage(ffmpeg)
# FFmpeg has source that requires one of nasm or yasm to assemble it.
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
find_program(ASSEMBLER NAMES nasm yasm REQUIRED)
endif()
find_program(AUTOCONF autoconf REQUIRED)
set(FFmpeg_PREFIX ${ffmpeg_SOURCE_DIR}) set(FFmpeg_PREFIX ${ffmpeg_SOURCE_DIR})
set(FFmpeg_BUILD_DIR ${ffmpeg_BINARY_DIR}) set(FFmpeg_BUILD_DIR ${ffmpeg_BINARY_DIR})
set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
@@ -252,6 +291,13 @@ else()
# `--disable-vdpau` is needed to avoid linking issues # `--disable-vdpau` is needed to avoid linking issues
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
set(FFmpeg_HOST_CC ${CMAKE_C_HOST_COMPILER})
if (FFmpeg_IS_CROSS_COMPILING)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ld=${CMAKE_LINKER})
endif ()
# TODO: This is a bit fragile, it depends on FFmpeg_HWACCEL_LDFLAGS being a list
# whereas CMAKE_C_FLAGS (and likewise) is meant to NOT be a list, but rather
# an elongated piece of string
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${FFmpeg_MAKEFILE} ${FFmpeg_MAKEFILE}
@@ -261,10 +307,12 @@ else()
--disable-avformat --disable-avformat
--disable-doc --disable-doc
--disable-everything --disable-everything
--disable-autodetect
--disable-ffmpeg --disable-ffmpeg
--disable-ffprobe --disable-ffprobe
--disable-network --disable-network
--disable-swresample --disable-swresample
--disable-iconv
--enable-decoder=h264 --enable-decoder=h264
--enable-decoder=vp8 --enable-decoder=vp8
--enable-decoder=vp9 --enable-decoder=vp9
@@ -272,45 +320,40 @@ else()
--enable-pic --enable-pic
--cc=${FFmpeg_CC} --cc=${FFmpeg_CC}
--cxx=${FFmpeg_CXX} --cxx=${FFmpeg_CXX}
--ld=${CMAKE_LINKER}
--extra-cflags=${CMAKE_C_FLAGS} --extra-cflags=${CMAKE_C_FLAGS}
--extra-cxxflags=${CMAKE_CXX_FLAGS} --extra-cxxflags=${CMAKE_CXX_FLAGS}
--extra-ldflags=${CMAKE_C_LINK_FLAGS} --extra-ldflags="${FFmpeg_HWACCEL_LDFLAGS}"
--host-cc=${FFmpeg_HOST_CC}
${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_HWACCEL_FLAGS}
${FFmpeg_CROSS_COMPILE_FLAGS} ${FFmpeg_CROSS_COMPILE_FLAGS}
WORKING_DIRECTORY WORKING_DIRECTORY
${FFmpeg_BUILD_DIR} ${FFmpeg_BUILD_DIR})
)
unset(FFmpeg_CC) unset(FFmpeg_CC)
unset(FFmpeg_CXX) unset(FFmpeg_CXX)
unset(FFmpeg_HOST_CC)
unset(FFmpeg_LD)
unset(FFmpeg_HWACCEL_FLAGS) unset(FFmpeg_HWACCEL_FLAGS)
unset(FFmpeg_CROSS_COMPILE_FLAGS) unset(FFmpeg_CROSS_COMPILE_FLAGS)
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
# with context of the jobserver. Also helps ninja users. # with context of the jobserver. Also helps ninja users.
execute_process( cmake_host_system_information(RESULT SYSTEM_THREADS QUERY NUMBER_OF_LOGICAL_CORES)
COMMAND set(FFmpeg_MAKE_ARGS "")
nproc if (DEFINED SYSTEM_THREADS)
OUTPUT_VARIABLE set(FFmpeg_MAKE_ARGS -j ${SYSTEM_THREADS})
SYSTEM_THREADS) endif()
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
# BSD make or Solaris make don't support ffmpeg make-j8 # Most distros use 'gmake', Arch uses 'make'
if (LINUX OR ANDROID OR APPLE OR WIN32 OR FREEBSD) find_program(MAKE NAMES gmake make REQUIRED)
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
else()
set(FFmpeg_MAKE_ARGS "")
endif()
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_BUILD_LIBRARIES}
COMMAND COMMAND
gmake ${FFmpeg_MAKE_ARGS} ${MAKE} ${FFmpeg_MAKE_ARGS}
WORKING_DIRECTORY WORKING_DIRECTORY
${FFmpeg_BUILD_DIR} ${FFmpeg_BUILD_DIR})
)
set(FFmpeg_INCLUDE_DIR set(FFmpeg_INCLUDE_DIR
"${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}"
@@ -332,12 +375,10 @@ else()
unset(FFmpeg_HWACCEL_INCLUDE_DIRS) unset(FFmpeg_HWACCEL_INCLUDE_DIRS)
unset(FFmpeg_HWACCEL_LDFLAGS) unset(FFmpeg_HWACCEL_LDFLAGS)
unset(FFmpeg_HWACCEL_LIBRARIES) unset(FFmpeg_HWACCEL_LIBRARIES)
endif()
unset(FFmpeg_COMPONENTS)
if (FFmpeg_FOUND) if (NOT FFmpeg_FOUND)
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
else()
message(FATAL_ERROR "FFmpeg not found") message(FATAL_ERROR "FFmpeg not found")
endif() endif()
endif() message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
unset(FFmpeg_COMPONENTS)
@@ -30,7 +30,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"), ENABLE_BUFFER_HISTORY("enable_buffer_history"),
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"), USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
SYNC_MEMORY_OPERATIONS("sync_memory_operations"), SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
BUFFER_REORDER_DISABLE("disable_buffer_reorder"), BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
RENDERER_DEBUG("debug"), RENDERER_DEBUG("debug"),
@@ -908,13 +908,6 @@ abstract class SettingsItem(
descriptionId = R.string.enable_buffer_history_description descriptionId = R.string.enable_buffer_history_description
) )
) )
put(
SwitchSetting(
BooleanSetting.ENABLE_GPU_BUFFER_READBACK,
titleId = R.string.enable_gpu_buffer_readback,
descriptionId = R.string.enable_gpu_buffer_readback_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS, BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
@@ -549,7 +549,6 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key) add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key) add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key) add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key) add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
add(HeaderSetting(R.string.hacks)) add(HeaderSetting(R.string.hacks))
@@ -580,8 +580,6 @@
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string> <string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string> <string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string> <string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
<string name="enable_gpu_buffer_readback">تفعيل قراءة مخزن وحدة معالجة الرسومات</string>
<string name="enable_gpu_buffer_readback_description">يحافظ هذا النظام على بيانات المخزن المؤقت المُعدّلة بواسطة وحدة معالجة الرسومات عن طريق قراءتها مرة أخرى قبل التحميل. تتطلب بعض الألعاب ذلك لعرض بعض التأثيرات بشكل صحيح. قد يُسبب ذلك مشاكل إذا لم يتمكن الجهاز من التعامل مع عبء العمل الإضافي.</string>
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string> <string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string> <string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
@@ -1099,7 +1097,6 @@
<string name="gpu_fence_behavior_immediate">فوري</string> <string name="gpu_fence_behavior_immediate">فوري</string>
<string name="gpu_fence_behavior_balanced">متوازن</string> <string name="gpu_fence_behavior_balanced">متوازن</string>
<string name="gpu_fence_behavior_accurate">دقيق</string> <string name="gpu_fence_behavior_accurate">دقيق</string>
<string name="gpu_fence_behavior_strict">صارم</string>
<string name="vram_usage_conservative">محافظ</string> <string name="vram_usage_conservative">محافظ</string>
<string name="vram_usage_aggressive">عدواني</string> <string name="vram_usage_aggressive">عدواني</string>
@@ -967,7 +967,6 @@ Wirklich fortfahren?</string>
<string name="gpu_fence_behavior_immediate">Direkt</string> <string name="gpu_fence_behavior_immediate">Direkt</string>
<string name="gpu_fence_behavior_balanced">Ausgewogen</string> <string name="gpu_fence_behavior_balanced">Ausgewogen</string>
<string name="gpu_fence_behavior_accurate">Genau</string> <string name="gpu_fence_behavior_accurate">Genau</string>
<string name="gpu_fence_behavior_strict">Strikt</string>
<string name="vram_usage_conservative">Konservativ</string> <string name="vram_usage_conservative">Konservativ</string>
<string name="vram_usage_aggressive">Aggressiv</string> <string name="vram_usage_aggressive">Aggressiv</string>
@@ -524,8 +524,6 @@
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string> <string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
<string name="enable_buffer_history">Activar el historial del búfer</string> <string name="enable_buffer_history">Activar el historial del búfer</string>
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string> <string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
<string name="enable_gpu_buffer_readback">Activar la lectura del buffer de la GPU</string>
<string name="enable_gpu_buffer_readback_description">Conserva los datos del búfer modificados por la GPU leyéndolos antes de subirlos.\nAlgunos juegos requieren esto para renderizar correctamente ciertos efectos.\nPuede causar problemas si el hardware no puede soportar la carga de trabajo adicional.</string>
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string> <string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string> <string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
@@ -1038,7 +1036,6 @@
<string name="gpu_fence_behavior_immediate">Inmediato</string> <string name="gpu_fence_behavior_immediate">Inmediato</string>
<string name="gpu_fence_behavior_balanced">Equilibrado</string> <string name="gpu_fence_behavior_balanced">Equilibrado</string>
<string name="gpu_fence_behavior_accurate">Preciso</string> <string name="gpu_fence_behavior_accurate">Preciso</string>
<string name="gpu_fence_behavior_strict">Estricto</string>
<string name="vram_usage_conservative">Conservador</string> <string name="vram_usage_conservative">Conservador</string>
<string name="vram_usage_aggressive">Agresivo</string> <string name="vram_usage_aggressive">Agresivo</string>
@@ -569,8 +569,6 @@
<string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string> <string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string>
<string name="enable_buffer_history">Включить историю буфера</string> <string name="enable_buffer_history">Включить историю буфера</string>
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string> <string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
<string name="enable_gpu_buffer_readback">Включить обратное чтение буфера ГПУ</string>
<string name="enable_gpu_buffer_readback_description">Сохраняет измененные ГПУ данные буфера путем чтения их обратно перед выгрузками. Некоторые игры требуют этого, чтобы рендерить определенные эффекты правильно. Может вызывать проблемы если оборудование не может обработать дополнительную рабочую нагрузку.</string>
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string> <string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
<string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string> <string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string>
@@ -1088,7 +1086,6 @@
<string name="gpu_fence_behavior_immediate">Мгновенный</string> <string name="gpu_fence_behavior_immediate">Мгновенный</string>
<string name="gpu_fence_behavior_balanced">Сбалансированный</string> <string name="gpu_fence_behavior_balanced">Сбалансированный</string>
<string name="gpu_fence_behavior_accurate">Точный</string> <string name="gpu_fence_behavior_accurate">Точный</string>
<string name="gpu_fence_behavior_strict">Строгий</string>
<string name="vram_usage_conservative">Консервативный</string> <string name="vram_usage_conservative">Консервативный</string>
<string name="vram_usage_aggressive">Агрессивный</string> <string name="vram_usage_aggressive">Агрессивный</string>
@@ -570,8 +570,6 @@
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string> <string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
<string name="enable_buffer_history">启用缓冲区历史</string> <string name="enable_buffer_history">启用缓冲区历史</string>
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string> <string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏会用到这项设定以正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string> <string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string> <string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
@@ -1089,7 +1087,6 @@
<string name="gpu_fence_behavior_immediate">即时</string> <string name="gpu_fence_behavior_immediate">即时</string>
<string name="gpu_fence_behavior_balanced">均衡</string> <string name="gpu_fence_behavior_balanced">均衡</string>
<string name="gpu_fence_behavior_accurate">精确</string> <string name="gpu_fence_behavior_accurate">精确</string>
<string name="gpu_fence_behavior_strict">严格</string>
<string name="vram_usage_conservative">保守式</string> <string name="vram_usage_conservative">保守式</string>
<string name="vram_usage_aggressive">主动式</string> <string name="vram_usage_aggressive">主动式</string>
@@ -561,8 +561,6 @@
<string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string> <string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
<string name="enable_buffer_history">啟用緩衝區歷史</string> <string name="enable_buffer_history">啟用緩衝區歷史</string>
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string> <string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
<string name="enable_gpu_buffer_readback">啟用 GPU 緩衝區讀回</string>
<string name="enable_gpu_buffer_readback_description">透過在上傳之前先將 GPU 修改過的緩衝區資料讀回來保存資料,部分遊戲需要啟用此功能才能正常渲染遊戲特效。如果硬體無法負荷可能會導致錯誤</string>
<string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string> <string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string>
<string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string> <string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string>
@@ -558,7 +558,6 @@
<item>@string/gpu_fence_behavior_immediate</item> <item>@string/gpu_fence_behavior_immediate</item>
<item>@string/gpu_fence_behavior_balanced</item> <item>@string/gpu_fence_behavior_balanced</item>
<item>@string/gpu_fence_behavior_accurate</item> <item>@string/gpu_fence_behavior_accurate</item>
<item>@string/gpu_fence_behavior_strict</item>
</string-array> </string-array>
<integer-array name="gpuFenceBehaviorValues"> <integer-array name="gpuFenceBehaviorValues">
<item>0</item> <item>0</item>
@@ -586,8 +586,6 @@
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
<string name="enable_buffer_history">Enable buffer history</string> <string name="enable_buffer_history">Enable buffer history</string>
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string> <string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
<string name="enable_gpu_buffer_readback">Enable GPU Buffer Readback</string>
<string name="enable_gpu_buffer_readback_description">Preserves GPU-modified buffer data by reading it back before uploads. Some games require this to render certain effects properly. May cause issues if the hardware cannot handle the additional workload.</string>
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string> <string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string> <string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
@@ -1138,7 +1136,6 @@
<string name="gpu_fence_behavior_immediate">Immediate</string> <string name="gpu_fence_behavior_immediate">Immediate</string>
<string name="gpu_fence_behavior_balanced">Balanced</string> <string name="gpu_fence_behavior_balanced">Balanced</string>
<string name="gpu_fence_behavior_accurate">Accurate</string> <string name="gpu_fence_behavior_accurate">Accurate</string>
<string name="gpu_fence_behavior_strict">Strict</string>
<!-- ASTC Decoding Method Choices --> <!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string> <string name="accelerate_astc_cpu" translatable="false">CPU</string>
+6
View File
@@ -137,6 +137,8 @@ add_library(
uuid.cpp uuid.cpp
uuid.h uuid.h
vector_math.h vector_math.h
zbic_compression.cpp
zbic_compression.h
zstd_compression.cpp zstd_compression.cpp
zstd_compression.h zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp fs/ryujinx_compat.h fs/ryujinx_compat.cpp
@@ -147,6 +149,10 @@ add_library(
net/net.h net/net.cpp net/net.h net/net.cpp
container/unordered_map.h container/unordered_set.h) container/unordered_map.h container/unordered_set.h)
set_source_files_properties(zbic_compression.cpp PROPERTIES
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function;-Wno-missing-declarations;-Wno-shadow>")
if(WIN32) if(WIN32)
target_sources(common PRIVATE windows/timer_resolution.cpp target_sources(common PRIVATE windows/timer_resolution.cpp
windows/timer_resolution.h) windows/timer_resolution.h)
-4
View File
@@ -178,10 +178,6 @@ bool IsGPUFenceBehaviorAccurate() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate; return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
} }
bool IsGPUFenceBehaviorStrict() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
}
bool IsFastmemEnabled() { bool IsFastmemEnabled() {
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging) if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
return bool(values.cpuopt_fastmem); return bool(values.cpuopt_fastmem);
+1 -9
View File
@@ -525,7 +525,7 @@ struct Values {
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage, SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
GpuFenceBehavior::Default, GpuFenceBehavior::Default,
GpuFenceBehavior::Default, GpuFenceBehavior::Default,
GpuFenceBehavior::Strict, GpuFenceBehavior::Accurate,
"gpu_fence_behavior", "gpu_fence_behavior",
Category::RendererAdvanced, Category::RendererAdvanced,
Specialization::Default, Specialization::Default,
@@ -655,13 +655,6 @@ struct Values {
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack", SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<bool> enable_gpu_buffer_readback{linkage,
false,
"enable_gpu_buffer_readback",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererHacks}; Category::RendererHacks};
@@ -979,7 +972,6 @@ bool IsDMALevelSafe();
bool IsGPUFenceBehaviorDefault(); bool IsGPUFenceBehaviorDefault();
bool IsGPUFenceBehaviorBalanced(); bool IsGPUFenceBehaviorBalanced();
bool IsGPUFenceBehaviorAccurate(); bool IsGPUFenceBehaviorAccurate();
bool IsGPUFenceBehaviorStrict();
bool IsFastmemEnabled(); bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit); void SetNceEnabled(bool is_64bit);
+1 -1
View File
@@ -137,7 +137,7 @@ ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV); ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
ENUM(GpuAccuracy, Low, High); ENUM(GpuAccuracy, Low, High);
ENUM(DmaAccuracy, Default, Unsafe, Safe); ENUM(DmaAccuracy, Default, Unsafe, Safe);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict); ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate);
ENUM(CpuBackend, Dynarmic, Nce); ENUM(CpuBackend, Dynarmic, Nce);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging); ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
ENUM(CpuClock, Normal, Boost, Overclock) ENUM(CpuClock, Normal, Boost, Overclock)
+20 -4
View File
@@ -6,6 +6,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32 #ifdef _WIN32
#include <algorithm>
#include <windows.h> #include <windows.h>
#include <mutex> #include <mutex>
#else #else
@@ -20,19 +21,22 @@ namespace Common {
#ifdef _WIN32 #ifdef _WIN32
static std::vector<std::pair<u64, u64>> vector_regions {}; static std::vector<std::pair<u64, u64>> vector_regions {};
static std::mutex vector_regions_mutex {};
// Workaround for handling non-commited memory accessed by Dynarmic; usually result of an error // Workaround for handling non-commited memory accessed by Dynarmic; usually result of an error
static LONG WINAPI FakePageFaultHandler(PEXCEPTION_POINTERS info) { static LONG WINAPI FakePageFaultHandler(PEXCEPTION_POINTERS info) {
DWORD code = info->ExceptionRecord->ExceptionCode; DWORD code = info->ExceptionRecord->ExceptionCode;
u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionAddress); u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionInformation[1]);
if (code != EXCEPTION_ACCESS_VIOLATION) { if (code != EXCEPTION_ACCESS_VIOLATION || info->ExceptionRecord->ExceptionInformation[0] == 1) {
// Not our problem // Not our problem
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
u64 addr = 0, addr2 = 0; u64 addr = 0, addr2 = 0;
{
std::lock_guard lock(vector_regions_mutex);
for (auto region: vector_regions) { for (auto region: vector_regions) {
auto addr_shifted = exception_addr >> HostPageBits; auto addr_shifted = exception_addr >> HostPageBits;
if (region.first <= addr_shifted && addr_shifted <= region.second) { if (region.first <= addr_shifted && addr_shifted <= region.second) {
@@ -48,6 +52,7 @@ static LONG WINAPI FakePageFaultHandler(PEXCEPTION_POINTERS info) {
break; break;
} }
} }
}
if (addr == 0 && addr2 == 0) { if (addr == 0 && addr2 == 0) {
// Not our problem // Not our problem
@@ -77,8 +82,16 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
auto res = VirtualQuery(reinterpret_cast<void*>(addr), &info, sizeof(info)); auto res = VirtualQuery(reinterpret_cast<void*>(addr), &info, sizeof(info));
if (res == 0) { if (res == 0) {
LOG_CRITICAL(HW_Memory, "Failed to query large buffer region at {:#x} with error {}, will try committing anyway", addr, GetLastError()); LOG_CRITICAL(HW_Memory, "Failed to query large buffer region at {:#x} with error {}, will try committing anyway", addr, GetLastError());
} else if (info.State == MEM_COMMIT) {
DWORD old_protect {};
auto perm = write ? PAGE_READWRITE : PAGE_READONLY;
if (!VirtualProtect(reinterpret_cast<void*>(addr), HostPageSize, perm, &old_protect)) {
LOG_ERROR(HW_Memory, "Failed to change permissions of large buffer region at {:#x}, error {}", addr, GetLastError());
return false;
}
return true;
} else if (info.State != MEM_RESERVE) { } else if (info.State != MEM_RESERVE) {
LOG_ERROR(HW_Memory, "Tried to commit an unreserved large buffer region at {:#x} that is not mapped or is already committed (state {:#x})", addr, info.State); LOG_ERROR(HW_Memory, "Tried to commit an unreserved large buffer region at {:#x} that is not mapped (state {:#x})", addr, info.State);
return false; return false;
} }
@@ -123,7 +136,8 @@ void* AllocateMemoryPages(std::size_t size) noexcept {
void* base = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); void* base = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (base != nullptr) { if (base != nullptr) {
vector_regions.emplace_back(reinterpret_cast<u64>(base), reinterpret_cast<u64>(base) + size); std::lock_guard lock(vector_regions_mutex);
vector_regions.emplace_back(reinterpret_cast<u64>(base) >> HostPageBits, (reinterpret_cast<u64>(base) + size) >> HostPageBits);
static std::once_flag flag; static std::once_flag flag;
std::call_once(flag, []() { AddVectoredExceptionHandler(1, FakePageFaultHandler); }); std::call_once(flag, []() { AddVectoredExceptionHandler(1, FakePageFaultHandler); });
@@ -149,6 +163,8 @@ void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
if (!base) if (!base)
return; return;
#ifdef _WIN32 #ifdef _WIN32
std::lock_guard lock(vector_regions_mutex);
std::erase_if(vector_regions, [base](const auto& r) {return r.first == reinterpret_cast<u64>(base); });
ASSERT(VirtualFree(base, 0, MEM_RELEASE)); ASSERT(VirtualFree(base, 0, MEM_RELEASE));
#else #else
ASSERT(munmap(base, size) == 0); ASSERT(munmap(base, size) == 0);
+15 -10
View File
@@ -28,9 +28,9 @@ constexpr u64 HostPageBits = 12;
constexpr u64 HostPageMask = ~(HostPageSize - 1); constexpr u64 HostPageMask = ~(HostPageSize - 1);
bool CommitVectorPage(uintptr_t addr, bool write) noexcept; bool CommitVectorPage(uintptr_t addr, bool write) noexcept;
#else #else
const u64 HostPageSize = sysconf(_SC_PAGESIZE); inline const u64 HostPageSize = sysconf(_SC_PAGESIZE);
const u64 HostPageBits = std::countr_zero(HostPageSize); inline const u64 HostPageBits = std::countr_zero(HostPageSize);
const u64 HostPageMask = ~(HostPageSize - 1); inline const u64 HostPageMask = ~(HostPageSize - 1);
#endif #endif
void* AllocateMemoryPages(std::size_t size) noexcept; void* AllocateMemoryPages(std::size_t size) noexcept;
@@ -81,8 +81,8 @@ public:
UNREACHABLE_MSG("Out of bounds RW access on SparseLargeVector @ {}", index); UNREACHABLE_MSG("Out of bounds RW access on SparseLargeVector @ {}", index);
} }
if (!IsCommittedPage(index)) { if (!IsCommittedPage(index) && !CommitPage(index)) {
CommitPage(index); UNREACHABLE_MSG("Cannot access SparseLargeVector index {} with RW permission", index);
} }
return base_ptr[index]; return base_ptr[index];
} }
@@ -103,8 +103,7 @@ public:
LOG_CRITICAL(Common_Memory, "Out of bounds write on SparseLargeVector @ {}", index); LOG_CRITICAL(Common_Memory, "Out of bounds write on SparseLargeVector @ {}", index);
return; return;
} }
if (!IsCommittedPage(index)) if (IsCommittedPage(index) || CommitPage(index))
CommitPage(index);
base_ptr[index] = value; base_ptr[index] = value;
} }
@@ -177,16 +176,22 @@ private:
return (val >> (page & 63)) & 1; return (val >> (page & 63)) & 1;
} }
constexpr void CommitPage(std::size_t index) noexcept { constexpr bool CommitPage(std::size_t index) noexcept {
auto page_index = (index * sizeof(T)) >> HostPageBits; auto page_index = (index * sizeof(T)) >> HostPageBits;
auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask; auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask;
#if defined(_WIN32) #if defined(_WIN32)
CommitVectorPage(page, true); if (!CommitVectorPage(page, true)) {
return false;
}
#else #else
mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE); if (mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE) != 0) {
LOG_ERROR(Common_Memory, "Failed to commit large buffer region at index {}, error {}", index, strerror(errno));
return false;
}
#endif #endif
committed_pages[page_index >> 6].fetch_or(1ULL << (page_index & 63), std::memory_order_release); committed_pages[page_index >> 6].fetch_or(1ULL << (page_index & 63), std::memory_order_release);
return true;
} }
constexpr void DecommitPage(std::size_t index) noexcept { constexpr void DecommitPage(std::size_t index) noexcept {
+46
View File
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include "common/zbic_compression.h"
#define ZSTD_ZBIC_SUPPORT 1
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#define ZSTDERRORLIB_VISIBLE static
#define ZSTDERRORLIB_HIDDEN static
#undef ZSTD_MULTITHREAD
#if defined(__ANDROID__)
#undef _GNU_SOURCE
#endif
#include "zstd.h"
#define g_ZSTD_threading_useless_symbol g_ZSTD_zbic_threading_useless_symbol
#include "zstd.c"
#undef g_ZSTD_threading_useless_symbol
namespace Common::Compression {
bool IsZBIC(std::span<const u8> src) {
if (src.size() < sizeof(u32)) {
return false;
}
u32 magic = 0;
std::memcpy(&magic, src.data(), sizeof(u32));
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
}
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
if (dst.empty() || src.empty()) {
return -1;
}
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
if (ZSTD_isError(res)) {
return -1;
}
return static_cast<int>(res);
}
} // namespace Common::Compression
+15
View File
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <span>
#include "common/common_types.h"
namespace Common::Compression {
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
} // namespace Common::Compression
+31 -4
View File
@@ -7,12 +7,14 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
#include <cstring> #include <cstring>
#include <span>
#include <vector> #include <vector>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/hex_util.h" #include "common/hex_util.h"
#include "common/logging.h" #include "common/logging.h"
#include "common/lz4_compression.h" #include "common/lz4_compression.h"
#include "common/zbic_compression.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/core.h" #include "core/core.h"
@@ -104,11 +106,36 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset); nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
if (nso_header.IsSegmentCompressed(i)) { if (nso_header.IsSegmentCompressed(i)) {
int r = Common::Compression::DecompressDataLZ4(decompressed_size.data(), nso_header.segments[i].size, compressed_data.data(), nso_header.segments_compressed_size[i]); if (nso_header.IsZBICCompressed()) {
ASSERT(r == int(nso_header.segments[i].size)); // ZBIC compression
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size); const int r = Common::Compression::DecompressDataZBIC(
std::span<u8>{decompressed_size}.first(nso_header.segments[i].size),
std::span<const u8>{compressed_data}.first(nso_header.segments_compressed_size[i])
);
ASSERT(r > 0);
} else { } else {
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, compressed_data.data(), nso_header.segments[i].size); // LZ4 compression
int r = Common::Compression::DecompressDataLZ4(
decompressed_size.data(),
nso_header.segments[i].size,
compressed_data.data(),
nso_header.segments_compressed_size[i]
);
ASSERT(r == int(nso_header.segments[i].size));
}
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
decompressed_size.data(),
nso_header.segments[i].size
);
} else {
// Not compressed
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
compressed_data.data(),
nso_header.segments[i].size
);
} }
codeset.segments[i].addr = module_start + nso_header.segments[i].location; codeset.segments[i].addr = module_start + nso_header.segments[i].location;
codeset.segments[i].offset = module_start + nso_header.segments[i].location; codeset.segments[i].offset = module_start + nso_header.segments[i].location;
+6
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -58,6 +61,9 @@ struct NSOHeader {
std::array<SHA256Hash, 3> segment_hashes; std::array<SHA256Hash, 3> segment_hashes;
bool IsSegmentCompressed(size_t segment_num) const; bool IsSegmentCompressed(size_t segment_num) const;
bool IsZBICCompressed() const {
return ((flags >> 7) & 1) != 0;
}
}; };
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
+3 -17
View File
@@ -761,9 +761,6 @@ void EmulatedController::StartMotionCalibration() {
} }
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, Common::UUID uuid) { void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, Common::UUID uuid) {
const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
const auto& player = Settings::values.players.GetValue()[player_index];
if (index >= controller.button_values.size()) { if (index >= controller.button_values.size()) {
return; return;
} }
@@ -916,21 +913,10 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
break; break;
} }
if (!is_connected) { const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
if (npad_type == NpadStyleIndex::Handheld) { const auto& player = Settings::values.players.GetValue()[player_index];
if (npad_id_type == NpadIdType::Handheld) { if (player.connected) {
Connect(); Connect();
controller_connected[player_index] = true;
}
} else if (npad_type != NpadStyleIndex::Handheld) {
if (npad_id_type == NpadIdType::Player1) {
Connect();
controller_connected[player_index] = true;
} else if (player.connected && !controller_connected[player_index]) {
Connect();
controller_connected[player_index] = true;
}
}
} }
TriggerOnChange(ControllerTriggerType::Button, true); TriggerOnChange(ControllerTriggerType::Button, true);
@@ -22,7 +22,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "common/vector_math.h" #include "common/vector_math.h"
#include "hid_core/frontend/motion_input.h" #include "hid_core/frontend/motion_input.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
#include "hid_core/irsensor/irs_types.h" #include "hid_core/irsensor/irs_types.h"
@@ -585,7 +584,6 @@ private:
std::array<VibrationValue, 2> last_vibration_value{DEFAULT_VIBRATION_VALUE, std::array<VibrationValue, 2> last_vibration_value{DEFAULT_VIBRATION_VALUE,
DEFAULT_VIBRATION_VALUE}; DEFAULT_VIBRATION_VALUE};
std::array<std::chrono::steady_clock::time_point, 2> last_vibration_timepoint{}; std::array<std::chrono::steady_clock::time_point, 2> last_vibration_timepoint{};
std::array<bool, HIDCore::available_controllers> controller_connected{};
// Atomically synched values // Atomically synched values
std::atomic<HID::NpadStyleIndex> npad_type{HID::NpadStyleIndex::None}; std::atomic<HID::NpadStyleIndex> npad_type{HID::NpadStyleIndex::None};
+1 -4
View File
@@ -226,9 +226,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"), INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"),
tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting.")); tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."));
INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"), INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"),
tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nStrict is the slowest option, but can fix issues that require stricter synchronization.\nDefault follows the GPU Accuracy setting.")); tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nDefault follows the GPU Mode setting."));
INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"),
tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"), INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
tr("May reduce shader stutter.")); tr("May reduce shader stutter."));
INSERT(Settings, gpu_clock, tr("GPU Clocks"), INSERT(Settings, gpu_clock, tr("GPU Clocks"),
@@ -442,7 +440,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
PAIR(GpuFenceBehavior, Immediate, tr("Immediate")), PAIR(GpuFenceBehavior, Immediate, tr("Immediate")),
PAIR(GpuFenceBehavior, Balanced, tr("Balanced")), PAIR(GpuFenceBehavior, Balanced, tr("Balanced")),
PAIR(GpuFenceBehavior, Accurate, tr("Accurate")), PAIR(GpuFenceBehavior, Accurate, tr("Accurate")),
PAIR(GpuFenceBehavior, Strict, tr("Strict")),
}}); }});
translations->insert( translations->insert(
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(), {Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
+14 -17
View File
@@ -249,6 +249,10 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
runtime.CopyBuffer(dest_buffer, src_buffer, copies, true); runtime.CopyBuffer(dest_buffer, src_buffer, copies, true);
if (has_new_downloads) { if (has_new_downloads) {
memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
const bool should_sync = Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate();
if (should_sync) {
runtime.Finish();
}
} }
Tegra::Memory::DeviceGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::UnsafeReadWrite> Tegra::Memory::DeviceGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::UnsafeReadWrite>
@@ -1230,7 +1234,7 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
buffer.MarkUsage(offset, size); buffer.MarkUsage(offset, size);
if (is_written) { if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size); MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size, true);
} }
if constexpr (NEEDS_BIND_STORAGE_INDEX) { if constexpr (NEEDS_BIND_STORAGE_INDEX) {
@@ -1516,11 +1520,13 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
} }
template <class P> template <class P>
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) { void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size, bool needs_sync) {
if constexpr (!IS_OPENGL) { if constexpr (!IS_OPENGL) {
if (needs_sync) {
Buffer& buffer = slot_buffers[buffer_id]; Buffer& buffer = slot_buffers[buffer_id];
buffer.setWriteTick(runtime.CurrentTick()); buffer.setWriteTick(runtime.CurrentTick());
} }
}
memory_tracker.MarkRegionAsGpuModified(device_addr, size); memory_tracker.MarkRegionAsGpuModified(device_addr, size);
gpu_modified_ranges.Add(device_addr, size); gpu_modified_ranges.Add(device_addr, size);
uncommitted_gpu_modified_ranges.Add(device_addr, size); uncommitted_gpu_modified_ranges.Add(device_addr, size);
@@ -1535,8 +1541,11 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size, bool sparse_com
const BufferId buffer_id = page_table[page]; const BufferId buffer_id = page_table[page];
if (buffer_id) { if (buffer_id) {
Buffer& buffer = slot_buffers[buffer_id]; Buffer& buffer = slot_buffers[buffer_id];
WaitForGpuFenceIfNeeded(buffer);
if (buffer.IsInBounds(device_addr, size)) { if (buffer.IsInBounds(device_addr, size)) {
const bool should_sync = Settings::IsGPUFenceBehaviorAccurate();
if (should_sync) {
SynchronizeBufferWrites(buffer);
}
bool usable = true; bool usable = true;
if constexpr (requires { buffer.IsSparseCompatible(); }) { if constexpr (requires { buffer.IsSparseCompatible(); }) {
if (sparse_compatible && !buffer.IsSparseCompatible()) { if (sparse_compatible && !buffer.IsSparseCompatible()) {
@@ -1552,20 +1561,14 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size, bool sparse_com
} }
template <class P> template <class P>
void BufferCache<P>::WaitForGpuFenceIfNeeded(Buffer& buffer) { void BufferCache<P>::SynchronizeBufferWrites(Buffer& buffer) {
if constexpr (!IS_OPENGL) { if constexpr (!IS_OPENGL) {
const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
if (gpu_fence_accurate || gpu_fence_strict) {
const u64 gpu_tick_delay = gpu_fence_strict ? 0 : 3;
const u64 buffer_tick = buffer.getWriteTick(); const u64 buffer_tick = buffer.getWriteTick();
const u64 gpu_tick = runtime.KnownGpuTick(); if (!runtime.IsFree(buffer_tick)) {
if (buffer_tick > gpu_tick + gpu_tick_delay) {
runtime.Wait(buffer_tick); runtime.Wait(buffer_tick);
} }
} }
} }
}
template <class P> template <class P>
typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr, typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr,
@@ -1795,9 +1798,6 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
if (immediate_buffer.empty()) { if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy); immediate_buffer = ImmediateBuffer(largest_copy);
} }
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
DownloadBufferMemory(buffer, device_addr, copy.size);
}
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size); device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
upload_span = immediate_buffer.subspan(0, copy.size); upload_span = immediate_buffer.subspan(0, copy.size);
} }
@@ -1816,9 +1816,6 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
for (BufferCopy& copy : copies) { for (BufferCopy& copy : copies) {
u8* const src_pointer = staging_pointer.data() + copy.src_offset; u8* const src_pointer = staging_pointer.data() + copy.src_offset;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
DownloadBufferMemory(buffer, device_addr, copy.size);
}
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size); device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
// Apply the staging offset // Apply the staging offset
copy.src_offset += upload_staging.offset; copy.src_offset += upload_staging.offset;
@@ -430,11 +430,11 @@ private:
void UpdateComputeTextureBuffers(); void UpdateComputeTextureBuffers();
void MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size); void MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size, bool needs_sync = false);
[[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size, bool sparse_compatible); [[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size, bool sparse_compatible);
void WaitForGpuFenceIfNeeded(Buffer& buffer); void SynchronizeBufferWrites(Buffer& buffer);
[[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size); [[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
+1 -1
View File
@@ -72,7 +72,7 @@ public:
} }
void SignalFence(std::function<void()>&& func) { void SignalFence(std::function<void()>&& func) {
const bool delay_fence = Settings::IsGPUFenceBehaviorDefault() ? Settings::IsGPULevelHigh() : Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate() || Settings::IsGPUFenceBehaviorStrict(); const bool delay_fence = Settings::IsGPUFenceBehaviorDefault() ? Settings::IsGPULevelHigh() : Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate();
const bool should_flush = ShouldFlush(); const bool should_flush = ShouldFlush();
if constexpr (!can_async_check) { if constexpr (!can_async_check) {
TryReleasePendingFences<false>(); TryReleasePendingFences<false>();
+1 -1
View File
@@ -260,7 +260,7 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
}; };
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr); u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8); u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
bool is_synced = (Settings::IsGPUFenceBehaviorDefault() ? !Settings::IsGPULevelHigh() : !Settings::IsGPUFenceBehaviorBalanced() && !Settings::IsGPUFenceBehaviorAccurate() && !Settings::IsGPUFenceBehaviorStrict()) && is_fence; bool is_synced = (Settings::IsGPUFenceBehaviorDefault() ? !Settings::IsGPULevelHigh() : !Settings::IsGPUFenceBehaviorBalanced() && !Settings::IsGPUFenceBehaviorAccurate()) && is_fence;
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location, std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
pointer, pointer_timestamp] { pointer, pointer_timestamp] {
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
@@ -419,15 +419,15 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noe
} }
u64 BufferCacheRuntime::CurrentTick() { u64 BufferCacheRuntime::CurrentTick() {
return scheduler.GetMasterSemaphore().CurrentTick(); return scheduler.CurrentTick();
} }
u64 BufferCacheRuntime::KnownGpuTick() { bool BufferCacheRuntime::IsFree(u64 tick) {
return scheduler.GetMasterSemaphore().KnownGpuTick(); return scheduler.IsFree(tick);
} }
void BufferCacheRuntime::Wait(u64 buffer_tick) { void BufferCacheRuntime::Wait(u64 tick) {
scheduler.Wait(buffer_tick); scheduler.Wait(tick);
} }
void BufferCacheRuntime::Finish() { void BufferCacheRuntime::Finish() {
@@ -112,9 +112,9 @@ public:
u64 CurrentTick(); u64 CurrentTick();
u64 KnownGpuTick(); bool IsFree(u64 tick);
void Wait(u64 buffer_tick); void Wait(u64 tick);
void Finish(); void Finish();