Compare commits

..

9 Commits

Author SHA1 Message Date
PavelBARABANOV 355f9d84ef [shader_recompiler, renderer_vulkan] draw sprites whose texture handle comes from a vertex attribute 2026-10-05 05:14:18 +03:00
MaranBr d16735f5b6 [am] Properly handle None frontend applet (#4500)
- [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.

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

Properly handle the `AppletId::None` case by returning a null frontend applet instead of falling back to the stub implementation.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4500
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-02 02:24:58 +02:00
lizzie d3550c4571 [qt] Filter collates accents (Unicode NFD) (#4380)
Now "POKEMON" and "pokemon" are the same, and search's no longer case sensitive.
Maybe we could transliterate? But that would require icu which is a bit overkill.
Main point is to be able to search "Pokemon" (accent on 'e') without actually typing the accent

https://unicode.org/reports/tr15/

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [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.

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4380
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-01 07:39:44 +02:00
John 963119e7cc [ffmpeg]Gamescope / Gamemode NVDEC Emulation - GPU Decoding Patches (#4501)
Switch to ffmpeg with liz's gamescope patches.

- [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.

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4501
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-01 03:34:57 +02:00
xbzk 2a7e9b53b1 [android,ui] fixed shader cache clearing when changing drivers (#4496)
- [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.

-------------------
Trivial bug pending on backlog, where changing drivers was not clearing up sharder cache as expected.

The driver flow (broken) was deleting externalFilesDir/shader/<game>, while the visible cache-size control (working) DirectoryInitialization.userDirectory/cache/shader/<game>.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4496
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-01 00:28:18 +02:00
xbzk 8e2d26c272 [video_core] buffer cache readback for nce invalidations (#4490)
- [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 a follow up of 4473, a fix for the next Ender Magnolia known crash, the shackled beast's vaper crash, but specific for NCE.

Imma try to be short:

NCE invalidation was dooming whole guest pages when it shouldn't. If the GPU buffer cache owns some bytes on a page, invalidating first discards their ownership, and the retrying CPU can then observe stale data. On Android, this was corrupting some indirect draw packets and causing huge invalid index count reach staging memory allocation.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4490
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-30 22:13:37 +02:00
Eden CI f8b7651104 [dist, android] Update translations from Transifex for Sep 28 (#4494)
Automatic translation update for Sep 28

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4494
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-30 02:00:44 +02:00
xbzk 3f78512c83 [ro] add TLS patching for runtime NROs (#4492)
- [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.

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

Aimed to fix Biomutant which stucks in a bootloop due to guest being unable to reach correct thread local storage (TLS)
This fixes runtime NRO loading by properly patching the guest TLS (TPIDR_EL0) path. Steps:
-Read the loaded NRO image into a temporary buffer.
-Run the NCE patcher on it.
-Produce a patch section / relocated code.
-Map that patch section as executable memory in the target process.
Game still has intermittent visual issues which can be solved with GPU level accurate, but that causes a huge performance drop in exchange. Someone else will resume this one.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4492
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-30 00:58:29 +02:00
xbzk a82f31a310 [settings,qt] merge of "disable controller applet" toggle with "controller applet mode" picker (#4498)
- [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.

-------------------
Small good simplification to nuke a toggle which costed me almost an entire day of work when fixing controller applet issues:

There were two settings related to Controller applet:
-"disable controller applet", which is a boolean toggle;
-"controller configuration" applet mode, which is a "Real"/"Custom" picker;

All i did was to nuke the toggle and add a third option "Disabled" to the picker.
Users which used the disable toggle will have to pick Disabled;
Real/Custom settings wont be affected since their indexes remains.
All options tested against diablo 3. All working as intended.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4498
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-30 00:57:23 +02:00
50 changed files with 12313 additions and 12621 deletions
+1 -1
View File
@@ -79,7 +79,7 @@
"name": "ffmpeg", "name": "ffmpeg",
"package": "FFmpeg", "package": "FFmpeg",
"repo": "crueter-ci/FFmpeg", "repo": "crueter-ci/FFmpeg",
"version": "9.0.1-1788120736-bf1b838f2a" "version": "9.0.2-1790726865-946fcce07b"
}, },
"fmt": { "fmt": {
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2", "hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
+455 -473
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+440 -463
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+440 -463
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+440 -463
View File
File diff suppressed because it is too large Load Diff
+440 -463
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+440 -463
View File
File diff suppressed because it is too large Load Diff
+439 -456
View File
File diff suppressed because it is too large Load Diff
+168 -209
View File
@@ -11,149 +11,110 @@ 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 (CMAKE_CROSSCOMPILING) if (ANDROID)
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") set(FFmpeg_CPU "armv8-a")
set(FFmpeg_CPU "armv8-a") list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --enable-cross-compile
--enable-cross-compile --arch=arm64
--arch=arm64 #--cpu=${FFmpeg_CPU}
#--cpu=${FFmpeg_CPU} --cross-prefix="${TOOLCHAIN}/bin/aarch64-linux-android-"
--cross-prefix="${TOOLCHAIN}/bin/aarch64-linux-android-" --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)
else() # User attempts to do a FFmpeg cross compilation because...
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME) # Here we just quickly test against host/system processors not matching
# systems FFmpeg natively supports # TODO: Test for versions not matching as well?
if (NOT (NETBSD OR SOLARIS OR FREEBSD elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
OR OPENBSD OR DRAGONFLYBSD OR HAIKU AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
OR LINUX OR MSYS OR WIN32 OR ANDROID OR APPLE)) string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
set(FFmpeg_SYSTEM_NAME "none") if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis" OR FFmpeg_SYSTEM_NAME STREQUAL "managarm")
endif() set(FFmpeg_SYSTEM_NAME "none")
# TODO: Can we really do better? Auto-detection? Something clever?
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch="${CMAKE_SYSTEM_PROCESSOR}"
--target-os="${FFmpeg_SYSTEM_NAME}"
--sysroot="${CMAKE_SYSROOT}")
if (DEFINED FFmpeg_CROSS_PREFIX)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}")
else()
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()
set(FFmpeg_IS_CROSS_COMPILING TRUE)
endif() endif()
# TODO: Can we really do better? Auto-detection? Something clever?
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch="${CMAKE_SYSTEM_PROCESSOR}"
--target-os="${FFmpeg_SYSTEM_NAME}"
--sysroot="${CMAKE_SYSROOT}"
)
if (DEFINED FFmpeg_CROSS_PREFIX)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}")
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}-")
endif()
set(FFmpeg_IS_CROSS_COMPILING TRUE)
endif() endif()
endif() endif()
if (WIN32) if (OPENORBIS OR MANAGARM)
list(APPEND FFmpeg_HWACCEL_FLAGS # Doesn't support VA-API, don't go thru the embarrassment of trying to enable it
--enable-d3d11va list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
--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 )
--enable-decoder=vp8_mediacodec elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
--enable-decoder=vp9_mediacodec) find_package(PkgConfig REQUIRED)
elseif (APPLE)
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-videotoolbox
--enable-hwaccel=videotoolbox_h264
--enable-hwaccel=videotoolbox_vp9)
endif()
find_package(X11)
if(X11_FOUND)
# Include X11 if possible, VDPAU lists it as complementary
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)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
X11
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
else()
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBDRM_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBDRM_LDFLAGS})
endif()
list(APPEND FFmpeg_HWACCEL_FLAGS --enable-libdrm)
endif()
pkg_check_modules(LIBVA libva) pkg_check_modules(LIBVA libva)
if(LIBVA_FOUND) pkg_check_modules(CUDA cuda)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA_LIBRARIES}) pkg_check_modules(FFNVCODEC ffnvcodec)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA_INCLUDE_DIRS}) pkg_check_modules(VDPAU vdpau)
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA_LDFLAGS})
list(APPEND FFmpeg_HWACCEL_FLAGS find_package(X11)
--enable-vaapi if(X11_FOUND)
--enable-hwaccel=h264_vaapi if (NOT APPLE)
--enable-hwaccel=vp8_vaapi # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
--enable-hwaccel=vp9_vaapi) if(SOLARIS)
# Logically, they can only exist if libva itself exists list(APPEND FFmpeg_HWACCEL_LIBRARIES
pkg_check_modules(LIBVA-DRM libva-drm) X11
if (LIBVA-DRM_FOUND) "${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-DRM_LIBRARIES}) else()
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-DRM_INCLUDE_DIRS}) pkg_check_modules(LIBDRM libdrm REQUIRED)
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-DRM_LDFLAGS}) list(APPEND FFmpeg_HWACCEL_LIBRARIES
${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS})
endif()
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-libdrm)
endif() endif()
message(STATUS "ffmpeg: LIBVA-DRM ${LIBVA-DRM_FOUND} ${LIBVA-DRM_VERSION}") if(LIBVA_FOUND)
pkg_check_modules(LIBVA-X11 libva-x11) pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
if (LIBVA-X11_FOUND) pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-X11_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_LIBRARIES
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-X11_INCLUDE_DIRS}) ${X11_LIBRARIES}
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-X11_LDFLAGS}) ${LIBVA-DRM_LIBRARIES}
${LIBVA-X11_LIBRARIES}
${LIBVA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-hwaccel=h264_vaapi
--enable-hwaccel=vp8_vaapi
--enable-hwaccel=vp9_vaapi)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${X11_INCLUDE_DIRS}
${LIBVA-DRM_INCLUDE_DIRS}
${LIBVA-X11_INCLUDE_DIRS}
${LIBVA_INCLUDE_DIRS}
)
message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found")
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...")
endif() 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: 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
@@ -161,42 +122,39 @@ if (PkgConfig_FOUND)
--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
find_package(CUDAToolkit) if (CUDA_FOUND)
if (CUDAToolkit_FOUND) # This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDAToolkit_LIBRARIES}) #list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDAToolkit_LDFLAGS}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
endif() list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
message(STATUS "ffmpeg: CUDAToolkit ${CUDAToolkit_FOUND} ${CUDAToolkit_VERSION}") message(STATUS "ffmpeg: CUDA libraries version ${CUDA_VERSION} found, hard-linking will be performed")
endif(CUDA_FOUND)
endif() endif()
message(STATUS "ffmpeg: FFNVCODEC ${FFNVCODEC_FOUND} ${FFNVCODEC_VERSION}")
endif()
message(STATUS "ffmpeg: PkgConfig ${PkgConfig_FOUND} ${PkgConfig_VERSION}")
find_package(Vulkan) if (VDPAU_FOUND AND NOT APPLE)
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() 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()
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
@@ -204,28 +162,20 @@ 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)
@@ -233,32 +183,43 @@ 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")
AddJsonPackage(ffmpeg)
# FFmpeg has source that requires one of nasm or yasm to assemble it.
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)") if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
find_program(ASSEMBLER NAMES nasm yasm REQUIRED) # 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() endif()
find_program(AUTOCONF autoconf REQUIRED)
find_program(AUTOCONF autoconf)
if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
message(FATAL_ERROR "Required program `autoconf` not found.")
endif()
AddJsonPackage(ffmpeg)
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})
@@ -289,15 +250,8 @@ else()
# `configure` parameters builds only exactly what yuzu needs from FFmpeg # `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--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}
@@ -307,12 +261,10 @@ 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
@@ -320,40 +272,45 @@ 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="${FFmpeg_HWACCEL_LDFLAGS}" --extra-ldflags=${CMAKE_C_LINK_FLAGS}
--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.
cmake_host_system_information(RESULT SYSTEM_THREADS QUERY NUMBER_OF_LOGICAL_CORES) execute_process(
set(FFmpeg_MAKE_ARGS "") COMMAND
if (DEFINED SYSTEM_THREADS) nproc
set(FFmpeg_MAKE_ARGS -j ${SYSTEM_THREADS}) OUTPUT_VARIABLE
endif() SYSTEM_THREADS)
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
# Most distros use 'gmake', Arch uses 'make' # BSD make or Solaris make don't support ffmpeg make-j8
find_program(MAKE NAMES gmake make REQUIRED) if (LINUX OR ANDROID OR APPLE OR WIN32 OR FREEBSD)
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
else()
set(FFmpeg_MAKE_ARGS "")
endif()
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_BUILD_LIBRARIES}
COMMAND COMMAND
${MAKE} ${FFmpeg_MAKE_ARGS} gmake ${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}"
@@ -375,10 +332,12 @@ 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 (NOT FFmpeg_FOUND) if (FFmpeg_FOUND)
message(FATAL_ERROR "FFmpeg not found") message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
else()
message(FATAL_ERROR "FFmpeg not found")
endif()
endif() endif()
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
unset(FFmpeg_COMPONENTS)
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import java.io.File import java.io.File
@@ -146,11 +147,11 @@ class DriverViewModel : ViewModel() {
private fun wipeGameShaders(game: Game) { private fun wipeGameShaders(game: Game) {
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val externalFilesDir = YuzuApplication.appContext.getExternalFilesDir(null) val userDirectory = DirectoryInitialization.userDirectory
?: return@withContext ?: return@withContext
val shaderDir = File( val shaderDir = File(
externalFilesDir.absolutePath + userDirectory +
"/shader/" + game.settingsName.lowercase() "/cache/shader/" + game.settingsName.lowercase()
) )
if (shaderDir.exists()) { if (shaderDir.exists()) {
shaderDir.deleteRecursively() shaderDir.deleteRecursively()
+1 -1
View File
@@ -150,7 +150,7 @@ ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, Scale
ENUM(AntiAliasing, None, Fxaa, Smaa); ENUM(AntiAliasing, None, Fxaa, Smaa);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked); ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE); ENUM(AppletMode, HLE, LLE, Disabled);
ENUM(SpirvOptimizeMode, Never, OnLoad, Always); ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuClock, Normal, Boost, Overclock) ENUM(GpuClock, Normal, Boost, Overclock)
ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge) ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge)
+3 -2
View File
@@ -250,9 +250,10 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer); return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
case AppletId::NetConnect: case AppletId::NetConnect:
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect); return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
case AppletId::None:
return nullptr;
default: default:
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}" UNIMPLEMENTED_MSG("No frontend implementation exists for applet_id={:02X} program_id={:016X}! Using stub applet.", static_cast<u8>(id), applet->program_id);
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
return std::make_shared<StubApplet>(system, applet, id, mode); return std::make_shared<StubApplet>(system, applet, id, mode);
} }
} }
+30 -2
View File
@@ -16,6 +16,10 @@
#include "core/hle/service/ro/ro_types.h" #include "core/hle/service/ro/ro_types.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#ifdef HAS_NCE
#include "core/arm/nce/patcher.h"
#include "core/hle/kernel/k_shared_memory.h"
#endif
namespace Service::RO { namespace Service::RO {
@@ -386,7 +390,7 @@ public:
R_SUCCEED(); R_SUCCEED();
} }
Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address, Result MapManualLoadModuleMemory(Kernel::KernelCore& kernel, u64* out_address, size_t context_id, u64 nro_address,
u64 nro_size, u64 bss_address, u64 bss_size) { u64 nro_size, u64 bss_address, u64 bss_size) {
// Get context. // Get context.
ProcessContext* context = this->GetContextById(context_id); ProcessContext* context = this->GetContextById(context_id);
@@ -421,7 +425,31 @@ public:
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
std::addressof(ro_size), std::addressof(rw_size), std::addressof(ro_size), std::addressof(rw_size),
nro_info->base_address, nro_size, bss_size)); nro_info->base_address, nro_size, bss_size));
#ifdef HAS_NCE
if (Settings::IsNceEnabled()) {
auto* process = context->GetProcess();
auto& memory = process->GetMemory();
std::vector<u8> image(total_size);
memory.ReadBlock(nro_info->base_address, image.data(), rx_size);
Kernel::CodeSet::Segment code{.size = static_cast<u32>(rx_size)};
Core::NCE::Patcher patch;
patch.PatchText(image, code);
patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr);
const u64 patch_address = nro_info->base_address + total_size;
const size_t patch_size = patch.GetSectionSize();
constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute;
auto* patch_memory = Kernel::KSharedMemory::Create(kernel);
R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size));
std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size);
R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size));
R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission));
memory.WriteBlock(nro_info->base_address, image.data(), rx_size);
}
#endif
// Set NRO perms. // Set NRO perms.
R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size, R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
rw_size + bss_size)); rw_size + bss_size));
@@ -531,7 +559,7 @@ public:
Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid, Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address, R_RETURN(m_ro->MapManualLoadModuleMemory(system.Kernel(), out_load_address.Get(), m_context_id, nro_address,
nro_size, bss_address, bss_size)); nro_size, bss_address, bss_size));
} }
+1 -1
View File
@@ -757,7 +757,7 @@ struct Memory::Impl {
}; };
auto& gpu = system.GPU(); auto& gpu = system.GPU();
gpu_device_memory->ApplyOpOnPointer( gpu_device_memory->ApplyOpOnPointer(
p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size, true); });
} }
Core::System& system; Core::System& system;
+1 -3
View File
@@ -342,9 +342,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
"it bypasses such prompts and directly exits the emulation.")); "it bypasses such prompts and directly exits the emulation."));
INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"),
tr("Hides the mouse after 2.5s of inactivity.")); tr("Hides the mouse after 2.5s of inactivity."));
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
tr("Forcibly disables the use of the controller applet in emulated programs.\n"
"When a program attempts to open the controller applet, it is immediately closed."));
INSERT(UISettings, check_for_updates, tr("Check for updates"), INSERT(UISettings, check_for_updates, tr("Check for updates"),
tr("Whether or not to check for updates upon startup.")); tr("Whether or not to check for updates upon startup."));
@@ -380,6 +377,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
{ {
PAIR(AppletMode, HLE, tr("Custom frontend")), PAIR(AppletMode, HLE, tr("Custom frontend")),
PAIR(AppletMode, LLE, tr("Real applet")), PAIR(AppletMode, LLE, tr("Real applet")),
PAIR(AppletMode, Disabled, tr("Disabled")),
}}); }});
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(), translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
-2
View File
@@ -127,8 +127,6 @@ struct Values {
Setting<bool> hide_mouse{ Setting<bool> hide_mouse{
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
true, true}; true, true};
Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
Category::UiGeneral};
// Set when Vulkan is known to crash the application // Set when Vulkan is known to crash the application
bool has_broken_vulkan = false; bool has_broken_vulkan = false;
@@ -38,6 +38,8 @@ struct HostTranslateInfo {
///< passthrough shaders ///< passthrough shaders
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
///< control flow ///< control flow
bool support_attribute_texture_handle{}; ///< True when the host binds texture handles that
///< arrive as vertex attributes
void ApplyDescriptorLimitPolicy() noexcept { void ApplyDescriptorLimitPolicy() noexcept {
if (min_ssbo_alignment == 0) { if (min_ssbo_alignment == 0) {
+44 -3
View File
@@ -268,6 +268,10 @@ static inline u32 ReadCbufCached(Environment& env, u32 index, u32 offset) {
return v; return v;
} }
static inline bool IsAttributeHandle(const ConstBufferAddr& cbuf) {
return cbuf.index == ATTRIBUTE_HANDLE_CBUF_INDEX;
}
static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) { static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) {
// Must all be uniquely different variables // Must all be uniquely different variables
// If has secondary, then it will be cbuf.secondary_{index|offset}, else its 0. // If has secondary, then it will be cbuf.secondary_{index|offset}, else its 0.
@@ -287,14 +291,23 @@ static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr
// Cached variants of existing helpers // Cached variants of existing helpers
static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) { static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return TextureType::Color2D;
}
return env.ReadTextureType(GetTextureHandleCached(env, cbuf)); return env.ReadTextureType(GetTextureHandleCached(env, cbuf));
} }
static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env, static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env,
const ConstBufferAddr& cbuf) { const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return TexturePixelFormat::A8B8G8R8_UNORM;
}
return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf)); return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf));
} }
static inline bool IsTexturePixelFormatIntegerCached(Environment& env, static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
const ConstBufferAddr& cbuf) { const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return false;
}
return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf)); return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf));
} }
@@ -466,15 +479,43 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
}; };
} }
bool IsAttributeSourcedHandle(const IR::Value& handle) {
if (handle.IsImmediate()) {
return false;
}
const IR::Inst* inst{handle.InstRecursive()};
if (inst->GetOpcode() == IR::Opcode::BitCastU32F32 && !inst->Arg(0).IsImmediate()) {
inst = inst->Arg(0).InstRecursive();
}
return inst->GetOpcode() == IR::Opcode::GetAttribute ||
inst->GetOpcode() == IR::Opcode::GetAttributeU32;
}
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) { TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) {
ConstBufferAddr addr; ConstBufferAddr addr;
if (IsBindless(inst)) { if (IsBindless(inst)) {
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)}; const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)};
if (!track_addr) { if (track_addr) {
throw NotImplementedException("Failed to track bindless texture constant buffer");
} else {
addr = *track_addr; addr = *track_addr;
} else if (host_info.support_attribute_texture_handle &&
IsAttributeSourcedHandle(inst.Arg(0))) {
// The handle travels with the vertices (sprite batches pick the texture per quad), so
// there is no constant buffer to read it from. The host binds the handle of each run
// of vertices that share one.
addr = ConstBufferAddr{
.index = ATTRIBUTE_HANDLE_CBUF_INDEX,
.offset = 0,
.shift_left = 0,
.secondary_index = 0,
.secondary_offset = 0,
.secondary_shift_left = 0,
.dynamic_offset = {},
.count = 1,
.has_secondary = false,
};
} else {
throw NotImplementedException("Failed to track bindless texture constant buffer");
} }
} else { } else {
addr = ConstBufferAddr{ addr = ConstBufferAddr{
+4
View File
@@ -38,6 +38,10 @@ enum class TextureType : u32 {
}; };
constexpr u32 NUM_TEXTURE_TYPES = 9; constexpr u32 NUM_TEXTURE_TYPES = 9;
/// Constant buffer index marking a texture handle that the shader receives as a vertex attribute
/// instead of reading it from a constant buffer. The host supplies the handle of each draw run.
constexpr u32 ATTRIBUTE_HANDLE_CBUF_INDEX = 0xFFFF;
enum class TexturePixelFormat { enum class TexturePixelFormat {
A8B8G8R8_UNORM, A8B8G8R8_UNORM,
A8B8G8R8_SNORM, A8B8G8R8_SNORM,
+13 -3
View File
@@ -226,7 +226,17 @@ struct GPU::Impl {
} }
/// Notify rasterizer that any caches of the specified region should be invalidated /// Notify rasterizer that any caches of the specified region should be invalidated
void InvalidateRegion(DAddr addr, u64 size) { void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer();
if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) {
const u64 fence = RequestSyncOperation([rasterizer, addr, size] {
rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache);
rasterizer->OnCacheInvalidation(addr, size);
});
gpu_thread.TickGPU(is_async);
WaitForSyncOperation(fence);
return;
}
gpu_thread.InvalidateRegion(addr, size); gpu_thread.InvalidateRegion(addr, size);
} }
@@ -518,8 +528,8 @@ void GPU::FlushRegion(DAddr addr, u64 size) {
impl->FlushRegion(addr, size); impl->FlushRegion(addr, size);
} }
void GPU::InvalidateRegion(DAddr addr, u64 size) { void GPU::InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
impl->InvalidateRegion(addr, size); impl->InvalidateRegion(addr, size, preserve_gpu_writes);
} }
bool GPU::OnCPUWrite(DAddr addr, u64 size) { bool GPU::OnCPUWrite(DAddr addr, u64 size) {
+1 -1
View File
@@ -248,7 +248,7 @@ public:
void FlushRegion(DAddr addr, u64 size); void FlushRegion(DAddr addr, u64 size);
/// Notify rasterizer that any caches of the specified region should be invalidated /// Notify rasterizer that any caches of the specified region should be invalidated
void InvalidateRegion(DAddr addr, u64 size); void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes = false);
/// Notify rasterizer that CPU is trying to write this area. It returns true if the area is /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
/// sensible, false otherwise, addr and size must be a valid combination /// sensible, false otherwise, addr and size must be a valid combination
@@ -276,6 +276,9 @@ GraphicsPipeline::GraphicsPipeline(
num_textures += Shader::NumDescriptors(info->texture_descriptors); num_textures += Shader::NumDescriptors(info->texture_descriptors);
num_image_elements += Shader::NumDescriptors(info->texture_descriptors); num_image_elements += Shader::NumDescriptors(info->texture_descriptors);
num_image_elements += Shader::NumDescriptors(info->image_descriptors); num_image_elements += Shader::NumDescriptors(info->image_descriptors);
for (const auto& desc : info->texture_descriptors) {
uses_attribute_handle |= desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX;
}
num_descriptor_entries += NumDescriptorEntries(*info); num_descriptor_entries += NumDescriptorEntries(*info);
} }
fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0]; fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0];
@@ -375,6 +378,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
} }
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers}; const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
const auto read_handle{[&](const auto& desc, u32 index) { const auto read_handle{[&](const auto& desc, u32 index) {
if (desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX) {
return TexturePair(attribute_handle, via_header_index);
}
ASSERT(cbufs[desc.cbuf_index].enabled); ASSERT(cbufs[desc.cbuf_index].enabled);
const u32 index_offset{index << desc.size_shift}; const u32 index_offset{index << desc.size_shift};
const u32 offset{desc.cbuf_offset + index_offset}; const u32 offset{desc.cbuf_offset + index_offset};
@@ -110,6 +110,16 @@ public:
return configure_func(this, is_indexed); return configure_func(this, is_indexed);
} }
/// True when a shader samples a texture whose handle arrives as a vertex attribute.
[[nodiscard]] bool UsesAttributeHandle() const noexcept {
return uses_attribute_handle;
}
/// Handle bound to those textures by the next Configure.
void SetAttributeHandle(u32 handle) noexcept {
attribute_handle = handle;
}
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept { [[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
if (key == current_key) { if (key == current_key) {
return this; return this;
@@ -168,6 +178,8 @@ private:
u32 num_descriptor_entries{}; u32 num_descriptor_entries{};
size_t num_image_elements{}; size_t num_image_elements{};
u32 num_textures{}; u32 num_textures{};
u32 attribute_handle{};
bool uses_attribute_handle{};
bool fragment_has_color0_output{}; bool fragment_has_color0_output{};
vk::DescriptorSetLayout descriptor_set_layout; vk::DescriptorSetLayout descriptor_set_layout;
@@ -479,6 +479,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
.support_conditional_barrier = device.SupportsConditionalBarriers(), .support_conditional_barrier = device.SupportsConditionalBarriers(),
.support_attribute_texture_handle = true,
}; };
host_info.ApplyDescriptorLimitPolicy(); host_info.ApplyDescriptorLimitPolicy();
@@ -248,6 +248,15 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
// update engine as channel may be different. // update engine as channel may be different.
pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->SetEngine(maxwell3d, gpu_memory);
attribute_handle_pipeline = nullptr;
attribute_handle_runs.clear();
if (split_attribute_handles && pipeline->UsesAttributeHandle()) {
CollectAttributeHandleRuns(is_indexed);
if (!attribute_handle_runs.empty()) {
attribute_handle_pipeline = pipeline;
pipeline->SetAttributeHandle(attribute_handle_runs.front().handle);
}
}
if (!pipeline->Configure(is_indexed)) if (!pipeline->Configure(is_indexed))
return; return;
@@ -259,22 +268,110 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
draw_func(); draw_func();
} }
void RasterizerVulkan::CollectAttributeHandleRuns(bool is_indexed) {
using VertexAttribute = Maxwell::VertexAttribute;
const auto& regs = maxwell3d->regs;
const auto& draw_state = maxwell3d->draw_manager.draw_state;
const u32 total = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count;
if (total == 0) {
return;
}
// The handle is an integer attribute; sprite batches repeat it on every vertex of a quad.
const VertexAttribute* source{};
for (const auto& attr : regs.vertex_attrib_format) {
if (attr.constant || attr.size == VertexAttribute::Size::Invalid) {
continue;
}
if (attr.type == VertexAttribute::Type::UInt || attr.type == VertexAttribute::Type::SInt) {
source = &attr;
break;
}
}
const auto& stream = regs.vertex_streams[source ? source->buffer.Value() : 0];
if (!source || !stream.IsEnabled()) {
attribute_handle_runs.push_back({0, total, 0});
return;
}
// Only plain triangle lists are split; anything else keeps the handle of its first vertex.
const u32 primitive_size =
draw_state.topology == Maxwell::PrimitiveTopology::Triangles ? 3 : total;
const GPUVAddr base_address = stream.Address() + source->offset;
const auto read_handle = [&](u32 position) {
u32 vertex;
if (is_indexed) {
const auto& index_buffer = draw_state.index_buffer;
const GPUVAddr address =
index_buffer.IndexStart() + size_t{position} * index_buffer.FormatSizeInBytes();
u32 index{};
gpu_memory->ReadBlockUnsafe(address, &index, index_buffer.FormatSizeInBytes());
vertex = static_cast<u32>(draw_state.base_index + index);
} else {
vertex = draw_state.vertex_buffer.first + position;
}
return gpu_memory->Read<u32>(base_address + static_cast<GPUVAddr>(vertex) * stream.stride);
};
for (u32 position = 0; position + primitive_size <= total; position += primitive_size) {
const u32 handle = read_handle(position);
if (!attribute_handle_runs.empty() && attribute_handle_runs.back().handle == handle) {
attribute_handle_runs.back().count += primitive_size;
} else {
attribute_handle_runs.push_back({position, primitive_size, handle});
}
}
if (attribute_handle_runs.empty()) {
attribute_handle_runs.push_back({0, total, read_handle(0)});
} else {
const u32 covered = attribute_handle_runs.back().first + attribute_handle_runs.back().count;
if (covered < total) {
attribute_handle_runs.back().count += total - covered;
}
}
}
void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
split_attribute_handles = true;
SCOPE_EXIT {
split_attribute_handles = false;
};
PrepareDraw(is_indexed, [this, is_indexed, instance_count] { PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
const auto& draw_state = maxwell3d->draw_manager.draw_state; const auto& draw_state = maxwell3d->draw_manager.draw_state;
const u32 num_instances{instance_count}; const u32 num_instances{instance_count};
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { const auto record_draw = [this](const DrawParams& params) {
if (draw_params.is_indexed) { scheduler.Record([params](vk::CommandBuffer cmdbuf) {
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, if (params.is_indexed) {
draw_params.first_index, draw_params.base_vertex, cmdbuf.DrawIndexed(params.num_vertices, params.num_instances,
draw_params.base_instance); params.first_index, params.base_vertex,
} else { params.base_instance);
cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances, } else {
draw_params.base_vertex, draw_params.base_instance); cmdbuf.Draw(params.num_vertices, params.num_instances, params.base_vertex,
params.base_instance);
}
});
};
if (attribute_handle_pipeline && attribute_handle_runs.size() > 1) {
// The first run is already configured, each further one binds its own texture.
for (size_t i = 0; i < attribute_handle_runs.size(); ++i) {
const AttributeHandleRun& run = attribute_handle_runs[i];
if (i != 0) {
attribute_handle_pipeline->SetAttributeHandle(run.handle);
if (!attribute_handle_pipeline->Configure(is_indexed)) {
continue;
}
}
DrawParams run_params = draw_params;
run_params.num_vertices = run.count;
if (is_indexed) {
run_params.first_index += run.first;
} else {
run_params.base_vertex += run.first;
}
record_draw(run_params);
} }
}); } else {
record_draw(draw_params);
}
// Log draw call // Log draw call
if (GPU::Logging::IsActive() && if (GPU::Logging::IsActive() &&
@@ -157,6 +157,20 @@ private:
template <typename Func> template <typename Func>
void PrepareDraw(bool is_indexed, Func&&); void PrepareDraw(bool is_indexed, Func&&);
/// A stretch of a draw whose vertices all carry the same texture handle.
struct AttributeHandleRun {
u32 first;
u32 count;
u32 handle;
};
/// Splits the current draw wherever the texture handle carried in the vertex data changes.
void CollectAttributeHandleRuns(bool is_indexed);
std::vector<AttributeHandleRun> attribute_handle_runs;
GraphicsPipeline* attribute_handle_pipeline{};
bool split_attribute_handles{};
void FlushWork(); void FlushWork();
void UpdateDynamicStates(); void UpdateDynamicStates();
+3 -1
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,7 +11,6 @@
class QCheckBox; class QCheckBox;
class QLineEdit; class QLineEdit;
class QComboBox;
class QDateTimeEdit; class QDateTimeEdit;
namespace Core { namespace Core {
class System; class System;
+8 -4
View File
@@ -140,7 +140,12 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
if (combobox_enumerations.contains(type)) { if (combobox_enumerations.contains(type)) {
enumeration = &combobox_enumerations.at(type); enumeration = &combobox_enumerations.at(type);
for (const auto& [id, name] : *enumeration) { for (const auto& [id, name] : *enumeration) {
combobox->addItem(name); if (type == Settings::EnumMetadata<Settings::AppletMode>::Index() &&
id == static_cast<u32>(Settings::AppletMode::Disabled) &&
setting.Id() != Settings::values.controller_applet_mode.Id()) {
continue;
}
combobox->addItem(name, id);
} }
} else { } else {
return combobox; return combobox;
@@ -158,9 +163,8 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0); const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0);
combobox->setCurrentIndex(find_index(setting_value)); combobox->setCurrentIndex(find_index(setting_value));
serializer = [this, enumeration]() { serializer = [this]() {
int current = combobox->currentIndex(); return std::to_string(combobox->currentData().toUInt());
return std::to_string(enumeration->at(current).first);
}; };
restore_func = [this, find_index]() { restore_func = [this, find_index]() {
+15 -11
View File
@@ -12,25 +12,29 @@ namespace Yuzu {
inline bool ContainsAllWords(const QString& haystack, const QString& userinput) { inline bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts); const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(), return std::all_of(userinput_split.begin(), userinput_split.end(), [&haystack](const QString& s) {
[&haystack](const QString& s) { return haystack.contains(s); }); return haystack.contains(s);
});
} }
inline bool FilterMatches(const QString& filter, const QStandardItem* item) { inline bool FilterMatches(const QString& filter, const QStandardItem* item) {
if (filter.isEmpty()) if (filter.isEmpty())
return true; return true;
auto const sluggify = [](const QString& s) {
QString o(s.normalized(QString::NormalizationForm_D).toLower());
return o.replace(QRegularExpression(QStringLiteral("[^a-z\\s]")), QStringLiteral(""));
};
const auto norm_filter = sluggify(filter);
const auto program_id = item->data(GameListItemPath::ProgramIdRole).toULongLong(); const auto program_id = item->data(GameListItemPath::ProgramIdRole).toULongLong();
const QString file_path = sluggify(item->data(GameListItemPath::FullPathRole).toString());
const QString file_path = item->data(GameListItemPath::FullPathRole).toString().toLower(); const QString file_title = sluggify(item->data(GameListItemPath::TitleRole).toString());
const QString file_title = item->data(GameListItemPath::TitleRole).toString().toLower();
const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'}); const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
const QString file_name = sluggify(file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title);
const QString file_name = return (ContainsAllWords(file_name, norm_filter)
file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title; || ContainsAllWords(file_title, norm_filter))
|| (file_program_id.size() == 16 && file_program_id.contains(norm_filter));
return Yuzu::ContainsAllWords(file_name, filter) ||
(file_program_id.size() == 16 && file_program_id.contains(filter));
} }
} // namespace Yuzu } // namespace Yuzu
+1 -1
View File
@@ -1786,7 +1786,7 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
QtCommon::system->SetFrontendAppletSet({ QtCommon::system->SetFrontendAppletSet({
std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
(UISettings::values.controller_applet_disabled.GetValue() == true) (Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::Disabled)
? nullptr ? nullptr
: std::make_unique<QtControllerSelector>(*this), // Controller Selector : std::make_unique<QtControllerSelector>(*this), // Controller Selector
std::make_unique<QtErrorDisplay>(*this), // Error Display std::make_unique<QtErrorDisplay>(*this), // Error Display