diff --git a/README.md b/README.md
index 3ae31151f7..44a2b4c28b 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,10 @@ See the [sign-up instructions](docs/SIGNUP.md) for information on registration.
Alternatively, if you wish to add translations, go to the [Eden project on Transifex](https://app.transifex.com/edenemu/eden-emulator) and review [the translations README](./dist/languages).
+## Documentation
+
+We have a user manual! See our [User Handbook](./docs/user/README.md).
+
## Building
See the [General Build Guide](docs/Build.md)
@@ -69,7 +73,9 @@ For information on provided development tooling, see the [Tools directory](./too
## Download
-You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
+You can download the latest releases from [here](https://git.eden-emu.dev/eden-emu/eden/releases).
+
+Save us some bandwidth! We have [mirrors available](./docs/user/ThirdParty.md#mirrors) as well.
## Support
diff --git a/docs/README.md b/docs/README.md
index 01727ae4dc..4ea532be8e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,5 +1,7 @@
# Eden Build Documentation
+Are you just a casual user? Take a look at our [User Handbook](./user) then!
+
This contains documentation created by developers. This contains build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil), and more.
- **[General Build Instructions](Build.md)**
@@ -11,7 +13,6 @@ This contains documentation created by developers. This contains build instructi
- **[CPM - CMake Package Manager](./CPMUtil)**
- **[Platform-Specific Caveats](Caveats.md)**
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
-- **[User Handbook](./user)**
- **[Dynarmic](./dynarmic)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**
diff --git a/docs/user/AddGamesToSRM.md b/docs/user/AddGamesToSRM.md
deleted file mode 100644
index 433999c9b6..0000000000
--- a/docs/user/AddGamesToSRM.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Importing Games into Steam with Steam Rom Manager
-
-Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
-
-**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
-
----
-
-### Pre-Requisites
-
-- Steam Deck Set up and Configured
-- Eden set up and Configured
-- Internet Access
-
----
-
-## Steps
-
-1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
-
-1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
-
- ---
-
- ### Manual Installation
-
- 1. Open the *Discover Store* and search for *Steam ROM Manager.*
- 2. Select the **Install** button to install the program.
-
- ---
-
- ### Installing Through *EmuDeck*
-
-
-
- ***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
-
-
-
- 1. Open **EmuDeck**, then navigate to *Manage Emulators.*
- 2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
-
- 3. Click the **Install** button on the right hand side to install it.
-
- ---
-
-2. Open the Start Menu and Launch ***Steam ROM Manager***
-
-1. The program will now launch and show you a window with parsers.
-
-
-
- ***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
-
-
-
-2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
-3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
-
- ---
- ### Creating the Eden Parser
-
- 1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
- 2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
- 3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
- 4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
- 5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
- 6. Leave everything else the same and hit **Save** to save the parser.
- ---
-
-4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
-1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
-1. When you are happy with the results, click the **Add Games** → **Parse** to start the actual Parsing.
-1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
-2. Review the game matches and ensure everything is there.
-
- ---
-
- ### Correcting a Mismatch
-
- If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
-
- 1. Hover over the game card and click the magnifying glass icon.
- 2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
- 3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
-
- ---
-
- ### Excluding Matches
-
- You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
-
- 1. Hit the **Exclude Games** button in the bottom right.
- 2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
- 3. Hit **Save Excludes** when you are happy with your selections.
- ---
-3. When you are happy with the results, select **Save to Steam** to save the results.
-1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
-2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
-3. Try to launch a game and ensure everything is working. You are now good to go.
\ No newline at end of file
diff --git a/docs/user/CFW.md b/docs/user/CFW.md
new file mode 100644
index 0000000000..ea224d3d36
--- /dev/null
+++ b/docs/user/CFW.md
@@ -0,0 +1,11 @@
+# User Handbook - Custom Firmware (CFW)
+
+At the moment of writing, we do not support CFW such as Atmosphere, due to:
+
+- Lacking the required LLE emulation capabilities to properly emulate the full firmware.
+- Lack of implementation on some of the key internals.
+- Nobody has bothered to do it (PRs always welcome!)
+
+We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments.
+
+If they don't run - then that's a bug!
diff --git a/docs/user/Graphics.md b/docs/user/Graphics.md
index e1e13a777d..ad359b9049 100644
--- a/docs/user/Graphics.md
+++ b/docs/user/Graphics.md
@@ -1,5 +1,7 @@
# User Handbook - Graphics
+Graphical enhancements and visual quality improvments. This doesn't cover texture mods.
+
## Visual Enhancements
### Anti-aliasing
@@ -89,7 +91,7 @@ The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe w
### HaikuOS compatibility
-HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purpouses `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
+HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purposes `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
### Fixes for Windows 10 and above having "Device loss"
diff --git a/docs/user/Mods.md b/docs/user/Mods.md
new file mode 100644
index 0000000000..11361d628c
--- /dev/null
+++ b/docs/user/Mods.md
@@ -0,0 +1,206 @@
+# User Handbook - Installing Mods
+
+## General Notes
+
+**Note:** When installing a mod, always read the mod's installation instructions.
+
+This is especially important if a mod uses a framework such as **ARCropolis**, **Skyline**, or **Atmosphere plugins**. In those cases, follow the framework's instructions instead of using Eden's normal mod folder.
+
+For example, **Super Smash Bros. Ultimate** uses such a framework. See the related section below for details.
+
+---
+
+# Installing Mods for Most Games
+
+1. Right click a game in the game list.
+2. Click **"Open Mod Data Location"**.
+3. Extract the mod into that folder.
+
+Each mod should be placed inside **its own subfolder**.
+
+---
+
+# Enabling or Disabling Mods
+
+1. Right click the game in the game list.
+2. Click **Configure Game**.
+3. In the **Add-Ons** tab, enable or disable mods, updates, and DLC by ticking or unticking their boxes.
+
+---
+
+# Important Note About SD Card Paths
+
+Some mods are designed for real Nintendo Switch consoles and refer to the **SD card root**.
+
+The emulated SD card is located at:
+
+```
+%AppData%\eden\sdmc
+```
+
+Example:
+
+```
+Switch instruction: sd:/ultimate/mods
+Eden equivalent: sdmc/ultimate/mods
+```
+
+---
+
+# Framework-Based Mods (Super Smash Bros. Ultimate)
+
+Some games require external mod frameworks instead of the built-in mod loader.
+
+The most common example is **Super Smash Bros. Ultimate**.
+
+These mods are installed directly to the **emulated SD card**, not the normal Eden mod folder.
+
+---
+
+# Installing the ARCropolis Modding Framework
+
+**Note:** Some mod packs bundle ARCropolis with their installer (for example, Smash Ult-S).
+
+---
+
+## 1. Download ARCropolis
+
+Download the latest release:
+
+https://github.com/Raytwo/ARCropolis/releases/
+
+---
+
+## 2. Install ARCropolis
+
+Extract the **`atmosphere`** folder into:
+
+```
+%AppData%\eden\sdmc
+```
+
+This is the **emulated SD card directory**.
+
+Verify installation by checking that the following file exists:
+
+```
+sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins\libarcropolis.nro
+```
+
+---
+
+## 3. Download Skyline
+
+Download the latest Skyline release:
+
+https://github.com/skyline-dev/skyline/releases
+
+Skyline used to be bundled with ARCropolis but is now distributed separately to avoid compatibility issues caused by outdated bundled versions.
+
+---
+
+## 4. Install Skyline
+
+Extract the **`exefs`** folder into:
+
+```
+sdmc\atmosphere\contents\01006A800016E000
+```
+
+The `exefs` folder should be **next to the `romfs` folder**.
+
+Verify installation by checking that the following file exists:
+
+```
+%AppData%\eden\sdmc\atmosphere\contents\01006A800016E000\exefs\subsdk9
+```
+
+---
+
+## 5. Launch the Game Once
+
+Start the game and make sure you see the **ARCropolis version text on the title screen**.
+
+This will also create the folders required for installing mods.
+
+---
+
+## 6. Install Smash Ultimate Mods
+
+Install mods inside:
+
+```
+sdmc\ultimate\mods
+```
+
+Each mod must be placed inside **its own subfolder**.
+
+Example:
+
+```
+sdmc\ultimate\mods\ExampleMod
+```
+
+---
+
+# Troubleshooting
+
+## ARCropolis text does not appear on startup
+
+Check the following:
+
+- `libarcropolis.nro` exists in:
+
+```
+sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins
+```
+
+- `subsdk9` exists in:
+
+```
+sdmc\atmosphere\contents\01006A800016E000\exefs
+```
+
+- Files were extracted to:
+
+```
+%AppData%\eden\sdmc
+```
+
+---
+
+## Mods are not loading
+
+Make sure mods are installed inside:
+
+```
+sdmc\ultimate\mods
+```
+
+Each mod must have its **own subfolder**.
+
+Correct example:
+
+```
+sdmc\ultimate\mods\ExampleMod
+```
+
+Incorrect example:
+
+```
+sdmc\ultimate\mods\ExampleMod\ExampleMod
+```
+
+---
+
+## Installing mods in the wrong folder
+
+ARCropolis mods **do not go in Eden's normal mod folder**.
+
+Do **not** install Smash mods here:
+
+```
+user\load\01006A800016E000
+```
+
+That folder is only used for traditional **RomFS mods**, not ARCropolis.
diff --git a/docs/user/README.md b/docs/user/README.md
index 5fd3a17e51..9804f4d62f 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -4,10 +4,14 @@ The "FAQ".
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
+A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md).
+
## Basics
- **[The Basics](Basics.md)**
- **[Quickstart](./QuickStart.md)**
+- **[Settings](./Settings.md)**
+- **[Installing Mods](./Mods.md)**
- **[Run On macOS](./RunOnMacOS.md)**
- **[Audio](Audio.md)**
- **[Graphics](Graphics.md)**
@@ -17,22 +21,29 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e
- **[Using Amiibo](./UsingAmiibo.md)**
- **[Using Cheats](./UsingCheats.md)**
- **[Importing Saves](./ImportingSaves.md)**
-- **[Add Eden to Steam ROM Manager](./AddEdenToSRM.md)**
-- **[Add Games to Steam ROM Manager](./AddGamesToSRM.md)**
- **[Installing Atmosphere Mods](./InstallingAtmosphereMods.md)**
- **[Installing Updates & DLCs](./InstallingUpdatesDLC.md)**
- **[Controller Profiles](./ControllerProfiles.md)**
- **[Alter Date & Time](./AlterDateTime.md)**
+## 3rd-party Integration
+
+- **[Configuring Steam ROM Manager](./SteamROM.md)**
+- **[Server hosting](ServerHosting.md)**
+- **[Syncthing Guide](./SyncthingGuide.md)**
+- **[Third Party](./ThirdParty.md)**
+ - **[Obtainium](./ThirdParty.md#configuring-obtainium)**
+ - **[ES-DE](./ThirdParty.md#configuring-es-de)**
+ - **[Mirrors](./ThirdParty.md#mirrors)**
+
## Advanced
+- **[Custom Firmware](./CFW.md)**
- **[How To Access Logs](./HowToAccessLogs.md)**
- **[Gyro Controls](./GyroControls.md)**
- **[Platforms and Architectures](Architectures.md)**
-- **[Server hosting](ServerHosting.md)**
- **[Command Line](CommandLine.md)**
- **[Native Application Development](Native.md)**
- **[Adding Boolean Settings Toggles](AddingBooleanToggles.md)**
- **[Adding Debug Knobs](./AddingDebugKnobs.md)**
-- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Testing](Testing.md)**
diff --git a/docs/user/Settings.md b/docs/user/Settings.md
new file mode 100644
index 0000000000..35fcd0c9ef
--- /dev/null
+++ b/docs/user/Settings.md
@@ -0,0 +1,54 @@
+# User Handbook - Settings
+
+As the emulator continues to grow, so does the number of settings that come and go.
+
+Most of the development adds new settings that enhance performance/compatibility, only to be removed later in newer versions due to newfound discoveries or because they were "a hacky workaround".
+
+As such, this guide will NOT mention those kind of settings, we'd rather mention settings which have a long shelf time (i.e won't get removed in future releases) and are likely to be unchanged.
+
+Some of the options are self explainatory, and they do exactly what they say they do (i.e "Pause when not in focus"); such options will be also skipped due to triviality.
+
+## Foreword
+
+Before touching the settings, please see the game boots with stock options. We try our best to ensure users can boot any game using the default settings. If they don't work, then you may try fiddling with options - but please, first use stock options.
+
+## General
+
+- `General/Force X11 as Graphics Backend`: Wayland on *NIX has prominent issues that are unlikely to be resolved; the kind that are "not our fault, it's Wayland issue", this "temporary" hack forces X11 as the backend, regardless of the desktop manager's default.
+- `General/Enable Gamemode`: This only does anything when you have Feral Interactive's Gamemode library installed somewhere, if you do, this will help boost FPS by telling the OS to explicitly prioritize *this* application for "gaming" - only for *NIX systems.
+- `Hotkeys`: Deceptively to remove a hotkey you must right click and a menu will appear to remove that specific hotkey.
+- `UI/Language`: Changes language *of the interface* NOT the emulated program!
+- `Debug/Enable Auto Stub`: May help to "fix" some games by just lying and saying that everything they do returns "success" instead of outright crashing for any function/service that is NOT implemented.
+- `Debug/Show log in console`: Does as said, note that the program may need to be reopened (Windows) for changes to take effect.
+- `Debug/Flush log output`: Classically, every write to the log is "buffered", that is, changes aren't written to the disk UNTIL the program has decided it is time to write, until then it keeps data in a buffer which resides on RAM. If the program crashes, the OS will automatically discard said buffer (any RAM associated with a dead process is automatically discarded/reused for some other purpose); this means critical data may not be logged to the disk on time, which may lead to missing log lines. Use this if you're wanting to remove that factor when debugging, sometimes a hard crash may "eat" some of the log lines IF this option isn't enabled.
+- `Debug/Disable Macro HLE:` The emulator has HLE emulation of macro programs for Maxwell, this means that some details are purpousefully skipped; this option forces all macro programs to be ran without skipping anything.
+
+## System
+
+- `System/RNG Seed`: Set to 0 (and uncheck) to disable ASLR systemwide (this makes mods like CTGP to stop working); by default it enables ASLR to replicate console behaviour.
+- `Network/Enable Airplane Mode`: Enable this if a game is crashing before loading AND the logs mention anything related to "web" or "internet" services.
+
+## CPU
+
+- `CPU/Virtual table bouncing`: Some games have the tendency to crash on loading due to an indirect bad jump (Pokemon ZA being the worst offender); this option lies to the game and tells it to just pretend it never executed a given function. This is fine for most casual users, but developers of switch applications **must** disable this. This temporary "hack" should hopefully be gone in 6-7 months from now on.
+- `Fastmem`, aka. `CPU/Enable Host MMU`: Enables "fastmem"; a detailed description of fastmem can be found [here](../dynarmic/Design.md#fast-memory-fastmem).
+- `CPU/Unsafe FMA`: Enables deliberate innacurate FMA behaviour which may affect how FMA returns any given operation - this may introduce tiny floating point errors which can cascade in sensitive code (i.e FFmpeg).
+- `CPU/Faster FRSQRTE and FRECPE`: Introduces accuracy errors on square root and reciprocals in exchange for less checks - this introduces inaccuracies with some cases but it's mostly safe.
+- `CPU/Faster ASIMD Instructions`: Skips rounding mode checks for ARM ASIMD instructions - this means some code dpeending on these rounding modes may misbehave.
+- `CPU/Disable address space checks`: Before each memory access, the emulator checks the address is in range, if not it faults; this option makes it so the emulator skips the check entirely (which may be expensive for a myriad of reasons). However at the same time this allows the guest program to "break out" of the emulation context by writing to arbitrary addresses.
+- `CPU/Ignore global monitor`: This relies on a quirk present on x86 to avoid the ARM global monitor emulation, this may increase performance in mutex-heavy contexts (i.e games waiting for next frames or such); but also can cause deadlocks and fun to debug issues.
+
+It is important to note the majority of precision-reducing instructions do not benefit cases where they are not used, which means the performance gains will vary per game.
+
+# Graphics
+
+See also [an extended breakdown of some options](./Graphics.md).
+
+- `Extras/Extended Dynamic State` and `Extras/Vertex Input Dynamic State`: These Vulkan extensions essentially allow you to reuse the same pipeline but just change the state between calls (so called "dynamic state"); the "extended" levels signifies how much state can be placed on this "dynamic" range, for example the amount of depth culling to use can be placed on the dynamic state, avoiding costly reloads and flushes. While this by itself is a fine option, SOME vendors (notably PowerVR and Mali) have problems with anything related to EDS3. EDS3 contains EDS2, and EDS2 contains EDS1. Essentially this means more extended data the driver has to keep track of, at the benefit of avoiding costly flushes.
+- `Advanced/Use persistent cache`: This saves compiled shaders onto the disk, independent of any driver's own disk saved shaders (yes, some drivers, notably NVIDIA, save a secondary shader cache onto disk) - disable this only if you're debugging or working on the GPU backend. This option is meant to massively help to reduce shader stutters (after playing for one session that compiles them).
+- `Advanced/Use Vulkan pipeline cache`: This is NOT the same as `Use persistent cache`; it's a separate flag that tells the Vulkan backend to create pipeline caches, which are a detail that can be used to massively improve performance and remove pipeline creation overhead. This is a Vulkan feature.
+
+## Controls
+
+Most of the controls should work out of the box. If not, please use a joystick calibrator to ensure it's not an issue with your own controller, for example:
+- https://github.com/dkosmari/calibrate-joystick
diff --git a/docs/user/AddEdenToSRM.md b/docs/user/SteamROM.md
similarity index 50%
rename from docs/user/AddEdenToSRM.md
rename to docs/user/SteamROM.md
index 4658bcf7e0..a782b51969 100644
--- a/docs/user/AddEdenToSRM.md
+++ b/docs/user/SteamROM.md
@@ -1,4 +1,6 @@
-# Importing Eden into Steam with Steam Rom Manager
+# User Handbook - Configuring Steam ROM Manager
+
+## Importing Eden into Steam with Steam Rom Manager
Use this when you want to import the Eden AppImage into your Steam Library along with artwork using *Steam ROM Manager.*
@@ -6,7 +8,7 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
-### Pre-Requisites
+#### Pre-Requisites
- Eden set up and configured
- Internet Connection
@@ -14,9 +16,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
-## Steps
+### Steps
-### Initial Setup
+#### Initial Setup
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
@@ -24,14 +26,14 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
- ### Manual Installation
+ #### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
- ### Installing Through *EmuDeck*
+ #### Installing Through *EmuDeck*
@@ -45,9 +47,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
-### Adding Eden into *Steam ROM Manager*
+#### Adding Eden into *Steam ROM Manager*
-### EmuDeck Users
+#### EmuDeck Users
EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam ROM Manager*** that uses shell scripts to launch them. We will follow this convention.
@@ -87,7 +89,7 @@ EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam
---
-### Non-EmuDeck Users
+#### Non-EmuDeck Users
We will need to create a new parser for the Emulators. Unlike with the EmuDeck model, we will have the parser look for AppImages.
@@ -126,7 +128,7 @@ We will need to create a new parser for the Emulators. Unlike with the EmuDeck
---
-### Adding Eden to Steam
+#### Adding Eden to Steam
Now that we have the parser or shell script created, we can actually add it to Steam.
@@ -137,7 +139,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
- ### Correcting a Mismatch
+ #### Correcting a Mismatch
If the emulator is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
@@ -147,7 +149,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
- ### Excluding Matches
+ #### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files that it finds in the directory. This is how you do so.
@@ -159,4 +161,105 @@ Now that we have the parser or shell script created, we can actually add it to S
5. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
6. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
-7. Try to launch the Emulator from Steam and ensure everything is working. You are now good to go.
\ No newline at end of file
+7. Try to launch the Emulator from Steam and ensure everything is working. You are now good to go.
+
+## Importing Games into Steam with Steam Rom Manager
+
+Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
+
+**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
+
+---
+
+#### Pre-Requisites
+
+- Steam Deck Set up and Configured
+- Eden set up and Configured
+- Internet Access
+
+---
+
+### Steps
+
+1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
+
+1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
+
+ ---
+
+ #### Manual Installation
+
+ 1. Open the *Discover Store* and search for *Steam ROM Manager.*
+ 2. Select the **Install** button to install the program.
+
+ ---
+
+ #### Installing Through *EmuDeck*
+
+
+
+ ***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
+
+
+
+ 1. Open **EmuDeck**, then navigate to *Manage Emulators.*
+ 2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
+
+ 3. Click the **Install** button on the right hand side to install it.
+
+ ---
+
+2. Open the Start Menu and Launch ***Steam ROM Manager***
+
+1. The program will now launch and show you a window with parsers.
+
+
+
+ ***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
+
+
+
+2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
+3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
+
+ ---
+ #### Creating the Eden Parser
+
+ 1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
+ 2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
+ 3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
+ 4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
+ 5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
+ 6. Leave everything else the same and hit **Save** to save the parser.
+ ---
+
+4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
+1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
+1. When you are happy with the results, click the **Add Games** → **Parse** to start the actual Parsing.
+1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
+2. Review the game matches and ensure everything is there.
+
+ ---
+
+ #### Correcting a Mismatch
+
+ If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
+
+ 1. Hover over the game card and click the magnifying glass icon.
+ 2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
+ 3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
+
+ ---
+
+ #### Excluding Matches
+
+ You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
+
+ 1. Hit the **Exclude Games** button in the bottom right.
+ 2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
+ 3. Hit **Save Excludes** when you are happy with your selections.
+ ---
+3. When you are happy with the results, select **Save to Steam** to save the results.
+1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
+2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
+3. Try to launch a game and ensure everything is working. You are now good to go.
diff --git a/docs/user/ThirdParty.md b/docs/user/ThirdParty.md
index af8942b49c..083542cd3e 100644
--- a/docs/user/ThirdParty.md
+++ b/docs/user/ThirdParty.md
@@ -7,3 +7,62 @@ While most of the links mentioned in this guide are relatively "safe"; we urge u
- [Nightly Eden builds](https://github.com/pflyly/eden-nightly)
- [NixOS Eden Flake](https://github.com/Grantimatter/eden-flake)
- [ES-DE Frontend Support](https://github.com/GlazedBelmont/es-de-android-custom-systems)
+
+## Mirrors
+
+The main origin repository is always at https://git.eden-emu.dev/eden-emu/eden.
+
+- https://github.com/eden-emulator/mirror
+- https://git.crueter.xyz/mirror/eden
+- https://collective.taymaerz.de/eden/eden
+
+Other mirrors obviously exist on the internet, but we can't guarantee their reliability and/or availability.
+
+If you're someone wanting to make a mirror, simply setup forgejo and automatically mirror from the origin repository. Or you could mirror a mirror to save us bandwidth... your choice!
+
+## Configuring Obtainium
+
+Very nice handy app, here's a quick rundown how to configure:
+
+1. Copy the URL: https://git.eden-emu.dev/eden-emu/eden/ (or one of your favourite mirrors)
+2. Open Obtainium and tap `Add App`.
+3. Paste the URL into the `App Source URL` field.
+4. Override Source: Look for the `Override Source` dropdown menu and select `Forgejo (Codeberg)`.
+5. Click `Add:` Obtainium should now be able to parse the releases and find the APK files.
+
+Note: Even though the site isn't Codeberg, it uses the same Forgejo/Gitea backend, and this setting tells Obtainium how to read the release data.
+
+## Configuring ES-DE
+
+### Method 1
+
+1. Download ZIP from [here](https://github.com/GlazedBelmont/es-de-android-custom-systems)
+2. Unzip the file and extract `es_systems.xml` and `es_find_rules.xml` to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
+3. Press `Start -> Other Settings -> Alternative Emulators` and set it to Eden (Standalone).
+
+### Method 2
+
+1. Navigate to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
+2. Add this to your `es_find_rules.xml`:
+
+```xml
+
+
+
+ dev.eden.eden_emulator/org.yuzu.yuzu_emu.activities.EmulationActivity
+
+
+
+
+
+
+ com.miHoYo.Yuanshen/org.yuzu.yuzu_emu.activities.EmulationActivity
+
+
+```
+
+3. Add this line of text to your `es_systems.xml` underneath where the rest of your switch system entries are:
+
+```xml
+%EMULATOR_EDEN% %ACTION%=android.nfc.action.TECH_DISCOVERED %DATA%=%ROMPROVIDER%
+```
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
index a8ec82e560..5566423af6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -10,6 +10,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.LifecycleOwner
+import com.google.android.material.button.MaterialButton
+import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
@@ -89,29 +91,33 @@ class GamePropertiesAdapter(
val hasVisibleActions = submenuProperty.secondaryActions?.any { it.isShown } == true
+ binding.layoutSecondaryActions.removeAllViews()
+ binding.dividerSecondaryActions.setVisible(false)
if (hasVisibleActions) {
- binding.dividerSecondaryActions.setVisible(true)
binding.layoutSecondaryActions.setVisible(true)
- submenuProperty.secondaryActions!!.forEach { secondaryAction ->
- if (secondaryAction.isShown) {
- val button = com.google.android.material.button.MaterialButton(
- binding.root.context,
- null,
- com.google.android.material.R.attr.materialButtonOutlinedStyle
- ).apply {
- setIconResource(secondaryAction.iconId)
- iconSize = (18 * binding.root.context.resources.displayMetrics.density).toInt()
- text = binding.root.context.getString(secondaryAction.descriptionId)
- contentDescription = binding.root.context.getString(secondaryAction.descriptionId)
- setOnClickListener { secondaryAction.action.invoke() }
- }
- binding.layoutSecondaryActions.addView(button)
+ val visibleActions = submenuProperty.secondaryActions!!.filter { it.isShown }
+ val inflater = LayoutInflater.from(binding.root.context)
+ visibleActions.forEachIndexed { index, secondaryAction ->
+ val button = inflater.inflate(
+ R.layout.item_secondary_action_button,
+ binding.layoutSecondaryActions,
+ false
+ ) as MaterialButton
+ button.setIconResource(secondaryAction.iconId)
+ button.text = ""
+ button.contentDescription = binding.root.context
+ .getString(secondaryAction.descriptionId)
+ button.tooltipText = binding.root.context
+ .getString(secondaryAction.descriptionId)
+ if (index == visibleActions.lastIndex) {
+ (button.layoutParams as ViewGroup.MarginLayoutParams).marginEnd = 0
}
+ button.setOnClickListener { secondaryAction.action.invoke() }
+ binding.layoutSecondaryActions.addView(button)
}
} else {
- binding.dividerSecondaryActions.setVisible(false)
binding.layoutSecondaryActions.setVisible(false)
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt
index 57fd551e02..6d5c6ef23f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.dialogs
@@ -14,6 +14,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
+import android.widget.FrameLayout
import androidx.core.content.getSystemService
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.DividerItemDecoration
@@ -58,6 +59,30 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
setupSearchBar()
}
+ override fun onStart() {
+ super.onStart()
+
+ window?.setLayout(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+
+ val bottomSheet =
+ findViewById(com.google.android.material.R.id.design_bottom_sheet)
+ if (bottomSheet != null) {
+ bottomSheet.layoutParams = bottomSheet.layoutParams.apply {
+ width = ViewGroup.LayoutParams.MATCH_PARENT
+ height = ViewGroup.LayoutParams.MATCH_PARENT
+ }
+ bottomSheet.requestLayout()
+ }
+
+ behavior.isFitToContents = false
+ behavior.expandedOffset = 0
+ behavior.skipCollapsed = true
+ behavior.state = BottomSheetBehavior.STATE_EXPANDED
+ }
+
private fun setupRecyclerView() {
adapter = LobbyRoomAdapter { room -> handleRoomSelection(room) }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index 37a331b385..0f89533d8e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
@@ -27,7 +27,7 @@ object Settings {
SECTION_APP_SETTINGS(R.string.app_settings),
SECTION_CUSTOM_PATHS(R.string.preferences_custom_paths),
SECTION_DEBUG(R.string.preferences_debug),
- SECTION_FREEDRENO(R.string.gpu_driver_settings),
+ SECTION_FREEDRENO(R.string.freedreno_settings_title),
SECTION_APPLETS(R.string.applets_menu);
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
index dd932fcafb..11be703536 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -111,10 +111,18 @@ class SettingsActivity : AppCompatActivity() {
if (navHostFragment.childFragmentManager.backStackEntryCount > 0) {
navHostFragment.navController.popBackStack()
} else {
- finish()
+ finishWithFragmentLikeAnimation()
}
}
+ private fun finishWithFragmentLikeAnimation() {
+ finish()
+ overridePendingTransition(
+ androidx.navigation.ui.R.anim.nav_default_pop_enter_anim,
+ androidx.navigation.ui.R.anim.nav_default_pop_exit_anim
+ )
+ }
+
override fun onStart() {
super.onStart()
if (!DirectoryInitialization.areDirectoriesReady) {
@@ -170,7 +178,7 @@ class SettingsActivity : AppCompatActivity() {
getString(R.string.settings_reset),
Toast.LENGTH_LONG
).show()
- finish()
+ finishWithFragmentLikeAnimation()
}
private fun setInsets() {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
index 2f527b5f62..667141725d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -98,23 +98,8 @@ class SettingsFragment : Fragment() {
activity
)
- binding.toolbarSettingsLayout.title = if (args.menuTag == Settings.MenuTag.SECTION_ROOT &&
- args.game != null
- ) {
- args.game!!.title
- } else {
- when (args.menuTag) {
- Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
- Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
- Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
- Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
- Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
- Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
- Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
- Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
- else -> getString(args.menuTag.titleId)
- }
- }
+ val toolbarTitle = resolveToolbarTitle()
+ configureToolbar(toolbarTitle)
binding.listSettings.apply {
adapter = settingsAdapter
@@ -193,11 +178,9 @@ class SettingsFragment : Fragment() {
}
presenter.onViewCreated()
-
setInsets()
}
-
- private fun getPlayerIndex(): Int =
+private fun getPlayerIndex(): Int =
when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> 1
@@ -210,6 +193,27 @@ class SettingsFragment : Fragment() {
else -> -1
}
+ private fun resolveToolbarTitle(): String {
+ if (args.menuTag == Settings.MenuTag.SECTION_ROOT && args.game != null) {
+ return args.game!!.title
+ }
+ return when (args.menuTag) {
+ Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
+ Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
+ else -> getString(args.menuTag.titleId)
+ }
+ }
+
+ private fun configureToolbar(title: String) {
+ binding.toolbarSettings.title = title
+ }
+
private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index 77104e0614..ff25584c92 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.features.settings.ui
import android.annotation.SuppressLint
import android.os.Build
import android.widget.Toast
-import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
@@ -27,11 +26,9 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
-import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
-import androidx.core.content.edit
import androidx.fragment.app.FragmentActivity
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
@@ -183,16 +180,6 @@ class SettingsFragmentPresenter(
menuKey = MenuTag.SECTION_DEBUG
)
)
- if (GpuDriverHelper.isAdrenoGpu() && !NativeConfig.isPerGameConfigLoaded()) {
- add(
- SubmenuSetting(
- titleId = R.string.gpu_driver_settings,
- descriptionId = R.string.freedreno_settings_title,
- iconId = R.drawable.ic_graphics,
- menuKey = MenuTag.SECTION_FREEDRENO
- )
- )
- }
add(
SubmenuSetting(
titleId = R.string.applets_menu,
@@ -1084,27 +1071,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.theme_and_color))
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- add(
- SingleChoiceSetting(
- theme,
- titleId = R.string.change_app_theme,
- choicesId = R.array.themeEntriesA12,
- valuesId = R.array.themeValuesA12
- )
- )
- } else {
- add(
- SingleChoiceSetting(
- theme,
- titleId = R.string.change_app_theme,
- choicesId = R.array.themeEntries,
- valuesId = R.array.themeValues
- )
- )
- }
-
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt()
override fun setInt(value: Int) {
@@ -1126,6 +1092,35 @@ class SettingsFragmentPresenter(
}
}
+ add(
+ SingleChoiceSetting(
+ themeMode,
+ titleId = R.string.change_theme_mode,
+ choicesId = R.array.themeModeEntries,
+ valuesId = R.array.themeModeValues
+ )
+ )
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ add(
+ SingleChoiceSetting(
+ theme,
+ titleId = R.string.change_app_theme,
+ choicesId = R.array.themeEntriesA12,
+ valuesId = R.array.themeValuesA12
+ )
+ )
+ } else {
+ add(
+ SingleChoiceSetting(
+ theme,
+ titleId = R.string.change_app_theme,
+ choicesId = R.array.themeEntries,
+ valuesId = R.array.themeValues
+ )
+ )
+ }
+
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
IntSetting.STATIC_THEME_COLOR.getInt(needsGlobal)
@@ -1149,15 +1144,6 @@ class SettingsFragmentPresenter(
}
}
- add(
- SingleChoiceSetting(
- themeMode,
- titleId = R.string.change_theme_mode,
- choicesId = R.array.themeModeEntries,
- valuesId = R.array.themeModeValues
- )
- )
-
if (IntSetting.THEME.getInt() != 1) {
add(
SingleChoiceSetting(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
index 9745970c5b..7fec413b66 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
@@ -1,7 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// SPDX-FileCopyrightText: 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -54,8 +51,8 @@ class AboutFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
-
binding.toolbarAbout.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt
index 573549d84b..96b7a8cce2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -19,7 +19,6 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
-import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.AddonAdapter
import org.yuzu.yuzu_emu.databinding.FragmentAddonsBinding
@@ -42,7 +41,7 @@ class AddonsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- addonViewModel.onOpenAddons(args.game)
+ addonViewModel.onAddonsViewCreated(args.game)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
@@ -122,12 +121,14 @@ class AddonsFragment : Fragment() {
override fun onResume() {
super.onResume()
- addonViewModel.refreshAddons()
+ addonViewModel.onAddonsViewStarted(args.game)
}
override fun onDestroy() {
+ if (activity?.isChangingConfigurations != true) {
+ addonViewModel.onCloseAddons()
+ }
super.onDestroy()
- addonViewModel.onCloseAddons()
}
val installAddon =
@@ -167,7 +168,7 @@ class AddonsFragment : Fragment() {
} catch (_: Exception) {
return@newInstance errorMessage
}
- addonViewModel.refreshAddons()
+ addonViewModel.refreshAddons(force = true)
return@newInstance getString(R.string.addon_installed_successfully)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
} else {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
index 525fbd9f91..e2b652dc60 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
@@ -29,6 +29,7 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter
import org.yuzu.yuzu_emu.model.DriverViewModel
+import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.IOException
@@ -87,6 +88,7 @@ class DriverFetcherFragment : Fragment() {
private lateinit var driverGroupAdapter: DriverGroupAdapter
private val driverViewModel: DriverViewModel by activityViewModels()
+ private val homeViewModel: HomeViewModel by activityViewModels()
private fun parseAdrenoModel(): Int {
if (gpuModel == null) {
@@ -138,7 +140,7 @@ class DriverFetcherFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
-
+ homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarDrivers.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt
index 40111272d5..2eb77690ca 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/FreedrenoSettingsFragment.kt
@@ -22,6 +22,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
import org.yuzu.yuzu_emu.utils.FreedrenoPresets
+import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class FreedrenoSettingsFragment : Fragment() {
@@ -74,10 +75,15 @@ class FreedrenoSettingsFragment : Fragment() {
binding.toolbarFreedreno.setNavigationOnClickListener {
requireActivity().onBackPressedDispatcher.onBackPressed()
}
- if (isPerGameConfig) {
- binding.toolbarFreedreno.title = getString(R.string.freedreno_per_game_title)
- binding.toolbarFreedreno.subtitle = game!!.title
- }
+
+ binding.toolbarFreedreno.title = getString(
+ if (isPerGameConfig) {
+ R.string.freedreno_per_game_title
+ } else {
+ R.string.freedreno_settings_title
+ }
+ )
+ binding.toolbarFreedreno.subtitle = null
}
private fun setupAdapters() {
@@ -175,17 +181,19 @@ class FreedrenoSettingsFragment : Fragment() {
private fun setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
- val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- binding.root.updatePadding(
- left = systemInsets.left,
- right = systemInsets.right,
- bottom = systemInsets.bottom
- )
+ val barInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
+ val cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
+
+ val leftInsets = barInsets.left + cutoutInsets.left
+ val rightInsets = barInsets.right + cutoutInsets.right
+
+ binding.appbarFreedreno.updateMargins(left = leftInsets, right = rightInsets)
+ binding.scrollFreedreno.updateMargins(left = leftInsets, right = rightInsets)
+ binding.scrollFreedreno.updatePadding(bottom = barInsets.bottom)
insets
}
}
-
- private fun showSnackbar(message: String) {
+private fun showSnackbar(message: String) {
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
index 97b0470feb..9e55297846 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -310,6 +310,21 @@ class GamePropertiesFragment : Fragment() {
)
)
+ if (!args.game.isHomebrew) {
+ add(
+ SubmenuProperty(
+ R.string.add_ons,
+ R.string.add_ons_description,
+ R.drawable.ic_edit,
+ action = {
+ val action = GamePropertiesFragmentDirections
+ .actionPerGamePropertiesFragmentToAddonsFragment(args.game)
+ binding.root.findNavController().navigate(action)
+ }
+ )
+ )
+ }
+
if (GpuDriverHelper.supportsCustomDriverLoading()) {
add(
SubmenuProperty(
@@ -341,18 +356,6 @@ class GamePropertiesFragment : Fragment() {
}
if (!args.game.isHomebrew) {
- add(
- SubmenuProperty(
- R.string.add_ons,
- R.string.add_ons_description,
- R.drawable.ic_edit,
- action = {
- val action = GamePropertiesFragmentDirections
- .actionPerGamePropertiesFragmentToAddonsFragment(args.game)
- binding.root.findNavController().navigate(action)
- }
- )
- )
add(
InstallableProperty(
R.string.save_data,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
index 918478bf85..6f4bf858ea 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
@@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
package org.yuzu.yuzu_emu.fragments
import android.Manifest
@@ -44,7 +41,9 @@ import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.FileUtil
+import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
+import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class HomeSettingsFragment : Fragment() {
private var _binding: FragmentHomeSettingsBinding? = null
@@ -71,8 +70,12 @@ class HomeSettingsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- homeViewModel.setStatusBarShadeVisibility(visible = true)
+ homeViewModel.setStatusBarShadeVisibility(visible = false)
mainActivity = requireActivity() as MainActivity
+ binding.toolbarHomeSettings.setNavigationOnClickListener {
+ findNavController().popBackStack()
+ }
+ binding.toolbarHomeSettings.title = getString(R.string.preferences_settings)
val optionsList: MutableList = mutableListOf().apply {
add(
@@ -144,6 +147,18 @@ class HomeSettingsFragment : Fragment() {
driverViewModel.selectedDriverTitle
)
)
+ if (GpuDriverHelper.isAdrenoGpu()) {
+ add(
+ HomeSetting(
+ R.string.freedreno_settings_title,
+ R.string.gpu_driver_settings,
+ R.drawable.ic_graphics,
+ {
+ binding.root.findNavController().navigate(R.id.freedrenoSettingsFragment)
+ }
+ )
+ )
+ }
add(
HomeSetting(
R.string.multiplayer,
@@ -465,19 +480,22 @@ class HomeSettingsFragment : Fragment() {
}
private fun setInsets() =
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
+ ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
+ binding.appbarHomeSettings.updateMargins(
+ left = barInsets.left + cutoutInsets.left,
+ right = barInsets.right + cutoutInsets.right
+ )
+
binding.scrollViewSettings.updatePadding(
- top = barInsets.top
+ bottom = barInsets.bottom
)
binding.homeSettingsList.updatePadding(
left = barInsets.left + cutoutInsets.left,
- top = cutoutInsets.top,
- right = barInsets.right + cutoutInsets.right,
- bottom = barInsets.bottom
+ right = barInsets.right + cutoutInsets.right
)
windowInsets
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt
index 2a0e72be26..2331630c4e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt
@@ -18,7 +18,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
import java.util.concurrent.atomic.AtomicBoolean
class AddonViewModel : ViewModel() {
- private val _patchList = MutableStateFlow(mutableListOf())
+ private val _patchList = MutableStateFlow>(emptyList())
val addonList get() = _patchList.asStateFlow()
private val _showModInstallPicker = MutableStateFlow(false)
@@ -31,34 +31,62 @@ class AddonViewModel : ViewModel() {
val addonToDelete = _addonToDelete.asStateFlow()
var game: Game? = null
+ private var loadedGameKey: String? = null
private val isRefreshing = AtomicBoolean(false)
+ private val pendingRefresh = AtomicBoolean(false)
- fun onOpenAddons(game: Game) {
+ fun onAddonsViewCreated(game: Game) {
this.game = game
- refreshAddons()
+ refreshAddons(commitEmpty = false)
}
- fun refreshAddons() {
- if (isRefreshing.get() || game == null) {
+ fun onAddonsViewStarted(game: Game) {
+ this.game = game
+ val hasLoadedCurrentGame = loadedGameKey == gameKey(game)
+ refreshAddons(force = !hasLoadedCurrentGame)
+ }
+
+ fun refreshAddons(force: Boolean = false, commitEmpty: Boolean = true) {
+ val currentGame = game ?: return
+ val currentGameKey = gameKey(currentGame)
+ if (!force && loadedGameKey == currentGameKey) {
return
}
- isRefreshing.set(true)
+ if (!isRefreshing.compareAndSet(false, true)) {
+ if (force) {
+ pendingRefresh.set(true)
+ }
+ return
+ }
+
viewModelScope.launch {
- withContext(Dispatchers.IO) {
- val patchList = (
- NativeLibrary.getPatchesForFile(game!!.path, game!!.programId)
- ?: emptyArray()
- ).toMutableList()
+ try {
+ val patches = withContext(Dispatchers.IO) {
+ NativeLibrary.getPatchesForFile(currentGame.path, currentGame.programId)
+ } ?: return@launch
+
+ val patchList = patches.toMutableList()
patchList.sortBy { it.name }
// Ensure only one update is enabled
ensureSingleUpdateEnabled(patchList)
removeDuplicates(patchList)
+ if (patchList.isEmpty() && !commitEmpty) {
+ return@launch
+ }
+ if (gameKey(game ?: return@launch) != currentGameKey) {
+ return@launch
+ }
- _patchList.value = patchList
+ _patchList.value = patchList.toList()
+ loadedGameKey = currentGameKey
+ } finally {
isRefreshing.set(false)
+ if (pendingRefresh.compareAndSet(true, false)) {
+ refreshAddons(force = true)
+ }
}
}
}
@@ -119,17 +147,26 @@ class AddonViewModel : ViewModel() {
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
- refreshAddons()
+ refreshAddons(force = true)
}
fun onCloseAddons() {
- if (_patchList.value.isEmpty()) {
+ val currentGame = game ?: run {
+ _patchList.value = emptyList()
+ loadedGameKey = null
+ return
+ }
+ val currentList = _patchList.value
+ if (currentList.isEmpty()) {
+ _patchList.value = emptyList()
+ loadedGameKey = null
+ game = null
return
}
NativeConfig.setDisabledAddons(
- game!!.programId,
- _patchList.value.mapNotNull {
+ currentGame.programId,
+ currentList.mapNotNull {
if (it.enabled) {
null
} else {
@@ -148,7 +185,8 @@ class AddonViewModel : ViewModel() {
}.toTypedArray()
)
NativeConfig.saveGlobalConfig()
- _patchList.value.clear()
+ _patchList.value = emptyList()
+ loadedGameKey = null
game = null
}
@@ -159,4 +197,8 @@ class AddonViewModel : ViewModel() {
fun showModNoticeDialog(show: Boolean) {
_showModNoticeDialog.value = show
}
+
+ private fun gameKey(game: Game): String {
+ return "${game.programId}|${game.path}"
+ }
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index db4cc0f60e..74a171cf1f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -642,7 +642,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
- addonViewModel.refreshAddons()
+ addonViewModel.refreshAddons(force = true)
val separator = System.lineSeparator() ?: "\n"
val installResult = StringBuilder()
diff --git a/src/android/app/src/main/res/drawable/item_release_box.xml b/src/android/app/src/main/res/drawable/item_release_box.xml
index 2f2ada1961..0e692713a8 100644
--- a/src/android/app/src/main/res/drawable/item_release_box.xml
+++ b/src/android/app/src/main/res/drawable/item_release_box.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml b/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml
new file mode 100644
index 0000000000..88d06d4873
--- /dev/null
+++ b/src/android/app/src/main/res/layout-land/dialog_lobby_browser.xml
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/android/app/src/main/res/layout-land/dialog_multiplayer_connect.xml b/src/android/app/src/main/res/layout-land/dialog_multiplayer_connect.xml
new file mode 100644
index 0000000000..7a9064f9b9
--- /dev/null
+++ b/src/android/app/src/main/res/layout-land/dialog_multiplayer_connect.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/android/app/src/main/res/layout-land/fragment_games.xml b/src/android/app/src/main/res/layout-land/fragment_games.xml
index da778eab69..4d492c6c4b 100644
--- a/src/android/app/src/main/res/layout-land/fragment_games.xml
+++ b/src/android/app/src/main/res/layout-land/fragment_games.xml
@@ -44,7 +44,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="4dp"
>
@@ -103,7 +108,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -127,7 +137,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -151,7 +166,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
diff --git a/src/android/app/src/main/res/layout-w1000dp/card_installable_icon.xml b/src/android/app/src/main/res/layout-w1000dp/card_installable_icon.xml
index 59ee1aad30..6fe4256c49 100644
--- a/src/android/app/src/main/res/layout-w1000dp/card_installable_icon.xml
+++ b/src/android/app/src/main/res/layout-w1000dp/card_installable_icon.xml
@@ -12,70 +12,83 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:orientation="horizontal"
- android:gravity="center_vertical"
+ android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
-
-
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
-
+
-
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+
+
+
+
+
-
+ android:layout_marginTop="10dp"
+ android:gravity="end|center_vertical"
+ android:orientation="horizontal">
-
+
+
+
+
+
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
index 4e3c738be5..ae2b3e3637 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
@@ -5,6 +5,7 @@
android:id="@+id/coordinator_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="?attr/colorSurface"
>
+ android:focusable="true"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
+ android:layout_marginVertical="12dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardCornerRadius="16dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
+ android:paddingTop="4dp"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"
+ android:paddingBottom="2dp">
+ android:paddingTop="3dp"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"
+ android:paddingBottom="3dp">
+ app:cardCornerRadius="16dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
+ android:layout_marginVertical="12dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardCornerRadius="16dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
-
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
-
+
+
+
+
+
diff --git a/src/android/app/src/main/res/layout/card_installable_icon.xml b/src/android/app/src/main/res/layout/card_installable_icon.xml
index 4ae5423b10..6313b7fbaf 100644
--- a/src/android/app/src/main/res/layout/card_installable_icon.xml
+++ b/src/android/app/src/main/res/layout/card_installable_icon.xml
@@ -6,63 +6,75 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
- android:layout_marginVertical="12dp">
+ android:layout_marginVertical="12dp"
+ android:background="@android:color/transparent"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
-
-
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
-
+
-
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+
+
+
+
+
+ android:layout_marginTop="10dp"
+ android:gravity="end|center_vertical"
+ android:orientation="horizontal">
+ android:focusable="true"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
-
diff --git a/src/android/app/src/main/res/layout/dialog_lobby_browser.xml b/src/android/app/src/main/res/layout/dialog_lobby_browser.xml
index 7ecbb17340..724fe266ea 100644
--- a/src/android/app/src/main/res/layout/dialog_lobby_browser.xml
+++ b/src/android/app/src/main/res/layout/dialog_lobby_browser.xml
@@ -8,16 +8,14 @@
+ android:layout_height="wrap_content">
+ android:orientation="vertical">
+ app:iconPadding="12dp"
+ app:iconTint="?attr/colorOnPrimary"
+ android:textColor="?attr/colorOnPrimary" />
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardCornerRadius="16dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardCornerRadius="16dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardCornerRadius="16dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp">
diff --git a/src/android/app/src/main/res/layout/fragment_addons.xml b/src/android/app/src/main/res/layout/fragment_addons.xml
index b029b4209f..1a206d58a6 100644
--- a/src/android/app/src/main/res/layout/fragment_addons.xml
+++ b/src/android/app/src/main/res/layout/fragment_addons.xml
@@ -8,6 +8,7 @@
-
+ android:touchscreenBlocksFocus="false">
+ android:touchscreenBlocksFocus="false">
+ android:touchscreenBlocksFocus="false">
-
-
-
-
-
+ android:layout_height="?attr/actionBarSize"
+ android:touchscreenBlocksFocus="false"
+ app:navigationIcon="@drawable/ic_back" />
@@ -63,8 +52,12 @@
android:id="@+id/list_freedreno_presets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="6dp"
+ android:clipToPadding="false"
android:orientation="horizontal"
+ android:paddingBottom="8dp"
android:scrollbars="horizontal"
+ android:scrollbarStyle="outsideInset"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
@@ -135,22 +128,23 @@
+ android:orientation="horizontal">
+ style="?attr/materialButtonOutlinedStyle"
+ android:text="@string/freedreno_clear_all" />
@@ -161,6 +155,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
+ app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeWidth="1dp"
app:strokeColor="?attr/colorOutline">
diff --git a/src/android/app/src/main/res/layout/fragment_game_properties.xml b/src/android/app/src/main/res/layout/fragment_game_properties.xml
index 9a3437404f..d2b5fc6793 100644
--- a/src/android/app/src/main/res/layout/fragment_game_properties.xml
+++ b/src/android/app/src/main/res/layout/fragment_game_properties.xml
@@ -33,9 +33,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -44,9 +47,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_shortcut"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/src/android/app/src/main/res/layout/fragment_games.xml b/src/android/app/src/main/res/layout/fragment_games.xml
index 921625e42b..e316b3d59f 100644
--- a/src/android/app/src/main/res/layout/fragment_games.xml
+++ b/src/android/app/src/main/res/layout/fragment_games.xml
@@ -37,7 +37,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -61,7 +66,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -85,7 +95,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -117,7 +132,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
+ android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
+ app:cardBackgroundColor="@android:color/transparent"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:padding="4dp"
>
diff --git a/src/android/app/src/main/res/layout/fragment_home_settings.xml b/src/android/app/src/main/res/layout/fragment_home_settings.xml
index 5e1cf52d78..a52ae09477 100644
--- a/src/android/app/src/main/res/layout/fragment_home_settings.xml
+++ b/src/android/app/src/main/res/layout/fragment_home_settings.xml
@@ -1,38 +1,64 @@
-
+ android:background="?attr/colorSurface">
-
+ android:fitsSystemWindows="true"
+ android:touchscreenBlocksFocus="false"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
+
-
+
+
+
+
+ android:orientation="vertical"
+ android:paddingHorizontal="16dp"
+ android:paddingTop="16dp">
-
+
-
+
+
+
+
+
diff --git a/src/android/app/src/main/res/layout/fragment_installables.xml b/src/android/app/src/main/res/layout/fragment_installables.xml
index 47ef3869f2..9b728dd5c7 100644
--- a/src/android/app/src/main/res/layout/fragment_installables.xml
+++ b/src/android/app/src/main/res/layout/fragment_installables.xml
@@ -8,6 +8,7 @@
+ android:touchscreenBlocksFocus="false">
-
-
-
-
-
+ android:layout_height="?attr/actionBarSize"
+ android:touchscreenBlocksFocus="false"
+ app:navigationIcon="@drawable/ic_back" />
diff --git a/src/android/app/src/main/res/layout/item_secondary_action_button.xml b/src/android/app/src/main/res/layout/item_secondary_action_button.xml
new file mode 100644
index 0000000000..efc4530940
--- /dev/null
+++ b/src/android/app/src/main/res/layout/item_secondary_action_button.xml
@@ -0,0 +1,7 @@
+
+
diff --git a/src/android/app/src/main/res/layout/list_item_addon.xml b/src/android/app/src/main/res/layout/list_item_addon.xml
index 861d98d989..4d654581ff 100644
--- a/src/android/app/src/main/res/layout/list_item_addon.xml
+++ b/src/android/app/src/main/res/layout/list_item_addon.xml
@@ -11,8 +11,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
+ app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="12dp"
- app:cardElevation="2dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
@@ -78,8 +81,11 @@
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
+ app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
- app:cardElevation="2dp"
+ app:cardElevation="0dp"
+ app:strokeColor="?attr/colorOutline"
+ app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
@@ -100,7 +106,7 @@
android:layout_gravity="center"
android:background="@null"
android:src="@drawable/ic_delete"
- app:tint="@color/eden_border_gradient_end"
+ app:tint="?attr/colorPrimary"
android:contentDescription="@string/delete" />
diff --git a/src/android/app/src/main/res/navigation/emulation_navigation.xml b/src/android/app/src/main/res/navigation/emulation_navigation.xml
index 2adc60a47c..5e6a49501d 100644
--- a/src/android/app/src/main/res/navigation/emulation_navigation.xml
+++ b/src/android/app/src/main/res/navigation/emulation_navigation.xml
@@ -40,6 +40,10 @@
+ app:destination="@id/settingsActivity"
+ app:enterAnim="@anim/nav_default_enter_anim"
+ app:exitAnim="@anim/nav_default_exit_anim"
+ app:popEnterAnim="@anim/nav_default_pop_enter_anim"
+ app:popExitAnim="@anim/nav_default_pop_exit_anim" />
diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml
index 873438e7ae..7d04a19f36 100644
--- a/src/android/app/src/main/res/navigation/home_navigation.xml
+++ b/src/android/app/src/main/res/navigation/home_navigation.xml
@@ -101,7 +101,11 @@
+ app:destination="@id/settingsActivity"
+ app:enterAnim="@anim/nav_default_enter_anim"
+ app:exitAnim="@anim/nav_default_exit_anim"
+ app:popEnterAnim="@anim/nav_default_pop_enter_anim"
+ app:popExitAnim="@anim/nav_default_pop_exit_anim" />
@color/eden_primary
- @color/eden_glow_pink
+
+
+
+
+
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index fcaab2b320..234c831ac0 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,10 +11,11 @@
namespace AudioCore {
-AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique()} {
+AudioCore::AudioCore(Core::System& system) {
+ audio_manager.emplace();
CreateSinks();
// Must be created after the sinks
- adsp = std::make_unique(system, *output_sink);
+ adsp.emplace(system, *output_sink);
}
AudioCore ::~AudioCore() {
diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h
index e4e27fc661..ababd780b1 100644
--- a/src/audio_core/audio_core.h
+++ b/src/audio_core/audio_core.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,10 +18,7 @@ class System;
namespace AudioCore {
-class AudioManager;
-/**
- * Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
- */
+/// @brief Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
class AudioCore {
public:
explicit AudioCore(Core::System& system);
@@ -50,27 +50,22 @@ public:
*/
Sink::Sink& GetInputSink();
- /**
- * Get the ADSP.
- *
- * @return Ref to the ADSP.
- */
+ /// @brief Get the ADSP.
+ /// @return Ref to the ADSP.
ADSP::ADSP& ADSP();
private:
- /**
- * Create the sinks on startup.
- */
+ /// @brief Create the sinks on startup.
void CreateSinks();
/// Main audio manager for audio in/out
- std::unique_ptr audio_manager;
+ std::optional audio_manager;
/// Sink used for audio renderer and audio out
std::unique_ptr output_sink;
/// Sink used for audio input
std::unique_ptr input_sink;
/// The ADSP in the sysmodule
- std::unique_ptr adsp;
+ std::optional adsp;
};
} // namespace AudioCore
diff --git a/src/audio_core/audio_in_manager.cpp b/src/audio_core/audio_in_manager.cpp
index 63b064922a..6b528e9db0 100644
--- a/src/audio_core/audio_in_manager.cpp
+++ b/src/audio_core/audio_in_manager.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -41,8 +44,7 @@ void Manager::ReleaseSessionId(const size_t session_id) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
- AudioManager& manager{system.AudioCore().GetAudioManager()};
- manager.SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
+ system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
diff --git a/src/audio_core/audio_out_manager.cpp b/src/audio_core/audio_out_manager.cpp
index 316ea7c817..569df8d1e0 100644
--- a/src/audio_core/audio_out_manager.cpp
+++ b/src/audio_core/audio_out_manager.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -40,8 +43,7 @@ void Manager::ReleaseSessionId(const size_t session_id) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
- AudioManager& manager{system.AudioCore().GetAudioManager()};
- manager.SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
+ system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
diff --git a/src/common/settings.h b/src/common/settings.h
index 7c6c0d062f..ac04d26fc5 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -706,6 +706,7 @@ struct Values {
Setting pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
Setting tas_enable{linkage, false, "tas_enable", Category::Controls};
Setting tas_loop{linkage, false, "tas_loop", Category::Controls};
+ Setting tas_show_recording_dialog{linkage, true, "tas_show_recording_dialog", Category::Controls};
Setting mouse_panning{
linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9db4589ceb..6ec656cf8c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -347,7 +347,7 @@ struct System::Impl {
// Register with applet manager
// All threads are started, begin main process execution, now that we're in the clear
- applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
+ applet_manager.CreateAndInsertByFrontendAppletParameters(std::make_unique(*std::move(process)), params);
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp
index c2920f91ae..2bedce03cb 100644
--- a/src/core/hle/service/am/applet_manager.cpp
+++ b/src/core/hle/service/am/applet_manager.cpp
@@ -268,7 +268,7 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
if (Settings::values.enable_overlay && m_window_system->GetOverlayDisplayApplet() == nullptr) {
if (auto overlay_process = CreateProcess(m_system, static_cast(AppletProgramId::OverlayDisplay), 0, 0)) {
- auto overlay_applet = std::make_shared(m_system, std::move(overlay_process), false);
+ auto overlay_applet = std::make_shared(m_system, std::make_unique(*std::move(overlay_process)), false);
overlay_applet->program_id = static_cast(AppletProgramId::OverlayDisplay);
overlay_applet->applet_id = AppletId::OverlayDisplay;
overlay_applet->type = AppletType::OverlayApplet;
diff --git a/src/core/hle/service/am/process_creation.cpp b/src/core/hle/service/am/process_creation.cpp
index b5e31353a2..a20ac7de83 100644
--- a/src/core/hle/service/am/process_creation.cpp
+++ b/src/core/hle/service/am/process_creation.cpp
@@ -1,6 +1,10 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
@@ -36,31 +40,23 @@ FileSys::StorageId GetStorageIdForFrontendSlot(
}
}
-std::unique_ptr CreateProcessImpl(std::unique_ptr& out_loader,
- Loader::ResultStatus& out_load_result,
- Core::System& system, FileSys::VirtualFile file,
- u64 program_id, u64 program_index) {
+std::optional CreateProcessImpl(std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index);
-
// Ensure we have a loader which can parse the NCA.
- if (!out_loader) {
- return nullptr;
+ if (out_loader) {
+ // Try to load the process.
+ auto process = std::optional(system);
+ if (process->Initialize(*out_loader, out_load_result)) {
+ return process;
+ }
}
-
- // Try to load the process.
- auto process = std::make_unique(system);
- if (process->Initialize(*out_loader, out_load_result)) {
- return process;
- }
-
- return nullptr;
+ return std::nullopt;
}
} // Anonymous namespace
-std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
- u8 minimum_key_generation, u8 maximum_key_generation) {
+std::optional CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
// Attempt to load program NCA.
FileSys::VirtualFile nca_raw{};
@@ -70,7 +66,7 @@ std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
// Ensure we retrieved a program NCA.
if (!nca_raw) {
- return nullptr;
+ return std::nullopt;
}
// Ensure we have a suitable version.
@@ -79,9 +75,8 @@ std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
if (nca.GetStatus() == Loader::ResultStatus::Success &&
(nca.GetKeyGeneration() < minimum_key_generation ||
nca.GetKeyGeneration() > maximum_key_generation)) {
- LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
- nca.GetKeyGeneration());
- return nullptr;
+ LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id, nca.GetKeyGeneration());
+ return std::nullopt;
}
}
@@ -90,15 +85,10 @@ std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
}
-std::unique_ptr CreateApplicationProcess(std::vector& out_control,
- std::unique_ptr& out_loader,
- Loader::ResultStatus& out_load_result,
- Core::System& system, FileSys::VirtualFile file,
- u64 program_id, u64 program_index) {
- auto process =
- CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
+std::optional CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
+ auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
if (!process) {
- return nullptr;
+ return std::nullopt;
}
FileSys::NACP nacp;
@@ -118,13 +108,10 @@ std::unique_ptr CreateApplicationProcess(std::vector& out_control,
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
- launch.base_game_storage_id = GetStorageIdForFrontendSlot(
- storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
- launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
- FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
+ launch.base_game_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
+ launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
-
return process;
}
diff --git a/src/core/hle/service/am/process_creation.h b/src/core/hle/service/am/process_creation.h
index 8cfb9e0c9e..57d8b8f815 100644
--- a/src/core/hle/service/am/process_creation.h
+++ b/src/core/hle/service/am/process_creation.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -24,12 +27,7 @@ class Process;
namespace Service::AM {
-std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
- u8 minimum_key_generation, u8 maximum_key_generation);
-std::unique_ptr CreateApplicationProcess(std::vector& out_control,
- std::unique_ptr& out_loader,
- Loader::ResultStatus& out_load_result,
- Core::System& system, FileSys::VirtualFile file,
- u64 program_id, u64 program_index);
+std::optional CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
+std::optional CreateApplicationProcess(std::vector& out_control, std::unique_ptr& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index);
} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_creator.cpp b/src/core/hle/service/am/service/application_creator.cpp
index d16fd7dd84..e8e4a103c2 100644
--- a/src/core/hle/service/am/service/application_creator.cpp
+++ b/src/core/hle/service/am/service/application_creator.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -21,8 +21,7 @@ namespace Service::AM {
namespace {
-Result CreateGuestApplication(SharedPointer* out_application_accessor,
- Core::System& system, WindowSystem& window_system, u64 program_id) {
+Result CreateGuestApplication(SharedPointer* out_application_accessor, Core::System& system, WindowSystem& window_system, u64 program_id) {
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
@@ -35,11 +34,10 @@ Result CreateGuestApplication(SharedPointer* out_applicati
std::vector control;
std::unique_ptr loader;
Loader::ResultStatus result;
- auto process =
- CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
- R_UNLESS(process != nullptr, ResultUnknown);
+ auto process = CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
+ R_UNLESS(process != std::nullopt, ResultUnknown);
- const auto applet = std::make_shared(system, std::move(process), true);
+ const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), true);
applet->program_id = program_id;
applet->applet_id = AppletId::Application;
applet->type = AppletType::Application;
@@ -47,8 +45,7 @@ Result CreateGuestApplication(SharedPointer* out_applicati
window_system.TrackApplet(applet, true);
- *out_application_accessor =
- std::make_shared(system, applet, window_system);
+ *out_application_accessor = std::make_shared(system, applet, window_system);
R_SUCCEED();
}
@@ -90,12 +87,10 @@ Result IApplicationCreator::CreateSystemApplication(
std::vector control;
std::unique_ptr loader;
+ auto process = CreateProcess(system, application_id, 1, 21);
+ R_UNLESS(process != std::nullopt, ResultUnknown);
- auto process =
- CreateProcess(system, application_id, 1, 21);
- R_UNLESS(process != nullptr, ResultUnknown);
-
- const auto applet = std::make_shared(system, std::move(process), true);
+ const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), true);
applet->program_id = application_id;
applet->applet_id = AppletId::Starter;
applet->type = AppletType::LibraryApplet;
@@ -103,8 +98,7 @@ Result IApplicationCreator::CreateSystemApplication(
m_window_system.TrackApplet(applet, true);
- *out_application_accessor =
- std::make_shared(system, applet, m_window_system);
+ *out_application_accessor = std::make_shared(system, applet, m_window_system);
Core::LaunchTimestampCache::SaveLaunchTimestamp(application_id);
R_SUCCEED();
}
diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp
index e38729e70a..9f0359ed2b 100644
--- a/src/core/hle/service/am/service/library_applet_creator.cpp
+++ b/src/core/hle/service/am/service/library_applet_creator.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -121,26 +121,23 @@ std::shared_ptr CreateGuestApplet(Core::System& system,
};
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2100);
- if (!process) {
- // Couldn't initialize the guest process
- return {};
+ if (process) {
+ const auto applet = std::make_shared(system, std::make_unique(*std::move(process)), false);
+ applet->program_id = program_id;
+ applet->applet_id = applet_id;
+ applet->type = AppletType::LibraryApplet;
+ applet->library_applet_mode = mode;
+ applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
+
+ auto broker = std::make_shared(system);
+ applet->caller_applet = caller_applet;
+ applet->caller_applet_broker = broker;
+ caller_applet->child_applets.push_back(applet);
+ window_system.TrackApplet(applet, false);
+ return std::make_shared(system, broker, applet);
}
-
- const auto applet = std::make_shared(system, std::move(process), false);
- applet->program_id = program_id;
- applet->applet_id = applet_id;
- applet->type = AppletType::LibraryApplet;
- applet->library_applet_mode = mode;
- applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
-
- auto broker = std::make_shared(system);
- applet->caller_applet = caller_applet;
- applet->caller_applet_broker = broker;
- caller_applet->child_applets.push_back(applet);
-
- window_system.TrackApplet(applet, false);
-
- return std::make_shared(system, broker, applet);
+ // Couldn't initialize the guest process
+ return {};
}
std::shared_ptr CreateFrontendApplet(Core::System& system,
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 331176bf7f..7637ed5bf5 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,17 +21,14 @@ namespace Service::Audio {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique(system);
- server_manager->RegisterNamedService("audctl", std::make_shared(system));
server_manager->RegisterNamedService("audin:u", std::make_shared(system));
server_manager->RegisterNamedService("audout:u", std::make_shared(system));
- server_manager->RegisterNamedService(
- "audrec:a", std::make_shared(system));
- server_manager->RegisterNamedService("audrec:u",
- std::make_shared(system));
- server_manager->RegisterNamedService("audren:u",
- std::make_shared(system));
- server_manager->RegisterNamedService("hwopus",
- std::make_shared(system));
+ // Depends on audout:u and audin:u on ctor!
+ server_manager->RegisterNamedService("audctl", std::make_shared(system));
+ server_manager->RegisterNamedService("audrec:a", std::make_shared(system));
+ server_manager->RegisterNamedService("audrec:u", std::make_shared(system));
+ server_manager->RegisterNamedService("audren:u", std::make_shared(system));
+ server_manager->RegisterNamedService("hwopus", std::make_shared(system));
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/audio/audio_out_manager.cpp b/src/core/hle/service/audio/audio_out_manager.cpp
index 0a8e1ec256..3b2087932c 100644
--- a/src/core/hle/service/audio/audio_out_manager.cpp
+++ b/src/core/hle/service/audio/audio_out_manager.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -14,7 +14,9 @@ namespace Service::Audio {
using namespace AudioCore::AudioOut;
IAudioOutManager::IAudioOutManager(Core::System& system_)
- : ServiceFramework{system_, "audout:u"}, impl{std::make_unique(system_)} {
+ : ServiceFramework{system_, "audout:u"}
+ , impl(system_)
+{
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
diff --git a/src/core/hle/service/audio/audio_out_manager.h b/src/core/hle/service/audio/audio_out_manager.h
index 791274d5e9..ec974aaba4 100644
--- a/src/core/hle/service/audio/audio_out_manager.h
+++ b/src/core/hle/service/audio/audio_out_manager.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -43,7 +43,7 @@ private:
AudioCore::AudioOut::AudioOutParameter parameter,
InCopyHandle process_handle, ClientAppletResourceUserId aruid);
- std::unique_ptr impl;
+ std::optional impl;
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
index 6a1345c074..972e930a89 100644
--- a/src/core/hle/service/audio/audio_renderer_manager.cpp
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,7 +18,9 @@ namespace Service::Audio {
using namespace AudioCore::Renderer;
IAudioRendererManager::IAudioRendererManager(Core::System& system_)
- : ServiceFramework{system_, "audren:u"}, impl{std::make_unique(system_)} {
+ : ServiceFramework{system_, "audren:u"}
+ , impl(system_)
+{
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
diff --git a/src/core/hle/service/audio/audio_renderer_manager.h b/src/core/hle/service/audio/audio_renderer_manager.h
index 69eee664c3..fdce8b6ffa 100644
--- a/src/core/hle/service/audio/audio_renderer_manager.h
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,7 +33,7 @@ private:
Result GetAudioDeviceServiceWithRevisionInfo(Out> out_audio_device,
u32 revision, ClientAppletResourceUserId aruid);
- std::unique_ptr impl;
+ std::optional impl;
u32 num_audio_devices{0};
};
diff --git a/src/core/hle/service/os/process.cpp b/src/core/hle/service/os/process.cpp
index 0dbadc315e..2d5d7def64 100644
--- a/src/core/hle/service/os/process.cpp
+++ b/src/core/hle/service/os/process.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,14 +13,6 @@
namespace Service {
-Process::Process(Core::System& system)
- : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
- m_process_started() {}
-
-Process::~Process() {
- this->Finalize();
-}
-
bool Process::Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result) {
// First, ensure we are not holding another process.
this->Finalize();
diff --git a/src/core/hle/service/os/process.h b/src/core/hle/service/os/process.h
index 9109b7d0a5..ca10945f84 100644
--- a/src/core/hle/service/os/process.h
+++ b/src/core/hle/service/os/process.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -22,8 +25,8 @@ namespace Service {
class Process {
public:
- explicit Process(Core::System& system);
- ~Process();
+ inline explicit Process(Core::System& system) noexcept : m_system(system) {}
+ inline ~Process() { this->Finalize(); }
bool Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result);
void Finalize();
@@ -50,8 +53,8 @@ public:
private:
Core::System& m_system;
Kernel::KProcess* m_process{};
- s32 m_main_thread_priority{};
u64 m_main_thread_stack_size{};
+ s32 m_main_thread_priority{};
bool m_process_started{};
};
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 7cdb3acadd..7bb632cedc 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -126,16 +126,14 @@ public:
current_query = nullptr;
amend_value = 0;
accumulation_value = 0;
- queries_prefix_scan_pass = std::make_unique(
- device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
+ queries_prefix_scan_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = 8,
- .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
- VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+ .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@@ -592,8 +590,7 @@ private:
VideoCommon::HostQueryBase* current_query;
bool has_started{};
std::mutex flush_guard;
-
- std::unique_ptr queries_prefix_scan_pass;
+ std::optional queries_prefix_scan_pass;
};
// Transform feedback queries
@@ -1176,35 +1173,21 @@ private:
} // namespace
struct QueryCacheRuntimeImpl {
- QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_,
- Tegra::MaxwellDeviceMemoryManager& device_memory_,
- Vulkan::BufferCache& buffer_cache_, const Device& device_,
- const MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
- StagingBufferPool& staging_pool_,
- ComputePassDescriptorQueue& compute_pass_descriptor_queue,
- DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
- : rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_},
- device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
- staging_pool{staging_pool_}, guest_streamer(0, runtime),
- sample_streamer(static_cast(QueryType::ZPassPixelCount64), runtime, rasterizer,
- texture_cache_, device, scheduler, memory_allocator,
- compute_pass_descriptor_queue, descriptor_pool),
- tfb_streamer(static_cast(QueryType::StreamingByteCount), runtime, device,
- scheduler, memory_allocator, staging_pool),
- primitives_succeeded_streamer(
- static_cast(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer,
- device_memory_),
- primitives_needed_minus_succeeded_streamer(
- static_cast(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u),
- hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
+ QueryCacheRuntimeImpl(QueryCacheRuntime& runtime, VideoCore::RasterizerInterface* rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_)
+ : rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_}
+ , device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}
+ , staging_pool{staging_pool_}, guest_streamer(0, runtime)
+ , sample_streamer(size_t(QueryType::ZPassPixelCount64), runtime, rasterizer, texture_cache_, device, scheduler, memory_allocator, compute_pass_descriptor_queue, descriptor_pool)
+ , tfb_streamer(size_t(QueryType::StreamingByteCount), runtime, device, scheduler, memory_allocator, staging_pool)
+ , primitives_succeeded_streamer(size_t(QueryType::StreamingPrimitivesSucceeded), runtime, tfb_streamer, device_memory_)
+ , primitives_needed_minus_succeeded_streamer(size_t(QueryType::StreamingPrimitivesNeededMinusSucceeded), runtime, 0u)
+ , hcr_setup{}, hcr_is_set{}, is_hcr_running{}, maxwell3d{} {
hcr_setup.sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
hcr_setup.pNext = nullptr;
hcr_setup.flags = 0;
- conditional_resolve_pass = std::make_unique(
- device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
-
+ conditional_resolve_pass.emplace(device, scheduler, descriptor_pool, compute_pass_descriptor_queue);
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -1241,7 +1224,7 @@ struct QueryCacheRuntimeImpl {
std::vector> copies_setup;
// Host conditional rendering data
- std::unique_ptr conditional_resolve_pass;
+ std::optional conditional_resolve_pass;
vk::Buffer hcr_resolve_buffer;
VkConditionalRenderingBeginInfoEXT hcr_setup;
VkBuffer hcr_buffer;
@@ -1253,13 +1236,7 @@ struct QueryCacheRuntimeImpl {
Maxwell3D* maxwell3d;
};
-QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer,
- Tegra::MaxwellDeviceMemoryManager& device_memory_,
- Vulkan::BufferCache& buffer_cache_, const Device& device_,
- const MemoryAllocator& memory_allocator_,
- Scheduler& scheduler_, StagingBufferPool& staging_pool_,
- ComputePassDescriptorQueue& compute_pass_descriptor_queue,
- DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
+QueryCacheRuntime::QueryCacheRuntime(VideoCore::RasterizerInterface* rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory_, Vulkan::BufferCache& buffer_cache_, const Device& device_, const MemoryAllocator& memory_allocator_, Scheduler& scheduler_, StagingBufferPool& staging_pool_, ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool, TextureCache& texture_cache_) {
impl = std::make_unique(
*this, rasterizer, device_memory_, buffer_cache_, device_, memory_allocator_, scheduler_,
staging_pool_, compute_pass_descriptor_queue, descriptor_pool, texture_cache_);
@@ -1484,13 +1461,11 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
impl->scheduler.RequestOutsideRenderPassOperationContext();
if (is_prebarrier) {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
- cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
});
} else {
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
- cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
});
}
}
@@ -1583,8 +1558,7 @@ void QueryCacheRuntime::SyncValues(std::span values, VkBuffer ba
}
impl->scheduler.RequestOutsideRenderPassOperationContext();
- impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to),
- vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
+ impl->scheduler.Record([src_buffer, dst_buffers = std::move(impl->buffers_to_upload_to), vk_copies = std::move(impl->copies_setup)](vk::CommandBuffer cmdbuf) {
size_t size = dst_buffers.size();
for (size_t i = 0; i < size; i++) {
cmdbuf.CopyBuffer(src_buffer, dst_buffers[i].first, vk_copies[i]);
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 82fce298da..1497108b16 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -1,10 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include
-
+#include
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
@@ -12,20 +15,15 @@ namespace Vulkan {
class Device;
class Scheduler;
-struct DescriptorUpdateEntry {
- struct Empty {};
-
+union DescriptorUpdateEntry {
DescriptorUpdateEntry() = default;
DescriptorUpdateEntry(VkDescriptorImageInfo image_) : image{image_} {}
DescriptorUpdateEntry(VkDescriptorBufferInfo buffer_) : buffer{buffer_} {}
DescriptorUpdateEntry(VkBufferView texel_buffer_) : texel_buffer{texel_buffer_} {}
-
- union {
- Empty empty{};
- VkDescriptorImageInfo image;
- VkDescriptorBufferInfo buffer;
- VkBufferView texel_buffer;
- };
+ std::monostate empty{};
+ VkDescriptorImageInfo image;
+ VkDescriptorBufferInfo buffer;
+ VkBufferView texel_buffer;
};
class UpdateDescriptorQueue final {
diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp
index 8bdb987426..75d5a5eeaf 100644
--- a/src/yuzu/configuration/configure_tas.cpp
+++ b/src/yuzu/configuration/configure_tas.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -35,6 +35,7 @@ void ConfigureTasDialog::LoadConfiguration() {
ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue());
ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue());
ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue());
+ ui->tas_show_recording_dialog->setChecked(Settings::values.tas_show_recording_dialog.GetValue());
}
void ConfigureTasDialog::ApplyConfiguration() {
@@ -42,6 +43,7 @@ void ConfigureTasDialog::ApplyConfiguration() {
Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked());
Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked());
Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked());
+ Settings::values.tas_show_recording_dialog.SetValue(ui->tas_show_recording_dialog->isChecked());
}
void ConfigureTasDialog::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui
index da8f2a86c5..5b4bba53b6 100644
--- a/src/yuzu/configuration/configure_tas.ui
+++ b/src/yuzu/configuration/configure_tas.ui
@@ -78,6 +78,13 @@
+ -
+
+
+ Show recording dialog
+
+
+
diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp
index e02e02b413..688078385a 100644
--- a/src/yuzu/main_window.cpp
+++ b/src/yuzu/main_window.cpp
@@ -3665,13 +3665,17 @@ void MainWindow::OnTasRecord() {
const bool is_recording = input_subsystem->GetTas()->Record();
if (!is_recording) {
- is_tas_recording_dialog_active = true;
+ if (Settings::values.tas_show_recording_dialog.GetValue()) {
+ is_tas_recording_dialog_active = true;
- bool answer = question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ bool answer = question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
- input_subsystem->GetTas()->SaveRecording(answer);
- is_tas_recording_dialog_active = false;
+ input_subsystem->GetTas()->SaveRecording(answer);
+ is_tas_recording_dialog_active = false;
+ } else {
+ input_subsystem->GetTas()->SaveRecording(true);
+ }
}
OnTasStateChanged();
}