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
59 changed files with 12200 additions and 12463 deletions
+18 -8
View File
@@ -24,8 +24,20 @@ include(CMakeDependentOption)
include(CTest)
include(CPMUtil)
if (CXX_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0")
message(FATAL_ERROR "GCC versions older than 14.0 are not supported. Update your system, or use clang/clang++ instead.")
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
endif()
# Needed for FFmpeg w/ VAAPI and DRM
if (OPENBSD)
# OpenBSD 7.8 broke libcxx when upgrading, so we must define the PSTL backend manually
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
elseif (NETBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
endif()
# NetBSD: Fun for the whole family!
@@ -73,7 +85,7 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON "WIN32 OR ANDROID OR APPLE OR LINUX OR FREEBSD" OFF)
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
# non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
@@ -264,7 +276,7 @@ cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib"
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
if (EXT_DEFAULT)
if (EXT_DEFAULT OR SOLARIS OR OPENBSD)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
endif()
@@ -297,12 +309,10 @@ if (YUZU_ROOM)
endif()
if (UNIX AND NOT (LINUX OR WIN32))
if(CXX_APPLE OR (CXX_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "20.0"))
if(CXX_APPLE OR CXX_CLANG)
# libc++ has stop_token and jthread as experimental
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexperimental-library")
elseif(CXX_CLANG)
# New clang >=20.0, so do nothing
else()
# Uses glibc, mostly?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LIBCPP_ENABLE_EXPERIMENTAL=1")
@@ -608,7 +618,7 @@ if (ENABLE_QT)
# Best practice is to ask for all components at once, so they are from the same version
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
if (NOT WIN32 AND NOT APPLE)
if (LINUX OR FREEBSD)
list(APPEND YUZU_QT_COMPONENTS DBus)
# yes Qt, we get it
set(QT_NO_PRIVATE_MODULE_WARNING ON)
+1 -1
View File
@@ -79,7 +79,7 @@
"name": "ffmpeg",
"package": "FFmpeg",
"repo": "crueter-ci/FFmpeg",
"version": "9.0.1-1788120736-bf1b838f2a"
"version": "9.0.2-1790726865-946fcce07b"
},
"fmt": {
"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
+17 -11
View File
@@ -65,7 +65,7 @@ export LIBGL_ALWAYS_SOFTWARE=1
## OmniOS
Install `developer/gcc15` on OmniOS using pkgsrc.
Install `developer/gcc14` on OmniOS using pkgsrc.
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON` and `-DYUZU_USE_BUNDLED_OPENSSL=OFF`.
@@ -74,15 +74,21 @@ For OmniOS you are required to build glslang yourself:
sudo pkg install python-313
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
cd glslang
python3 ./update_glslang_sources.py
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --build build -- -j `nproc`
cmake --install build
```
Use `gmake` to properly build all utilities. You require an X11 server, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) details how to attain one, the links to pkgsrc on said guide [are better found here](https://pkgsrc.smartos.org/install-on-illumos/).
It may be tempting to specify `-t glslang`, but this will cause installation to fail. So don't.
For Solaris based OSes, `${CMAKE_SYSTEM_PROCESSOR}` isn't properly set on CMake (it's set to i686 on AMD64, must be `amd64`), you may find issues when building OpenSSL from `openssl-cmake`.
Using `--parallel` on CMake incorrectly passes `dmake ... -jn` instead of `dmake ... -j n`, this is a bug with OmniOS's CMake, it's recommended to not use this option until it's fixed.
You may also need to install `gmake` in order to properly build FFmpeg, this is provided by the `build-essential` package.
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well.
For Solaris based OSes, `${CMAKE_SYSTEM_NAME}` isn't properly set on CMake (it's set to i686 on AMD64), you may find issues when building OpenSSL from `openssl-cmake`.
## HaikuOS
@@ -102,8 +108,6 @@ If you have `quazip1_qt6_devel`, uninstall it. It may call `Core5Compat` on CMak
## OpenBSD
OpenSSL 4.0 is available via ports, needs to be pointed to directly via `-DOPENSSL_ROOT_DIR=/usr/local/include/eopenssl40`.
System boost doesn't have `context` (as of 7.8); so you may need to specify `-DYUZU_USE_CPM=ON -DBoost_FORCE_BUNDLED=ON`.
After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`.
@@ -143,13 +147,15 @@ System provides a default `g++-10` which doesn't support the current C++ codebas
Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one.
If [parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary, build from source:
[parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary form and must be built from source.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
```sh
pkgin install python314
pkgin python313
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
cd glslang
python3.14 ./update_glslang_sources.py
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
@@ -157,7 +163,7 @@ cmake --install build
However, pkgsrc is highly recommended, see [getting pkgsrc](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/doc/pkgsrc.html#getting). You must get `current` not the `2025Q2` version.
`QtCore` on NetBSD is included, but due to misconfigurations you must include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is).
`QtCore` on NetBSD is included, but due to misconfigurations(!) we MUST include one of the standard headers that include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is). This is a bug with NetBSD packaging and not our fault, but alas.
## DragonFlyBSD
+3 -3
View File
@@ -213,7 +213,7 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/
# Enable the community repository
setup-apkrepos -c
# Install
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-qtcharts-dev libusb-dev boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev enet-dev glslang libtool jq patch
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
```
</details>
@@ -286,7 +286,7 @@ pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tool
```sh
pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1-1.0.29 quazip-qt6 openssl-4.0.2v0
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1-1.0.29 quazip-qt6
```
[Caveats](./Caveats.md#openbsd).
@@ -316,7 +316,7 @@ sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohman
<summary>OmniOS</summary>
```sh
sudo pkg install git cmake autoconf build-essential libusb-1 nasm gcc15 ffmpeg lz4 pkg-config unzip bash jq xsvc
sudo pkgin install git cmake autoconf build-essential libusb-1 nasm gcc13
```
[Caveats](./Caveats.md#omnios).
+1 -1
View File
@@ -15,7 +15,7 @@
## Cloning Eden with Git
```sh
git clone --depth=1 https://git.eden-emu.dev/eden-emu/eden.git
git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git
```
Eden by default will be cloned into:
@@ -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.NativeLibrary
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig
import java.io.File
@@ -146,11 +147,11 @@ class DriverViewModel : ViewModel() {
private fun wipeGameShaders(game: Game) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val externalFilesDir = YuzuApplication.appContext.getExternalFilesDir(null)
val userDirectory = DirectoryInitialization.userDirectory
?: return@withContext
val shaderDir = File(
externalFilesDir.absolutePath +
"/shader/" + game.settingsName.lowercase()
userDirectory +
"/cache/shader/" + game.settingsName.lowercase()
)
if (shaderDir.exists()) {
shaderDir.deleteRecursively()
+1 -1
View File
@@ -150,7 +150,7 @@ ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, Scale
ENUM(AntiAliasing, None, Fxaa, Smaa);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE);
ENUM(AppletMode, HLE, LLE, Disabled);
ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuClock, Normal, Boost, Overclock)
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);
case AppletId::NetConnect:
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
case AppletId::None:
return nullptr;
default:
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}"
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
UNIMPLEMENTED_MSG("No frontend implementation exists for applet_id={:02X} program_id={:016X}! Using stub applet.", static_cast<u8>(id), applet->program_id);
return std::make_shared<StubApplet>(system, applet, id, mode);
}
}
@@ -9,7 +9,6 @@
#include <functional>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
+30 -2
View File
@@ -16,6 +16,10 @@
#include "core/hle/service/ro/ro_types.h"
#include "core/hle/service/server_manager.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 {
@@ -386,7 +390,7 @@ public:
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) {
// Get context.
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),
std::addressof(ro_size), std::addressof(rw_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.
R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
rw_size + bss_size));
@@ -531,7 +559,7 @@ public:
Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
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));
}
+1 -1
View File
@@ -757,7 +757,7 @@ struct Memory::Impl {
};
auto& gpu = system.GPU();
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;
+3 -1
View File
@@ -67,7 +67,9 @@
#else
# define CTX_SP (_UC_MACHINE_SP(ucontext))
#endif
#elif defined(ARCHITECTURE_arm64)
#endif
#if defined(ARCHITECTURE_arm64)
# if defined(__APPLE__)
# define CTX_PC (mctx->__ss.__pc)
# define CTX_SP (mctx->__ss.__sp)
+1 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -6,7 +6,6 @@
#pragma once
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+1 -1
View File
@@ -92,7 +92,7 @@ if (ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
endif()
if (LINUX OR FREEBSD)
if (UNIX AND NOT APPLE)
if (DEFINED Qt6Gui_PRIVATE_INCLUDE_DIRS)
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
else()
+1 -3
View File
@@ -342,9 +342,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
"it bypasses such prompts and directly exits the emulation."));
INSERT(UISettings, hide_mouse, tr("Hide mouse on 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"),
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, LLE, tr("Real applet")),
PAIR(AppletMode, Disabled, tr("Disabled")),
}});
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
-2
View File
@@ -127,8 +127,6 @@ struct Values {
Setting<bool> hide_mouse{
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
true, true};
Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
Category::UiGeneral};
// Set when Vulkan is known to crash the application
bool has_broken_vulkan = false;
@@ -38,6 +38,8 @@ struct HostTranslateInfo {
///< passthrough shaders
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
///< control flow
bool support_attribute_texture_handle{}; ///< True when the host binds texture handles that
///< arrive as vertex attributes
void ApplyDescriptorLimitPolicy() noexcept {
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;
}
static inline bool IsAttributeHandle(const ConstBufferAddr& cbuf) {
return cbuf.index == ATTRIBUTE_HANDLE_CBUF_INDEX;
}
static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) {
// Must all be uniquely different variables
// 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
static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return TextureType::Color2D;
}
return env.ReadTextureType(GetTextureHandleCached(env, cbuf));
}
static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env,
const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return TexturePixelFormat::A8B8G8R8_UNORM;
}
return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf));
}
static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
const ConstBufferAddr& cbuf) {
if (IsAttributeHandle(cbuf)) {
return false;
}
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) {
ConstBufferAddr addr;
if (IsBindless(inst)) {
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)};
if (!track_addr) {
throw NotImplementedException("Failed to track bindless texture constant buffer");
} else {
if (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 {
addr = ConstBufferAddr{
+4
View File
@@ -38,6 +38,10 @@ enum class TextureType : u32 {
};
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 {
A8B8G8R8_UNORM,
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
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);
}
@@ -518,8 +528,8 @@ void GPU::FlushRegion(DAddr addr, u64 size) {
impl->FlushRegion(addr, size);
}
void GPU::InvalidateRegion(DAddr addr, u64 size) {
impl->InvalidateRegion(addr, size);
void GPU::InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
impl->InvalidateRegion(addr, size, preserve_gpu_writes);
}
bool GPU::OnCPUWrite(DAddr addr, u64 size) {
+1 -1
View File
@@ -248,7 +248,7 @@ public:
void FlushRegion(DAddr addr, u64 size);
/// 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
/// 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_image_elements += Shader::NumDescriptors(info->texture_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);
}
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 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);
const u32 index_offset{index << desc.size_shift};
const u32 offset{desc.cbuf_offset + index_offset};
@@ -110,6 +110,16 @@ public:
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 {
if (key == current_key) {
return this;
@@ -168,6 +178,8 @@ private:
u32 num_descriptor_entries{};
size_t num_image_elements{};
u32 num_textures{};
u32 attribute_handle{};
bool uses_attribute_handle{};
bool fragment_has_color0_output{};
vk::DescriptorSetLayout descriptor_set_layout;
@@ -479,6 +479,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
.support_conditional_barrier = device.SupportsConditionalBarriers(),
.support_attribute_texture_handle = true,
};
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};
// update engine as channel may be different.
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))
return;
@@ -259,22 +268,110 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, 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) {
split_attribute_handles = true;
SCOPE_EXIT {
split_attribute_handles = false;
};
PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
const auto& draw_state = maxwell3d->draw_manager.draw_state;
const u32 num_instances{instance_count};
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
if (draw_params.is_indexed) {
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
draw_params.first_index, draw_params.base_vertex,
draw_params.base_instance);
} else {
cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances,
draw_params.base_vertex, draw_params.base_instance);
const auto record_draw = [this](const DrawParams& params) {
scheduler.Record([params](vk::CommandBuffer cmdbuf) {
if (params.is_indexed) {
cmdbuf.DrawIndexed(params.num_vertices, params.num_instances,
params.first_index, params.base_vertex,
params.base_instance);
} else {
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
if (GPU::Logging::IsActive() &&
@@ -157,6 +157,20 @@ private:
template <typename 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 UpdateDynamicStates();
@@ -43,32 +43,26 @@ namespace {
switch (window_type) {
case Core::Frontend::WindowSystemType::Headless:
break;
#if defined(VK_USE_PLATFORM_WIN32_KHR)
#ifdef _WIN32
case Core::Frontend::WindowSystemType::Windows:
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
#elif defined(__APPLE__)
case Core::Frontend::WindowSystemType::Cocoa:
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
#elif defined(__ANDROID__)
case Core::Frontend::WindowSystemType::Android:
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
#elif defined(__HAIKU__)
case Core::Frontend::WindowSystemType::Xcb:
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#else
case Core::Frontend::WindowSystemType::X11:
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
case Core::Frontend::WindowSystemType::Wayland:
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
break;
@@ -8,7 +8,6 @@
#include "core/frontend/emu_window.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include "video_core/vulkan_common/vulkan.h"
namespace Vulkan {
@@ -18,7 +17,7 @@ vk::SurfaceKHR CreateSurface(
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
VkSurfaceKHR unsafe_surface = VkSurfaceKHR{};
#if defined(VK_USE_PLATFORM_WIN32_KHR)
#ifdef _WIN32
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
@@ -31,8 +30,7 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
#elif defined(__APPLE__)
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
const VkMetalSurfaceCreateInfoEXT metal_ci = {
.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
@@ -47,8 +45,7 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
#elif defined(__ANDROID__)
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
const VkAndroidSurfaceCreateInfoKHR android_ci{
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -62,8 +59,7 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
#elif defined(__HAIKU__)
if (window_info.type == Core::Frontend::WindowSystemType::Xcb) {
const VkXcbSurfaceCreateInfoKHR xcb_ci{
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
@@ -80,8 +76,7 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#else
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -95,8 +90,6 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -112,6 +105,7 @@ vk::SurfaceKHR CreateSurface(
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
+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-License-Identifier: GPL-2.0-or-later
@@ -8,7 +11,6 @@
class QCheckBox;
class QLineEdit;
class QComboBox;
class QDateTimeEdit;
namespace Core {
class System;
+8 -4
View File
@@ -140,7 +140,12 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
if (combobox_enumerations.contains(type)) {
enumeration = &combobox_enumerations.at(type);
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 {
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);
combobox->setCurrentIndex(find_index(setting_value));
serializer = [this, enumeration]() {
int current = combobox->currentIndex();
return std::to_string(enumeration->at(current).first);
serializer = [this]() {
return std::to_string(combobox->currentData().toUInt());
};
restore_func = [this, find_index]() {
+15 -11
View File
@@ -12,25 +12,29 @@ namespace Yuzu {
inline bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(),
[&haystack](const QString& s) { return haystack.contains(s); });
return std::all_of(userinput_split.begin(), userinput_split.end(), [&haystack](const QString& s) {
return haystack.contains(s);
});
}
inline bool FilterMatches(const QString& filter, const QStandardItem* item) {
if (filter.isEmpty())
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 QString file_path = item->data(GameListItemPath::FullPathRole).toString().toLower();
const QString file_title = item->data(GameListItemPath::TitleRole).toString().toLower();
const QString file_path = sluggify(item->data(GameListItemPath::FullPathRole).toString());
const QString file_title = sluggify(item->data(GameListItemPath::TitleRole).toString());
const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
const QString file_name =
file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title;
return Yuzu::ContainsAllWords(file_name, filter) ||
(file_program_id.size() == 16 && file_program_id.contains(filter));
const QString file_name = sluggify(file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title);
return (ContainsAllWords(file_name, norm_filter)
|| ContainsAllWords(file_title, norm_filter))
|| (file_program_id.size() == 16 && file_program_id.contains(norm_filter));
}
} // namespace Yuzu
+1 -1
View File
@@ -1786,7 +1786,7 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
QtCommon::system->SetFrontendAppletSet({
std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
(UISettings::values.controller_applet_disabled.GetValue() == true)
(Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::Disabled)
? nullptr
: std::make_unique<QtControllerSelector>(*this), // Controller Selector
std::make_unique<QtErrorDisplay>(*this), // Error Display