This PR adresses the following issue : `ProcessLoader.ActiveApplication` could return invalid results when `_latestPid` pointed to a process that no longer existed in the kernel's process table. The original exception path was commented out and bypassed (by sh0inx?) with `GetValueOrDefault` to prevent UI lockups, but this only resolved the symptoms without fixing the root cause.
This was due to sevral factors :
- `_latestPid` was never reset or validated against the actual process state
- ProcessLoader maintained its own `_processesByPid` dictionary separate from the kernel's `KernelContext.Processes`
- No cleanups happened when processes exited or were terminated
- ProcessLoader state could drift out of sync with the kernel process table
**Solution/Fixes**
- Validate` _latestPid` against the kernel process table before returning `ActiveApplication`
- Check process state (Exited/Exiting) and automatically clear stale references
- Add thread-safe cleanup methods (`ClearProcess`, `ClearAllProcesses`)
- Integrate `ClearAllProcesses` into Switch.Dispose for proper shutdown cleanup
- Add warning logs when stale PID is detected and cleared for debugging
**Code Changes**:
- `ProcessLoader.cs`: Add `_pidLock`, update `ActiveApplication` with validation, add cleanup methods
- `Switch.cs`: Call `Processes.ClearAllProcesses()` in Dispose()
Some games/applications may crash with a specific error:
00:00:00.690 |E| Application : Unhandled exception caught: System.Collections.Generic.KeyNotFoundException: The given key '0' was not present in the dictionary.
(or a different key)
However, this message is misleading and not indicative of the actual error (it masks it).
As an example, the error above was seen when attempting to load a mod onto Yo-kai Watch 1 (base game + update worked). However, after patching the ProcessResult, the resulting error was more revealing:
00:00:00.716 |E| Application : Unhandled exception caught: LibHac.Common.HorizonResultException: ResultFsInvalidCharacter (2002-6004): Error creating LocalFileSystem. at LibHac.FsSystem.LocalFileSystem..ctor(String rootPath)
(and so forth)
The actual error was due to an incorrect folder name in the Mods folder.
This introduces the somewhat completed version of the Player Select
Applet, allowing users to select either a user or a guest from the UI.
Note: Selecting the guest more then once currently does not work.
closes https://github.com/Ryubing/Ryujinx/issues/532
- misc: chore: optimize UserSelectorDialog closed handler
- misc: chore: Rename UserSelectorDialog to ProfileSelectorDialog
Co-authored-by: GreemDev <greemdev@ryujinx.app>
- Avalonia to 12.1.2
- Svg.Controls.Avalonia to 12.0.0.17
- Microsoft.IdentityModel.JsonWebTokens to 8.22.0
- Microsoft.NET.Test.Sdk to 18.10.0
- Ryujinx.Graphics.Vulkan.MoltenVK to 1.4.3-ryujinx.1
- System.IO.Hashing to 10.0.12
- Attempted fixing the strength: so far it hasn't been successful.
- Rumble should skip vibrations if they're not in-line with poll-rate: would like to come back to this. Queuing just does exactly what the hid buffer does, but our timer (poll rate) is not in sync with the rate the controller is reading at, which causes excess drops.
- Refactored the class so that implementing support for HD rumble for other controllers (DS5, Steam Controller) is much easier in the future.
Adds support for IAccountServiceForApplication command 52, TrySelectUserWithoutInteraction, introduced in Firmware 19.0.0.
Command 51 (TrySelectUserWithoutInteractionDeprecated) and command 52 use the existing ApplicationServiceServer.TrySelectUserWithoutInteraction implementation.
This prevents newer titles from failing when requesting automatic user selection through the new command.
Tomb Raider: Definitive Edition is now fully playable.
Fix EmbeddedResources.GetAllAvailableResources to respect the specified resource path when enumerating embedded resources.
Previously, resources were filtered only by file extension. Adding locale-named JSON files under anywhere else caused them to be included when querying Assets/Locales, resulting in duplicate entries in the language menu.
Multiple executables may report the same Build ID, causing ToDictionary to throw an ArgumentException while creating the executable lookup.
Build the lookup incrementally and keep the first code address when duplicate Build IDs are encountered. Log a warning if a duplicate Build ID is associated with a different code address.
In KAddressArbiter, threads were originally inserted into the wait queue according to their DynamicPriority.
When multiple threads had the same DynamicPriority, the original implementation could not guarantee their existing order. Threads with the same dynamic priority are now inserted in FIFO order, preventing unstable wake-up ordering from blocking the guest synchronization flow.
Initial PR was made by Avan for Ryubing.
This allows for Trails in the Sky 1st Chapter (and by extension Trails through Daybreak, Trails through Daybreak II, Trails Beyond the Horizon, and the future Trails in the Sky 2nd Chapter – tested via demo – to be fully playable.
Initial PR caused issues on macOS devices, specifically crashing in certain games (such as Mario Kart 8 Deluxe and the aforementioned Trails games). It was reverted on the original Ryubing project (at the time of writing this description) for causing small rendering issues on The Legend of Zelda: Breath of the Wild.
The rendering issues do not appear on macOS.
This commit improves the original PR by eliminating said macOS crash.
Trails in the Sky 1st writes its exposure/brightness value through an R32G32Float 1x1 texture and later reads the raw bits back through an R32Uint 2x1 texture mapped to the same guest memory. The two texture formats/dimensions are fully incompatible as texture views, so they end
up as separate host textures, and nothing kept their contents coherent - the reader saw stale zeroed data, making the exposure calculation (and the rendered image) too dark. (This is the initial fix for the game)
TextureGroup already had a raw-copy dependency mechanism intended to
handle this class of alias (TextureDependency, TextureGroupHandle
raw-copy plumbing), gated by CanCreateRawCopyDependency's strict same-guest-memory checks. This commit fixes three bugs that kept that mechanism from working correctly (and thus crashing Trails and other games, such as Mario Kart 8 Deluxe):
(1) TextureGroup.InitializeOverlaps() and TextureGroup.RegisterIncompatibleOverlap() only forwarded overlaps to CreateCopyDependency() when compatibility was LayoutIncompatible or better, silently excluding the fully Incompatible case the raw-copy path exists for. Widened both guards to let Incompatible overlaps through so CanCreateRawCopyDependency actually gets a chance to run.
(2) Once Incompatible overlaps were allowed through, CreateCopyDependency(TextureGroup, ...) could still fall back to a regular, non-raw textureCopy for such pairs, since ViewLayoutCompatible/CopySizeMatches only check byte size and were never meant to reason about fully incompatible pairs (e.g. a depth format aliasing a color format with the same byte size). On Vulkan running through MoltenVK on macOS, that non-raw copy path requires a pixel-format-reinterpreting texture view, and MoltenVK/Metal refuses to create any view onto a depth-format texture ("not castable"), aborting emulation. textureCopy is now forced false for Incompatible pairs, leaving raw copy (which already excludes depth/stencil formats) as the only route for that severity level.
(3) TextureGroupHandle.Inherit() copied a handle's pending DeferredCopy to the new handle when a view was recreated, but did not copy DeferredCopyRaw alongside it. A handle that inherited a pending raw copy would then execute it through the regular (non-raw) CopyTo path once acknowledged, reinterpreting the source bytes with the wrong row layout and corrupting the image - visible as vertical flickering stripes whenever a view happened to be recreated with a raw copy still pending. DeferredCopyRaw is now carried over together with DeferredCopy.
(As mentioned earlier, vertical stripes aren't present on macOS, so (3) doesn't negatively have an effect on macOS in any way).
- Moves emulation past the initial frame by providing the necessary inputs the game expects. Apparently games like to spin until they get what they want.
Co-authored-by: Mythrax <mythrax@mythrax-rs.org>
This PR threads process/program identity into PTC disk cache initialization so cache ownership is selected from the launched process rather than global/shared application state.
Previously, the PTC initialization path only propagated loose title/version information into the CPU layer. That was mostly fine for a single launched application, but will introduce many problems once multiple programs can be launched during the same session, given later processes could inherit cache identity from the first loaded application.
To address this issue, this PR introduces a `PtcCacheInfo` payload and applies it through the process context, CPU context, translator, and PTC initialization paths. Cache ownership is now resolved once the kernel process PID is known and includes:
- PID
- Program ID / Title ID
- Application ID
- Program index
- Display version
- Process kind
- Cache selector
`PtcCacheInfo` now owns its default title/application/version values, and `Ptc` uses that cache info directly instead of mirroring title/version fields internally.
The persistent cache key itself does remains title/version/selector based rather than PID based, so caches remain reusable across launches while still being selected from the correct process context. PID is only used for diagnostics and ownership tracing in logs.
Additional PTC logging has also been added to report cache ownership and selected paths during PTC initialization, Profiling info load/save and translation cache load/save
Both the PTC and profiler internal versions were bumped (a bunch of times lol).
It has been confirmed that Divinity: Original Sin 2 may describe the same or overlapping guest GPU memory using BCn-compressed textures with different logical dimensions, such as 104×104 and 102×102.
BCn formats store texture data in blocks, with each BC block covering 4×4 texels. After rounding the dimensions up to complete blocks, both 104×104 and 102×102 textures require a 26×26 grid of BC blocks. As a result, they have the same block footprint at the base mip level. Ryujinx originally determined size compatibility in TextureCompatibility.ViewSizeMatches() primarily from this block footprint, which could cause these textures to be classified as Full view-compatible and allowed to share the same Vulkan VkImage directly.
However, because the two textures have different logical dimensions, their mip chains are also different. For example, at mip level 3, a 104×104 texture is reduced to 13×13, while a 102×102 texture is reduced to 12×12. If a 104×104 child texture view shares the backing image of a 102×102 parent texture, a subsequent full mip upload may attempt to write 13×13 compressed data into a Vulkan image subresource whose actual dimensions are only 12×12.
This produces a compressed buffer-to-image copy that does not match the geometry of the backing image. After the invalid command is submitted to the GPU, the Vulkan driver may asynchronously report VK_ERROR_DEVICE_LOST during command buffer submission, waiting, or presentation. In Ryujinx, this eventually appears as: VulkanException: Unexpected API error "ErrorDeviceLost".
The fix adds a logical-dimension check to TextureCompatibility.ViewSizeMatches(). If either the parent or child uses a compressed texture format, and the actual width or height of the corresponding parent mip does not match the logical width or height of the child, the relationship is no longer classified as Full view-compatible. Instead, it is downgraded to CopyOnly.
CopyOnly indicates that the two textures may still describe the same or overlapping guest memory and that their contents must remain synchronized, but they cannot directly share a single fixed-size Vulkan image. Ryujinx instead allows each texture to retain a host texture matching its own logical dimensions and synchronizes their contents through the existing copy-dependency mechanism.
As a result, the 13×13 mip of the 104×104 texture is uploaded to an actual 13×13 destination mip, while the 12×12 mip of the 102×102 texture is uploaded to an actual 12×12 destination mip.
The Enhanced and Classic versions of FFT are different program indices within the same application. When the Classic version is launched, the game uses ExecuteProgram to stop the current program, trigger DisposeGpu, create a new renderer and OpenGL context, and then launch the requested program.
Previously, when AppHost executed DisposeGpu, it attempted to bind the old OpenGL context and then called Device.DisposeGpu to destroy GPU resources. During the program relaunch flow, however, the old RendererHost may already have been removed from the visual tree, causing its native window to become detached.
If the old OpenGL context can no longer be bound, a ContextException is thrown, preventing the subsequent AppExit and program relaunch flow from continuing.
The updated implementation handles this case by detecting a ContextException while binding the OpenGL context when ShouldRestart is true. It then skips the destruction of GPU resources that depend on the old OpenGL context, allowing the old context to be released together with the old window. The AppExit and program relaunch flow can then continue without being interrupted.
Some fragment passes used by FFT do not have any color or depth/stencil attachments. Instead, the fragment shader writes the results directly to storage images (on OpenGL: through imageStore).
### Vulkan
When SetImage is called and FramebufferParams has no attachments, its virtual size must be updated using the width, height, and layer count of the fragment storage image. Otherwise, the attachmentless framebuffer may retain an incorrect 1x1 extent, causing backgrounds, logos, UI elements, and other rendered content to be missing.
If the first draw occurs before the storage-image descriptor is rebound, SetImage cannot yet provide the correct storage-image dimensions. Therefore, when RecreateGraphicsPipelineIfNeeded finds that FramebufferParams has no attachments and still uses the default 1x1 extent, it initializes the framebuffer dimensions from the active viewport. Otherwise, the first Vulkan draw may be restricted to a 1x1 area and render incorrectly.
The storage-image extent is therefore used as the authoritative size for FramebufferParams, while the active viewport is used as a fallback when the storage-image extent is not yet available before the first draw.
### OpenGL
A storage image is not a framebuffer attachment, so OpenGL cannot derive the framebuffer width and height from it. When the framebuffer has no attachments but a viewport with valid dimensions has already been defined, Pipeline.PreDraw must set the default framebuffer width and height from the active viewport.
Without non-zero default width and height values, the attachmentless framebuffer remains incomplete. Drawing with that framebuffer results in InvalidFramebufferOperation, so rasterization and fragment shader execution do not occur even when the storage images are bound correctly.
- The Vulkan backend now reports the driver name and version using VK_KHR_driver_properties when available, with fallbacks for raw Vulkan driverVersion parsing. Intel Windows drivers also get the full package-style version from the driver UUID when exposed by the driver.
OpenGL now carries its existing OpenGL version string through HardwareInfo.GpuDriverVersion.
Fix an "Invalid texture format 0x25A5A (sRGB: True)" error that occurs when running OCTOPATH TRAVELER 0.
The game may leave texture descriptor heap entries filled with 0x5A. Interpreting such uninitialized entries as valid texture descriptors produces an invalid format and causes texture creation to proceed with garbage descriptor data.
Validate the texture address before decoding the descriptor. Descriptors with a zero or unmapped address are marked as invalid and skipped. The invalid state is cleared when the corresponding texture pool entry is modified, allowing the descriptor to be evaluated again.
Incorrect rendering was observed during loading transitions in Trails in the Sky 1st Chapter. Testing showed that routing the first render target's RT0 BlendEnable transition from disabled to enabled through the normal register write path prevented the issue.
Further investigation found that the normal register write was restoring Shadow RAM behavior that was missing from UpdateBlendEnable.
UpdateBlendEnable uses a fast bulk update path instead of issuing a normal register write for each render target. As a result, it bypasses the Shadow RAM handling provided by DeviceStateWithShadow.WriteWithRedundancyCheck.
A normal register write updates both State and ShadowState in MethodTrack and MethodTrackWithFilter modes. In MethodReplay mode, it ignores the incoming value and restores the value previously stored in ShadowState to State.
UpdateBlendEnable must reproduce the same behavior while retaining its bulk comparison and copy path. In track modes, copy the incoming enable values to shadowState. In replay mode, copy shadowState to the incoming enable span, then let the existing comparison and copy logic update state and mark BlendState dirty when necessary.
The original implementation incorrectly used state for both track and replay handling. This prevented Shadow RAM from correctly recording or replaying BlendEnable values, which could cause rendering state synchronization errors.
Correct the bulk update path to use ShadowState for tracking and replay. This preserves the optimized bulk operation while addressing the underlying issue without requiring an RT0-specific compatibility workaround.
Trails in the Sky 1st uses texture descriptors with different formats and dimensions that map to the same region of guest GPU memory. For example, the game interprets the same underlying data as both an R32Uint 2x1 texture and an R32G32Float 1x1 texture. Both textures have an 8-byte logical payload, but their texel formats and dimensions are different.
Ryubing cannot represent these two descriptors as normally compatible texture views, so it creates separate host texture objects for them. Since these host textures represent the same guest memory, a modification made to one of them should become visible to the other before the other texture is read. However, the existing synchronization mechanism does not fully handle this situation.
The game uses this pattern for its exposure or brightness history. A compute shader first writes the updated exposure data to the R32G32Float 1x1 host texture. A later operation then reads the raw bits of the same data through the R32Uint 2x1 host texture. The original Ryubing implementation did not synchronize the contents of these two separate host textures. As a result, the reading texture received stale zero values, which caused the shader to calculate an incorrectly low exposure value and made the rendered image appear too dark.
TextureGroup already has a guest-memory synchronization mechanism for incompatible overlaps. When _flushIncompatibleOverlaps is enabled, the most recent texture contents are written back to guest memory, after which the other texture reloads the data. However, this mechanism was primarily enabled through IsFormatHostIncompatible, which checks whether an individual texture format can be correctly supported by the host GPU.
In this case, both R32Uint and R32G32Float are individually supported by the host GPU. Therefore, IsFormatHostIncompatible does not enable this synchronization path. The issue is not that either format is unsupported. The issue is that two individually supported aliases, represented by separate host textures, do not maintain coherent contents.
In theory, the latest contents could be flushed to guest memory immediately after every GPU write to a host texture, allowing other textures that map to the same guest memory to reload the updated data. However, doing so could frequently trigger expensive operations such as GPU waits, data readbacks, guest texture layout conversions, and memory-tracking updates. This would be particularly costly for textures that are updated every frame or during every compute dispatch.
For this reason, the fix does not require an immediate flush after every write. Instead, it extends Ryubing's existing TextureDependency and TextureGroupHandle mechanisms. When two fully incompatible textures map to exactly the same guest memory and satisfy a strict set of raw-copy requirements, the program creates a raw-copy dependency between them.
When the source texture is modified, the target texture is only marked as requiring a raw copy. The latest logical raw bytes are copied from the source only when the target texture is actually about to be used. This keeps the contents of the separate host texture aliases coherent while avoiding unnecessary round trips through guest memory.
- Downloads updated gamecontrollerdb.txt file on launch, only updates when a new file is available. This keeps the database updated between SDL releases.
This reverts the mono jit PR.
It had several issues that I haven't had time to fix yet.
Expect mono jit v2 in the future with said fixes.
JitCache alignment fixes are still included/fixed.
Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
This PR contains the following updates:
| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [Ryujinx.Graphics.Vulkan.MoltenVK](https://github.com/Kenji-NX/MoltenVK) | `1.4.2-ryujinx.4` → `1.4.2-ryujinx.5` |  |  |
---
### Release Notes
<details>
<summary>Kenji-NX/MoltenVK (Ryujinx.Graphics.Vulkan.MoltenVK)</summary>
### [`v1.4.2-ryujinx.5`](https://github.com/Kenji-NX/MoltenVK/releases/tag/v1.4.2-ryujinx.5)
##### Fork changes
- CI changes
- Build with macOS 26
- Remove `all` build
- Add iOS Private API build
##### Upstream changes ([Changelog](https://github.com/KhronosGroup/MoltenVK/compare/29a0606...4b715bd))
- Fix incorrect placement heap check in MVKImagePlane::getMTLTexture()
- Fix AMD subgroup size to 32 for correct Metal simdgroup operations
- Fix SPIRV-Cross: symlink instead of submodule
- Fix regressions and crashes on Mac 1 (NVIDIA/Intel) GPUs
- Work around combined sampler arg buffers on NVIDIA Mac1
- `nativeTextureSwizzle = false` for NVIDIA Mac1
- Restore shader-side image view swizzle fallback.
- Avoid input attachment argument buffers on NVIDIA Mac1
- Disable discard store checks on NVIDIA Mac1
- Disable image descriptor argument buffers for shader swizzle
- Advertise native texture swizzle only on supported GPU families
- Simplify NVIDIA workaround checks
- Disable discarded-fragment store checks on Mac1 GPUs
- Avoid fragile Mac1 argument-buffer descriptor cases
- Do not rely on extension enable for vkGetPhysicalDeviceToolPropertiesEXT proc addr
- Emulate reversed-depth viewports on affected AMD Mac GPUs
- Refine legacy AMD Mac2 workaround handling
- Scope discarded-fragment store checks to Apple GPUs
- Disable non-working quad control flow
- Disable 64-bit float control properties
</details>
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDkuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI0OS41IiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->
Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/17
- fix alignment issue with jitcache that could cause a crash.
- Reimplement sparse-jit to only use 1 layer.
- the old 2 layer approach basically only ever used 1 path due to the bottom-layer size, so doing a double look-up seemed wasteful.
- changed memory block allocation stategy to allocate based on requested code range instead of the possible address-space.
Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
- jit caches are no longer static.
- JitUnwindWindows now supports multiple jit caches.
- Jit caches should no longer cause crashes due to entry offset collisions.
- cpu tests now run concurrently.
Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
The `OpenTK.Windowing.GraphicsLibraryFramework` package is included in the Ryujinx csproj, but is never used in the project.
Checking the source code, all source files included in the package are part of the `OpenTK.Windowing.GraphicsLibraryFramework` namespace, which is never included in the Ryujinx source code. Rider also confirms that it's an unused reference.
The library includes the entirety of libglfw into the program, it clears about a half a megabyte. Not much, but it's free.
- downgrade unicorn to last working version
- update to new cp reg struct system
- remove nonexistent register (used to silently continue)
- fix partial unmap tests
- InitializeSignalHandler() was moved out of the translator (almost 2.5 years ago), but the test code was never updated to manually call the function as it was changed to do in the real cpu context, so the tests just started failing.
- by manually initializing the handler we no longer cause tests to fail.
Ayyyy, welcome to the **macOS: Fix Hypervisor BadArgument Launch Crash PR!**
We are so so back my friends.
This PR fixes the macOS Hypervisor `BadArgument` launch crash, while also sneaking in some improvements to help _potentially_ mitigate those lovely 0 FPS deadlock on macOS in certain games with Vulkan + Hypervisor enabled (there will be a separate PR in the future to address this).
The PR is slightly different in terms of the PR messages that I write, but I hope that it'll provide the necessary context to those unaware of the reasoning/causes of the issue.
Also, this is a bit of a read, so grab some snacks, pour a drink, get comfortable, and enjoy some…
### STORY TIME!!!
_Before we proceed forward, we must properly understand what Hypervisor is._
_Hypervisor refers to using Apple's built-in virtualization technology, the Hypervisor Framework, to accelerate CPU emulation._
_There are two main ways to do this:_
_1. **Interpreter** – executes instructions one by one (very slow)._
_2. **JIT (Just-In-Time)** recompilation – translates Switch CPU instructions into native code (much faster)._
_On Apple Silicon Macs (M1, M2, M3, etc.), the guest CPU and host CPU are both ARM64-based. As the Nintendo Switch itself is ARM64, The Hypervisor Framework can allow Ryujinx to execute large amounts of guest code more directly, reducing emulation overhead. The architectural similarity makes hardware-assisted execution practical. On Intel Macs, there isn't the same direct ARM-to-ARM advantage, so the benefits are much more limited or unavailable._
_When Hypervisor mode is available and working correctly, it can provide higher frames, reduced CPU bottlenecks, faster shader compilation in certain instances, smoother gameplay, and lower CPU usage._
_The improvement depends heavily on the game. CPU-heavy titles tend to benefit the most._
_There are downsides though. Sometimes, certain games may have compatibilities issues, certain feature may not work exactly the same, bugs in the actual Hypervisor implementation can cause crashes or issues, and performance gain vary significantly on a game-to-game basis._
_In terms of a simple analogy:_
_**Without Hypervisor:** Ryujinx acts like a translator who rewrites every sentence before speaking it._
_**With Hypervisor:** Ryujinx can let the Mac's CPU understand and execute much more of the Switch's code directly, so less translation work is needed._
_Anyway, now that we have the background, onto the story!_
Once upon a time, around ~December 2025 / January 2026, users — and yes, even devs (though let’s be honest, macOS devs are basically cryptids at this point)
_(Authors note: Cryptids - animals or other beings whose present existence is disputed or unsubstantiated by science)_
Started noticing inconsistent behaviour with the macOS Hypervisor. In other words, Hypervisor began showing inconsistent launch behaviour for users who've upgraded to the then current macOS versions (15.7.3 / 26.2). This behaviour continued as macOS got updated, and is still present on the latest version (Tahoe 26.5.1).
Initially, Hypervisor was mostly crashing with an `Unexpected result "Denied"`. The likely cause is two fold:
1. macOS security permissions changed during that update.
2. Hypervisor framework got updated, but nothing what communicated to the devs.
(It is likely to be the former, not the later. This is the main theory, at least.)
However, this crash later evolved into (because of course it did) into `Unexpected result "BadArgument"`.
We'll come back to this in a bit.
For users who wished to run games with Hypervisor enabled, they had a simple solution - build Ryujinx locally. Yes, this is an effective solution in its own right, as that does bypass certain macOS signing and certain .app bundle-related constraints, as well as certain security permissions.
However, this doesn't explain why:
* Official server builds were the only builds that were affected
* Users on _older macOS_ (below 15.7.3 / 26.2) could run games with Hypervisor enabled as if nothing had ever gone wrong in their lives.
* Users on _newer macOS_ versions _could still run certain older_ Ryujinx builds as intended — specifically, the last or close-to-last version they had lying around in their Downloads folder.
* Users on macOS above 15.7.3 / 26.2 could still run games with Hypervisor enabled, on builds downloaded from the server, for whatever reason.
So now we’re here:
* Same macOS versions → Different outcomes
* Different Ryujinx builds → Different behavior
* `Denied` → Evolved into `BadArgument`
* No consistent reproduction steps
And so, after attempting to fix this for quite some time, I've determined it to be unfixable. Ryujinx should drop macOS support because development has been held back far too long, and there is nothing we can possibly do. Every possible solution was tested and the results were null.
So, it is with great sadness that, here and now, I proclaim that Ryujinx will terminate further macOS support.
Bye-bye, Ryujinx on macOS! You had a great run, and you'll always be remembered. Thank you for bringing so much great memories to us, macOS users!
...
...
...
...
...
HAHA - NOT SO FAST!
(_Please tell me I got you there_)
Not all hope is lost - there is light at the end of the tunnel!
**The key insight is this:** `BadArgument` is not just “`Denied` but newer and worse”. It’s something else entirely.
* `Denied` → macOS refuses the request at the security boundary. Nothing even starts.
* `BadArgument` → macOS accepts the request, but the data being passed is now invalid under newer constraints.
So instead of:
_“You shall not pass.”_
We now have:
_“You may pass… but what is THAT?”_
And this brings us to this PR!
### The PR
Users on macOS were experiencing two major issues when Hypervisor was enabled:
**1. Hard Crash – "Unexpected result `BadArgument`"**
The most frequent stack trace pointed to:
```
System.Exception: Unexpected result "BadArgument".
at Ryujinx.Cpu.AppleHv.HvResultExtensions.ThrowOnError(...)
at Ryujinx.Cpu.AppleHv.HvExecutionContextVcpu.GetX(Int32 index)
at Ryujinx.HLE.HOS.Kernel.Threading.KThread.GetCurrentContext()
at Ryujinx.HLE.HOS.Kernel.Threading.KThread.GetThreadContext3(...)
```
This crash occurred very early during game initialization, most often inside supervisor calls such as `GetThreadContext3`.
**2. Intermittent Permanent 0 FPS Freezes with Vulkan (unrelated to `BadArgument`, but somewhat addressed in this PR)**
The game would run normally for a while, then drop to 0 FPS permanently. Disabling Hypervisor eliminated the freezes but performance was at times inconsistent.
### The Explanation
`HvResult.BadArgument` is returned by Apple's Hypervisor framework (`hv_vcpu_get_reg`, `hv_vcpu_get_sys_reg`, `hv_vcpu_get_simd_fp_reg`, etc.) when it determines that the requested operation cannot be performed in the current vCPU state.
**Common reasons why this happens:**
* Timing races - the guest tries to read registers before the vCPU has fully synchronized its internal state after context switches, exceptions, or vCPU pool reuse.
* Stricter validation in newer macOS versions.
* vCPU state inconsistencies during early boot or heavy syscall activity.
Because the original implementation called `.ThrowOnError()` unconditionally on every Hypervisor call, even a single transient `BadArgument` would immediately terminate execution. This was the direct cause of the crash.
The 0 FPS issue was a separate but related symptom: when Hypervisor is enabled, the guest CPU runs significantly faster than MoltenVK's presentation queue expects, leading to command buffer starvation and queue deadlock.
### The Changes
* **Implemented: Complete Shadow Register Cache (`HvExecutionContextVcpu.cs`)**
* Added full in-memory shadow copies of every relevant register:
* General-purpose registers: `private readonly ulong[] _x = new ulong[32]`;
* Vector/SIMD registers: private readonly `V128[] _v = new V128[32]`;
* System/special registers: `_pc`, `_elrEl1`, `_esrEl1`, `_tpidrEl0`, `_tpidrroEl0`, `_fpcr`, `_fpsr`, and `_pstateRaw` (stored as `ulong` internally to avoid type conversion issues).
* **Reasoning:** Returning zero or garbage values on failure could corrupt game state. When the Hypervisor returns `BadArgument`, we now have a safe, previously-valid value to return instead of crashing. A shadow cache gives us that last known good value. The cache is updated on every successful read, so correctness is preserved in normal operation. This is the central fix for the `BadArgument` crash.
* **Defensive BadArgument Handling on Every Register Access Path**
* Updated every read operation (`GetX`, `GetV`, `Pstate`, cached getters, etc.) to explicitly check the return value, with the same pattern applied across all accessors.
* **Reasoning:** This directly eliminates the crash while preserving the original error-throwing behavior for genuine failures. Returning cached data is far safer than injecting zero or garbage values that could corrupt guest state:
```
HvResult res = HvApi.hv_vcpu_get_...(..., out value);
if (res == HvResult.BadArgument)
{
_fallbackCount++;
LogHvWarning("..."); // rate-limited
return cachedValue; // safe fallback
}
res.ThrowOnError(); // only throw on real errors
return cachedValue = value; // success path + cache update
```
* **AggressiveMode Global Option** (NOT IMPLEMENTED IN THIS PR, BUT A FUTURE PR WILL ADD THIS FULLY)
* Added:
`public static bool AggressiveMode { get; set; } = false;`
* When true/enabled, all warning logs in LogHvWarning() are suppressed.
* **Reasoning:** Diagnostic logging has overhead. In the future, users will be able to disable/enable this when required. This will also be useful for any dev working on macOS Hypevisor (aka - me).
* **Hot-Path Optimizations**
* Changed index checks from `if (index < 0 || index > 30)` to `if ((uint)index > 30)` in `GetX`, `SetX`, `GetV`, and `SetV`.
* Separated cache initialization into a dedicated `InitializeCacheDefaults()` method called by constructor and `Reset()`.
* **Reasoning:** `GetX` is called millions of times per second. Reducing branches improves CPU branch prediction and overall throughput. The clean initialization pattern ensures reliable behavior when vCPUs are reused from the pool.
* **Improved Logging, Diagnostics & Monitoring**
* Rate-limited warnings with a cooldown timer (`WarningCooldownTicks = 1_000_000_000 ≈ 1 second`).
* Clear, descriptive messages (e.g. "PAC failure on SP_EL0", "PAC failure on X15").
* Added `public long GetFallbackCount()` for runtime monitoring.
* **Reasoning:** We need visibility into fallback frequency during development and testing, but we must not spam the log for end users during normal gameplay.
_Quick side note:_
_The logging mentions "PAC failure" rather than HV `BadArgument`, and this is a shorthand I've added right now for myself.
Technically, we are catching HvResult.BadArgument. It's called "PAC failure" in logs because PAC is a frequent trigger, especially with games like TOTK that use heavy mods (AKA TOTK Optimiser)._
_Right now, I'm calling it a PAC failure, but will later rename to `BadArgument` as I progress further on a certain issue that's been sitting in our GitHub for some time._
_Back to the main stuff:_
* **GPU Synchronization & _Potential_ 0 FPS Mitigation (`HvExecutionContext.cs`) (PR FOLLOW UP IN THE FUTURE)**
* Added adaptive `TryGpuSync()` called periodically in the main `Execute()` loop (every 10–12 execution steps).
* Added strategic `Thread.Yield()` after `SvcAarch64` handling and in sync points.
* Tuned counters based on real gameplay testing (% 10 for light sync, % 6 for stronger sync).
* **Reasoning:** Hypervisor accelerates the guest CPU significantly. Without periodic yielding/flushing, MoltenVK's presentation queue can starve, causing permanent 0 FPS. The adaptive approach gives aims to fix this by performing a "resync". This has been tested and is showing positive progress, but, as mentioned earlier, will continue in a future PR.
These are all of the changes in this PR.
It's been quite a ride getting Hypervisor back up and running, but I loved every second of it.
If there is anything that is unclear in this PR, please let me know and I'll provide more details and update the description above.
Here is a small FAQ section to answer some more questions. These answers come from my own personal testing and behaviour that I observed.
### FAQ
**Q:** Why can some users play games with Hypervisor enabled and others can't on newer macOS versions?
**A:** This needs a bit of clarification.
You _can_ still run games with Hypervisor enabled on latest macOS - just not all games. Games such as Pokémon Legends: Z-A, The Legend of Zelda: Tears of the Kingdom, The Legend of Zelda: Breath of the Wild, can all _run_ and will _boot_ with Hypervisor enabled.
However, some other games, like Beyblade X Xone, Beyblade X Evobattle, Tales of Xillia Remastered, Tales of Berserk Remastered, etc, will _crash_ on boot with `BadArgument` error.
So it's not that Hypervisor works for one user and doesn't work for the other.
_It's that the game doesn't cause Hypervisor to crash._
Games differ in how aggressively they read registers early in boot and how much they rely on modded/JIT code. Games with heavy early supervisor calls and/or mods that manipulate pointers/PAC (pointer authentication errors) are far more likely to hit BadArgument.
(PAC is the reason why TOTK crashes with UltraCam when Hypervisor is disabled on macOS)
Lightweight or less modded titles often avoid the problematic code paths.
––––––
**Q:** How stable is this fix?
**A:** Updating macOS versions (Tahoe -> Tahoe) didn't break this implementation. Current data and testing all provide positive results (i.e. - no crash, hooray!)
––––––
**Q:** What about the `Denied` error?
**A:** This has more so to do with macOS permissions. Currently, Ryujinx is not being shipped in a DMG (which, by Apple conventions, is a more proper way of handling macOS app installations outside of the App Store). There is a theory that packaging Ryujinx into a DMG file will alleviate any permission issues that we currently have, and may help fix this type of error, so this PR may not even be needed (but we'll have to see how it goes).
That said, this error has not appeared in any of the more recent crash logs that I've analysed or acquired myself (from testing), leading to a possible hypothesis that the permission issues have been resolved, but the Hypervisor implementation broke on server builds due to an update to the framework. This is, however, unlikely, because, again, only builds after a particular version (i.e. - the last working version on a users system) broke.
However, DMG packaging is still on a table and something that we want to implement as soon as possible.
––––––
**Q:** So why do local builds run then?
**A:** A lot of different factors - build environment, folder location, lack of permissions associated with running .exe files, different ways of handling pure .exe files and .app bundles, notarisation, and more. There was no "scientific testing" done on each of the factors and seeing which one affects what exactly. Pushing this PR and implementing the DMG will tell.
This PR addresses [Ryubing/Issues#345](https://github.com/Ryubing/Issues/issues/345) by fixing the Windows console hide/show path so it only acts on Ryujinx’s own console window instead of whatever window happens to be focused during startup. Previously, when Show Console was disabled, the helper could race with focus changes and end up affecting another app or shell window while leaving the console visible; this change removes that foreground-window dependency and keeps the startup behavior scoped to the Ryujinx console.
Fixes a black screen on Metal versions older than 3.1 by disabling `VK_EXT_extended_dynamic_state` (and `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`). Fix imported from sunshineinabox's unpublished extended dynamic states branch.
Co-authored-by: sunshineinabox <aqemail@gmail.com>
fixes cursor being at 0 position even when text is present, especially annoying for handheld devices with kde virtual keyboard, which is pretty bad, with no way to move the cursor or delete text backward
This PR fixes two bugs introduced in #80 :
- Exiting fullscreen could exit the Ryujinx window (https://github.com/Ryubing/Issues/issues/415)
- Toggling fullscreen on would move the window to the primary monitor
And two other bugs related to input view :
- Exiting fullscreen when window was previously in a non maximized state now conserves the window coordinates and size properly (https://github.com/Ryubing/Issues/issues/425)
- Opening the ryujinx app no makes the app grow slightly larger vertically on each launch (+31px on my 1080p monitor) (https://github.com/Ryubing/Issues/issues/425)
This PR is the first in a batch of structural changes to Ryujinx.
**Changes**
- Added `ProcessIdentity` and `ProcessKind` to describe loaded programs by:
- PID, program ID, application ID, program index, display version, process kind
- Stored identity metadata on `ProcessResult`.
- Added PID-based process lookup helpers to `ProcessLoader`.
- Updated HLE services to resolve application metadata through the caller PID instead of `Processes.ActiveApplication`.
- Added PTC/JIT disk cache initialization logging with PID, title ID, display version, selector, and enabled state.
- Added `ClientProcessId` property to ServiceCtx (/src/Ryujinx.HLE/HOS/ServiceCtx.cs) that uses the handle descriptor PId when available, falling back to `Process.Pid`.
- Updated 15 HLE service files to use `context.ClientProcessId` instead of `context.Process.Pid` for client process access, ensuring services correctly identify the calling process even when invoked via IPC with handle descriptors.
These changes make service metadata resolution more explicit and prepare the emulator for other structural changes later on.
Welcome to [Renovate](https://github.com/renovatebot/renovate)! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.
🚦 To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.
📚 See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading.
🔡 Do you want to change how Renovate upgrades your dependencies? Add your custom config to `.forgejo/renovate.json` in this branch. Renovate will update the Pull Request description the next time it runs.
---
### Detected Package Files
* `Directory.Packages.props` (nuget)
* `global.json` (nuget)
* `src/ARMeilleure/ARMeilleure.csproj` (nuget)
* `src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj` (nuget)
* `src/Ryujinx.Common/Ryujinx.Common.csproj` (nuget)
* `src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj` (nuget)
* `src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj` (nuget)
* `src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj` (nuget)
* `src/Ryujinx.HLE/Ryujinx.HLE.csproj` (nuget)
* `src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj` (nuget)
* `src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj` (nuget)
* `src/Ryujinx.Horizon/Ryujinx.Horizon.csproj` (nuget)
* `src/Ryujinx.Input/Ryujinx.Input.csproj` (nuget)
* `src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj` (nuget)
* `src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj` (nuget)
* `src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj` (nuget)
* `src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj` (nuget)
* `src/Ryujinx.Tests/Ryujinx.Tests.csproj` (nuget)
* `src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj` (nuget)
* `src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj` (nuget)
* `src/Ryujinx/Ryujinx.csproj` (nuget)
### Configuration Summary
Based on the default config's presets, Renovate will:
- Start dependency updates only once this onboarding PR is merged
- Enable Renovate Dependency Dashboard creation.
- Use semantic commit type `fix` for dependencies and `chore` for all others if semantic commits are in use.
- Ignore `node_modules`, `bower_components`, `vendor` and various test/tests (except for nuget) directories.
- Group known monorepo packages together.
- Use curated list of recommended non-monorepo package groupings.
- Show only the Age and Confidence Merge Confidence badges for pull requests.
- Apply crowd-sourced package replacement rules.
- Apply crowd-sourced workarounds for known problems with packages.
- Ensure that every dependency pinned by digest and sourced from Forgejo contains a link to the commit-to-commit diff
- Ensure that every dependency pinned by digest and sourced from GitHub.com and Github enterprise contains a link to the commit-to-commit diff
- Enable Renovate configuration migration PRs when needed.
- Require Dependency Dashboard approval for `major` updates.
---
### What to Expect
With your current configuration, Renovate will create 9 Pull Requests:
<details>
<summary>Update avalonia monorepo to 11.3.16</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/avalonia-monorepo`
- Merge into: `master`
- Upgrade [Avalonia](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
- Upgrade [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
- Upgrade [Avalonia.Diagnostics](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
- Upgrade [Avalonia.Markup.Xaml.Loader](https://github.com/AvaloniaUI/Avalonia) to `11.3.16`
</details>
<details>
<summary>Update dependency Microsoft.NET.Test.Sdk to 18.5.1</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/vstest-monorepo`
- Merge into: `master`
- Upgrade [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) to `18.5.1`
</details>
<details>
<summary>Update dependency Microsoft.IdentityModel.JsonWebTokens to 8.18.0</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/dotnet-azure-ad-identitymodel-extensions-monorepo`
- Merge into: `master`
- Upgrade [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) to `8.18.0`
</details>
<details>
<summary>Update dependency NUnit to 4.6.1</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/nunit-4.x`
- Merge into: `master`
- Upgrade [NUnit](https://github.com/nunit/nunit) to `4.6.1`
</details>
<details>
<summary>Update dotnet monorepo</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/dotnet-monorepo`
- Merge into: `master`
- Upgrade [Microsoft.CodeAnalysis.Analyzers](https://github.com/dotnet/roslyn) to `3.11.0`
- Upgrade [Microsoft.CodeAnalysis.CSharp](https://github.com/dotnet/roslyn) to `4.14.0`
- Upgrade [System.IO.Hashing](https://github.com/dotnet/dotnet) to `10.0.8`
- Upgrade [dotnet-sdk](https://github.com/dotnet/sdk) to `10.0.300`
</details>
<details>
<summary>Update avalonia monorepo to v12</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/major-avalonia-monorepo`
- Merge into: `master`
- Upgrade [Avalonia](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`
- Upgrade [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`
- Upgrade [Avalonia.Markup.Xaml.Loader](https://github.com/AvaloniaUI/Avalonia) to `12.0.3`
</details>
<details>
<summary>Update dependency Avalonia.Controls.DataGrid to v12</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/avalonia.controls.datagrid-12.x`
- Merge into: `master`
- Upgrade [Avalonia.Controls.DataGrid](https://github.com/AvaloniaUI/Avalonia.Controls.DataGrid) to `12.0.0`
</details>
<details>
<summary>Update dotnet monorepo to v5</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/major-dotnet-monorepo`
- Merge into: `master`
- Upgrade [Microsoft.CodeAnalysis.Analyzers](https://github.com/dotnet/roslyn) to `5.3.0`
- Upgrade [Microsoft.CodeAnalysis.CSharp](https://github.com/dotnet/roslyn) to `5.3.0`
</details>
<details>
<summary>Update Svg.Controls to v12</summary>
- Schedule: ["at any time"]
- Branch name: `renovate/major-svg.controls`
- Merge into: `master`
- Upgrade [Svg.Controls.Avalonia](https://github.com/wieslawsoltes/Svg.Skia) to `12.0.0.9`
- Upgrade [Svg.Controls.Skia.Avalonia](https://github.com/wieslawsoltes/Svg.Skia) to `12.0.0.9`
</details>
🚸 PR creation will be limited to maximum 2 per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for `prHourlyLimit`](https://docs.renovatebot.com/configuration-options/#prhourlylimit) for details.
---
❓ Got questions? Check out Renovate's [Docs](https://docs.renovatebot.com/), particularly the Getting Started section.
If you need any further assistance then you can also [request help here](https://github.com/renovatebot/renovate/discussions).
---
This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-config-hash:b90d3633c498120cf097b76d90e40f530a1210d84c00ad2dc3491f01a81cbdd8-->
Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
Reviewed-on: https://git.ryujinx.app/projects/Kenji-NX/pulls/1
Fixes a bug introduced in e88fd327. The problematic commit did its work directly on the updater's own arrays, calling Auto.Get() on each entry as it went, and nulling entries out along the way. The problem is that Get() can call back into Commit (via ClearMirrors -> Rebind), and when it did, that reentrant Commit would read from the same arrays the outer call was still in the middle of processing, hit one of the entries the outer had already nulled, and throw an NullReferenceException. The fix is to have Commit start by copying everything it needs into local variables and resetting _count to zero, so a reentrant call sees a clean updater and operates on its own data. The outer call then writes its snapshot back into the native arrays just before recording the Vulkan bind.
Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
Co-authored-by: Max <randomgirlisweird@gmail.com>
Co-authored-by: Babib3l <gab.chevanne@gmail.com>
This PR fixes several validation errors caused by invalid Vulkan usage. These validation errors often end up invoking Undefined Behavior on the driver side, which can lead to artifacts or crashes which are driver specific and otherwise incredibly hard to track. I don't think it should have any impact on performance, but it would be good to test it with as many games as possible (maybe a bug in a game was fixed?).
Each commit fixes an error. I added to each a description with the validation error that was fixed and a small explanation on what was causing it and how I fixed it.
Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
The previous fix for Tomodachi Life (#91) included the extension to all shaders, independently on if it was needed or not. This PR fixes that by lazily adding the extension only when it is actually needed.
This change should not be noticed by anyone, but it avoids having to modify shaders that do not perform any type of dynamic indexing, which apparently is something some modders care about.
Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
This PR marks ALL texture indexes as nonuniform to fix an issue with the paths in Tomodachi Life: Living the Dream on AMD cards. It should have a negligible impact on performance (and it should not have an impact at all on NVIDIA cards!)
It's caused by what is called 'implicit non-uniform sampler array indexing'. The idea is basically that some GPUs optimize texture lookups from indexed texture arrays, by assuming that you are never going to index different textures within a single workgroup. What this causes is that visual glitch where a subgroup is tasked with rendering a block of the screen, and in the boundaries some cores are indexing the wrong texture.
Co-authored-by: AsperTheDog <guillerman0000@gmail.com>
This PR addresses [this issue](https://github.com/Ryubing/Issues/issues/231) and implements HD Rumble for compatible Nin devices.
## New Features
- Add the option for Gamepads to implement HD Rumble
- Add the HD rumble capability to SDL3Gamepad and SDL3JoyCon when they meet certain requirements
## Description
~~Fixes a fatal CLR crash when `caps` screenshot saving receives an input buffer larger than `0x384000`.~~
~~Resolves a crash in Tomodachi Life: Living the Dream where saving the pictures to the system's album crashes with 0x80131506.~~
Follow up to #18. This PR adjusts the validation and copy behavior to better match real hardware, and adds logging to make invalid screenshot buffer cases easier to diagnose.
Real hardware accepts screenshot buffers with a size greater than or equal to `0x384000`, but only `0x384000` bytes are needed for the 1280x720 RGBA image.
This changes screenshot saving to:
- reject buffers smaller than `0x384000`
- accept buffers equal to or larger than `0x384000`
- copy only the first `0x384000` bytes into the 1280x720 bitmap
## Testing
Tested with a real Switch NRO using `capssuSaveScreenShotEx0`, `capssuSaveScreenShotEx1`, and `capssuSaveScreenShotEx2`.
Observed hardware behavior:
```text
0x384000 => OK
0x384000 - 1 => NullInputBuffer
0x384000 + 1 => OK
0x3C0000 => OK // Tomo life picture size
```
Co-authored-by: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com>
This PR aims to Fix the Windows fullscreen gap when toggling from maximized state by using canonical Win32 fullscreen approach. When entering fullscreen, the window style is saved and replaced with WS_POPUP | WS_VISIBLE to remove all window chrome (title bar, borders), then SetWindowPos sizes the window to cover the full screen with SWP_FRAMECHANGED to force Win32 to recalculate the frame. On exit, the original window style is restored. This eliminates the few-pixel gap at the top that occurred because Avalonia's WindowState = FullScreen transition from a maximized state retained the title bar non-client area, leaving visible space at the top of the screen (Fullscreen resolution would be 1920 x 1072p on a 1080p monitor, it now correctly renders at 1920 x 1080p)
- Fixes `StoreData` layout/update handling so `UpdateLatest` returns the stored Mii data correctly.
- Implements `IDatabaseService.Append` (https://switchbrew.org/wiki/Shared_Database_services#IDatabaseService)
Also adds regression tests for `UpdateLatest` and `Append`.
(Might) fix Mario Kart 8 Deluxe crashing on first boot due to failed Mii verification check (due to custom Mii from emulator), and potentially Tomodachi Life: Living the Dream for the "Import Mii from system" option.
Co-authored-by: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com>
When connecting multiple controllers of the same model, the first device's name ends with (0), the second with (1), the third with (1), the fourth with (1), and so on. To ensure these names are truly unique, GetUniqueGamepadName is now called recursively.
@MaxLastBreath found that The Legend of Zelda: Tears of the Kingdom experiences inconsistent crashing with a limited JIT cache size. Increasing the cache size seems to help with this, and increasing it shouldn't degrade performance for other titles.
@LotP plans to look this over later, but for now, this should suffice as a fix for affected users.
Fixed LoadGuestApplication hanging when cancelled.
Since startup procedure has technically changed, we should consider testing this with a variety of game formats to ensure regressions do not occur.
- Avalonia to 11.3.14
- FluentAvalonia to 2.5.1
- Gommon to 2.8.1.2
- Microsoft.NET.Test.Sdk to 1.8.5.0
- SDL3-CS to 2026.426.0
- System.IO.Hashing to 10.0.7
no way this was working before, and if it did, just pure luck, unsafe blind copy of bytes as is and zero checks.
i only tested tomodachi, but should fix all games that were crashing on saving screenshots
the crash was happening because the screenshot buffer was bigger than the bitmap buffer, so marshall.copy() was raising an unhandhled expection crashing the emu.
on top of this, because the data was just copied as is, the result image was garbled.
- Fix: Crash when connecting a JoyCon
- Fix: Make controller GUIDs match old SDL2 GUIDs
- Fix: Detect face button layout for gamepads
Co-authored-by: Maki <77-maki@users.noreply.git.ryujinx.app>
- Services now use their actual names when creating processes instead of the generic "Service".
- Services now use their names encapsulated in curly brackets for threads, e.g. {HID}, instead of the default "HLE.OsThread", making it easier to see what is actually happening behind the scenes. Client threads should use <> and host threads should use {}.
- Fixed a bug where initiating services would create extra unneeded servers.
This is part 1 of a series of service and Horizon changes i'm working on. More will follow at a later date.
* Svg.Controls.Avalonia group to 11.3.9.5
* DynamicData to 9.4.31
* Humanizer to 3.0.10
* NUnit to 4.5.1
* NUnit3TestAdapter to 6.2.0
* Ryujinx.LibHac to 0.21.0-alpha.133
* System.IO.Hashing to 10.0.5
If an npad device was checking for if the device was at rest, we called `GetSixAxisSensorLifo()` -- if the npad was of type `None`, it triggered the `NotImplementedException` in that method because `None` doesn't have a gyroscope, and therefore no data attached to it.
Implement nn::ssl::sf::ISslServiceForSystem -> CreateContextForSystem (100)
Ryujinx implements both ISslService and ISslServiceForSystem in one class so we can just return new ISslContext.
Also fixed the incorrect parameter reading order. (CreateContextForSystem basically has same params as CreateContext)
- Add RestartEmulation() method to MainWindowViewModel
- Add 'Restart Emulation' menu item with Ctrl+R keybinding
- Add locale translations for all supported languages
- No confirmation dialog (faster restart experience)
Fix crash caused by reading incorrect size of Splitter data.
In most games the crash doesnt happen if you have nn::audio::AudioRendererParameter VoiceCount aligned to 2, as that causes splitter data to be aligned by 0x10, but otherwise, the alignment by 0x10 done in SplitterContext->Update may exceed SplitterSize (which was previously labeled as Unknown24), causing a crash.
(Crash can be replicated by doing AudioRendererParameter.voiceCount++; in any SDK 20.X game that works, which doesn't cause crash on actual hardware)
(This patch is from a friend who makes mods.)
Adds Ryujinx.Audio.Backends.Apple, which is a AudioToolbox based audio backend for macOS (and by extension iOS). Also added in MeloNX.
* Expose AudioToolkit in UI
Co-authored-by: GreemDev <greemdev@ryujinx.app>
In some games using newer SDK (e.g. Splatoon 3 11.0.0), when `nn::prepo::PlayReport::SetOptInCheckEnabled` is set to False, `nn::prepo::PlayReport::Save` will call `IPrepoService:10106` (SaveReport) and `IPrepoService:10107` (SaveReportWithUser) instead of 10104 (SaveReportOld) and 10105 (SaveReportWithUserOld).
A new param (optInCheckEnabled) is added in 10106/10107 compare to 10104/10105.
This should fix missing service error for Splatoon 3 11.0.0 and other games using newer SDK and has set `nn::prepo::PlayReport::SetOptInCheckEnabled` to False.
Fixes the actually insane amount of log spam in games that check for this, such as Luigi's Mansion 3.
Values in HidDevices.NpadDevices.isAtRest may need to be tuned to a better range for resting detection. I originally set them to 0, and my controller rests at definitely NOT 0.
Will need to be revisited when implementing functionality for the global SixAxisActive bool, IHidServer.StartSixAxisTracking, and IHidServer.StopSixAxisTracking.
* Avalonia to 11.3.11, Svg.Controls.Avalonia group to 11.3.9.2
* Gommon to 2.8.0.4
* NUnit3TestAdapter to 6.1.0
* Ryujinx.LibHac to 0.21.0-alpha.128
* System group to 10.0.2
Core dumps are disabled by default on Linux, but this prevents access to the file picker due to security hardening. To work around this, core dumps are selectively enabled and disabled around the file picker tasks.
Use [ObservableProperty] attribute, which greatly reduces or eliminates boilerplate code needed to generate observable properties
Co-authored-by: GreemDev <greemdev@ryujinx.app>
This add the following commands to Gdb Stub:
monitor get mappings
monitor get mappings <address>
monitor get mapping <address>
This is the first time arguments are used in Rcmd, so FindRcmdDelegate is changed to CallRcmdDelegate, to allow it to handle arguments cleanly.
The reply format mimics the same command on Atmosphere.
The forced pagination of monitor get mappings in Atmosphere is not added, as I think it's not needed here.
if a buffer is inherited, ignore it and remove it from the list.
fixes a crash when a buffer is inherited during a sync and the containing ranges have been modified to not fit in the old buffer.
Fixes a few crashes:
- fixes a crash related to waking threads (priorities were wrong).
- fixes a crash from reusing the SetRenderTargets texture array (left-over data causing issues).
- fixes a mistake and an oversight in the buffer system.
- buffers were getting updated wrong causing bad data to be stored or some times cut.
- modified ranges would extend past their old buffers, crashing on syncs. Old buffers are now skipped as the new buffers already sync instead.
Introduces pooling in a few more places to increase memory efficiency.
simplified RangeList item logic.
- removed RangeItem by making all the range objects use the I(NonOverlapping)Range interface.
- BufferCache class no longer locks its RangeList, as the list is only ever accessed synchronously.
Small change to how keyboard snapshots are stored.
Increase ThreadedRenderer SpanPool size to fit slightly more data (4MB -> 8MB).
Fix games that uses ContextRegistrar (e.g. After the socket blocking issue is fixed, Splatoon 3 and other ModuleSystem games will call this when booting, to create a context for the error, after a connection attempt to the server failed.)
Previously, sockets were only ever closed when the game specifically requested it.
Thanks @comex on GitHub for the patch submitted via the [Ryubing] issues page.
Co-Authored-By: comex <47517+comex@users.noreply.github.com>
* Gommon to 2.8.0.1
* Microsoft.NET.Test.Sdk to 18.0.0
* Newtonsoft.Json to 13.0.4 (reduces trim warnings by 56)
* Ryujinx.LibHac to 0.21.0-alpha.126
* System group to 9.0.10
* UnicornEngine.Unicorn to 2.1.4-a40db6c
General memory improvements to decrease GC pressure and frequency.
Pool big arrays and objects that are created and deleted often.
Skip data copies when they aren't needed.
Inline flag checks to skip unneeded allocations.
From my testing the performance is about the same, but the GC frequency is much lower and collection is faster causing less and smaller spikes.
This lets games such as The Legend of Zelda: Tears of the Kingdom (v1.4.2) and other SDK 20+ games successfully circumvent a crash when calling an applet.
Example: No controller connected on boot -> calls Controller Applet -> no stub = crash.
ObjectPool now uses ConcurrentBag instead if ConcurrentStack, as it has a smaller memory footprint.
Fix compiler warnings related to Audio Command Pools.
Switch gpu command initialization to use pointers, that way skipping the allocation of the command which is unnecessary.
Skip byte array allocation in Ioctl2/3 if it isn't needed (if the source data is all continuous we don't need to copy it to make it continuous).
Revert and reimplement Float BiquadFilterEffect support, fixes infinite load issues in a few games like Splatoon 3.
Fix incorrect string check with the new thread naming system.
Implement object pooling for all Audio Commands and a few other audio related objects and use a growing error list for updating wave buffers instead of always allocating space for 8 errors.
Currently, application list will not show until ApplicationLibrary_LdnGameDataReceived calls ViewModel.RefreshView();, forcing a refresh. This makes application list load slowly when RyuLDN is enabled.
Newer applications have a folder for ounce in the Control nca. This fixes Ryujinx trying to open a folder as a file, causing another exception, when trying to find the icon fallback.
When users enable GDB stub, we assume they intend to use it (it slows down the game a lot). If the server cannot start, we abort to save users' time troubleshooting why their GDB client can not connect.
- Move the message handler into its debugger class part,
- Move all message types into one file and collapse 3 of the ones with no data into a generic, stateless message with a single property being its type,
- Add an Fpscr helper property on IExecutionContext along with a comment about what Fpscr is (similar to the other registers in there)
- Moved the Rcmd helpers (such as GetRegisters, GetMinidump, etc) into a dedicated Debugger class part,
- Fixed the double-collection (ToArray being called twice) in GetThreadUids & GetThread in KProcess
- convert GdbRegisters utilities into extensions on IExecutionContext
- add a Write/Read Register helper on Debugger that handles 32/64 bit instead of doing that for every usage of register reading/writing
Using resolution mods, heaps past 8 GiB work in some games (like LoZ: TotK) and not in others (like SMP Jamboree). Setting the heap to a hard limit of 8 GiB on the 10 & 12 GiB DRAM options seems to be the safe bet right now until a better solution is found.
When GDB stub is enabled, CheckSynchronization is called too frequently because it skips _nativeContext.SetCounter(MinCountForCheck) (called in CheckInterrupt()), causing CheckSynchronization to be constantly called in JIT. This could cause performance issue.
It also skips the call to the KProcess.InterruptHandler, which causes some games to deadlock when GDB stub is enabled.
I'm not sure if this change will cause any side effects, but it seems GDB stub is still working correctly after this change.
This change will not affect regular users.
The heap was limited to 6 GiB no matter the memory setting, causing memory configurations above 8 GiB to not actually affect the heap size.
Now when the memory config is set to [10 or] 12 GiB the heap also allocates 12 GiB.
The SetHeapSize SysCall will now allow heap sizes up to 12 GiB (technically slightly less).
Co-authored-by: KeatonTheBot <keaton@ryujinx.app>
Currently, some logs can be missing when a fatal error occurs (especially GuestBrokeExecutionException).
This MR attempts to flush logs to console and file before process exit.
After commit 51ca73cb, using a non-blocking socket (e.g. poll(..., timeout=0)) will still result in a blocking socket.
It appears the above commit inverted the behavior.
This merge request fixes the blocking flag: blocking will be set to false when the flag is 0x800.
* Fixed an issue where games would boot loop because of an incorrect HID state.
* Turns out the SamplingNumber of the atomic input storage doesn't match the SamplingNumber of the input state held by the atomic storage, instead it is exactly double the value in the input state.
* Added new Condition struct to the HID Shared memory and populate it with dummy data to fix the no-controller crash (already merged).
* The audio renderer has been mostly updated to rev15, allowing rev15 games to launch.
* Biquad filters now use floats.
* Several structures have been renamed to match the SDK names, making it easier to compare functionality. A few names are still missing and will be changed at a later date.
* The new commands from rev15 have been added to the CommandType enum, but they are still missing from the code itself.
* Due to changes in the SDK layout, the time estimation functions are either missing or very well hidden (or Ghidra search functionality is useless). We can't fully implement the new commands until the timing data has been located.
* A few minor tweaks to the code have been made to more accurately match the SDK.
Adds an additional application list sorting method for the TitleID. A
bit of a niche choice for sorting but I think the TID is a relevant
enough piece of metadata that it should be there. (And I personally
would be using it)
- Using existing TitleId constant in ApplicationSort, implying this was
meant to be in the sorting options at some point?
- Reuses the "DlcManagerTableHeadingTitleIdLabel" locale for fulfilling
the need already, might be better to make a unique one for this in the
long run but this codebase is new to me so I wanted to make the changes
as unobtrusive as possible
- Using app.Id for the comparer seems to work fine, not sure if using
something else like IdString would be better?
Single L/R Joycons default to unbound for the SL/SR inputs - so by default you can't progress past 'press L + R to continue' type screens.
But
* ConfigGamepadInputId.SingleLeftTrigger0(L)
* ConfigGamepadInputId.SingleRightTrigger0(L)
* ConfigGamepadInputId.SingleLeftTrigger1(R)
* ConfigGamepadInputId.SingleRightTrigger1(R)
already exist (and I verified these are the inputs triggered by the SL/SR buttons), so my change would default to these instead.
A few more internal changes to the RangeList systems.
* No longer using a QuickAccess dictionary.
* The performance of the dictionary wasn't much faster than just doing binary searches.
* Using just binary searches allows us to take advantage of span and array returns as they're are faster than linked lists when iterating or copying the overlaps.
Small code optimizations.
Fixes a few leftover crashes.
* Slightly refactors RangeLists from the last Memory Changes MR, which fixes issue 61.
* Convert as many const size array iterators to span iterators as possible. When iterating over a const size array, every iteration created a Span, now only the first iteration does in most places.
* Now using object pooling for a few object types that were rapidly deleted and recreated.
* Converted a few flag checks to binary operations to save memory allocations.
* Refactors the RangeList and derivative classes used for handling lists of regions
* The Binary searches are now more performant, relying on edge searches instead of just returning the first matching hit and manually iterating until the edge is found
* Most look-ups now return a RangeItem, which acts as a linked list node now, instead where possible, moving away from Array copies. This should help with some specific lag spikes.
* Made IntrusiveRedBlackTreeNodes act like linked list nodes too to improve the lookup time of minimums, maximums and successors.
* Changed a few cases of HasFlag() into binary operations to save on memory allocations.
In general, [these changes] should increase frame time stability and lag spikes, but at the cost of some overhead to memory look-ups, the result being a very slightly better average fps from my testing (~1-2%).
* Rename timer interval constant
* Also cut the delay after which scrolling is considered ended in half
Co-authored-by: GreemDev <greemdev@ryujinx.app>
* PPTC version bump
* Also reset call depth when not using the unmanaged dispatch loop
* Increment call depth on function start rather than before call
* FluentAvalonia: Disabled NavigationView selection indicator animations due to bugged implementation in 2.1.0+, restoring previous behavior
* Avalonia: Fixed text on certain buttons being larger than normal
* Avalonia: Fixed ComboBox code inserting extra space to the left of selected items
This fixes https://github.com/Ryubing/Issues/issues/30
* Switch to "Release" build config (PerformanceCheck(); will only be called in Release build config)
* Enable "Trace Logs" in Ryujinx settings
* Double-click a game to launch
* Ryujinx will attempt to open a confirmation dialog box that never opens, causing UI deadlock
* _lastFileOffset now correctly stores the offset for the last file in the chain
* Fixes an issue where a RomFS mod with both overridden and new files in the same folder would load incorrectly
* Renamed a variable with the wrong name
* Now behaves correctly when the same file is added twice in a row compared to V1 MR
* GetSerialNumber in ISystemSettingsServer
* Bionic qualifiers
* Revert application pool size to 3285 MB for 4 GB DRAM
* Fix PPTC recompilation if mod or patch is applied
Launch the Ryujinx.exe, first argument --no-gui or nogui, and the rest of the arguments should be your normal headless script. You can include the new option --use-main-config which will provide any arguments that you don't, filled in from your main config made by the UI.
* FluentAvalonia: Disabled NavigationView selection indicator animations due to bugged implementation in 2.1.0+, restoring previous behavior
* Avalonia: Fixed text on certain buttons being larger than normal
* Avalonia: Fixed ComboBox code inserting extra space to the left of selected items
Fixes this problem
`|W| HLE.OsThread.47 KernelIpc CallCmifMethod: Missing service Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.IApplicationFunctions: 29 ignored`
Allows add-on content from Just Dance 2023/2024/2025 to be loaded.
Quality of life feature
Similar in function to the "Start Games in Fullscreen" toggle
For users who want to run games in windowed/non-fullscreen mode with
menu UI hidden, this eliminates the need to always click "Hide UI"
You can contribute to Ryujinx with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
You can contribute to Kenji-NX with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
# Quick Links
# Quick Links
@@ -14,17 +14,17 @@ We always welcome bug reports, feature proposals and overall feedback. Here are
### Finding Existing Issues
### Finding Existing Issues
Before filing a new issue, please search our [open issues](https://github.com/KeatonTheBot/Ryujinx/issues) to check if it already exists.
Before filing a new issue, please search our [open issues](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues) to check if it already exists.
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
### Writing a Good Feature Request
### Writing a Good Feature Request
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues).
### Writing a Good Bug Report
### Writing a Good Bug Report
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
Ideally, a bug report should contain the following information:
Ideally, a bug report should contain the following information:
* A high-level description of the problem.
* A high-level description of the problem.
@@ -34,13 +34,13 @@ Ideally, a bug report should contain the following information:
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/KeatonTheBot/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
When ready to submit a bug report, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues.
## Contributing Changes
## Contributing Changes
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/KeatonTheBot/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](LICENSE.txt) docs define additional guidance.
### DOs and DON'Ts
### DOs and DON'Ts
@@ -67,30 +67,25 @@ Please do not:
We use and recommend the following workflow:
We use and recommend the following workflow:
1. Create or find an issue for your work.
1. Create or find an issue for your work.
- You can skip this step for trivial changes.
- You can skip this step for trivial changes.
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
2. Create a personal fork of the repository on GitHub (if you don't already have one).
2. Create a personal fork of the repository on GitHub (if you don't already have one).
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
4. Make and commit your changes to your branch.
4. Make and commit your changes to your branch.
- [Build Instructions](https://github.com/KeatonTheBot/Ryujinx#building) explains how to build and test.
- [Build Instructions](https://git.ryujinx.app/kenji-nx/ryujinx#building) explains how to build and test.
- Commit messages should be clear statements of action and intent.
- Commit messages should be clear statements of action and intent.
6. Build the repository with your changes.
6. Build the repository with your changes.
- Make sure that the builds are clean.
- Make sure that the builds are clean.
- Make sure that `dotnet format` has been run and any corrections tested and committed.
- Make sure that `dotnet format` has been run and any corrections tested and committed.
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
- State in the description what issue or improvement your change is addressing.
- State in the description what issue or improvement your change is addressing.
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) to check for outstanding errors.
8. Wait for feedback or approval of your changes from the core development team
8. Wait for feedback or approval of your changes from the core development team
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
9. When the team members have signed off, and all checks are green, your PR will be merged.
9. When the team members have signed off, and all checks are green, your PR will be merged.
- The next official build will automatically include your change.
- The next official build will automatically include your change.
- You can delete the branch you used for making the change.
- You can delete the branch you used for making the change.
### Good First Issues
The team marks the most straightforward issues as [good first issues](https://github.com/KeatonTheBot/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
### Commit Messages
### Commit Messages
@@ -111,15 +106,6 @@ Fix #42
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
### PR - CI Process
The [Ryujinx continuous integration](https://github.com/KeatonTheBot/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
*`dotnet format` has not been run on the PR and has outstanding stylistic issues.
* There is an error within the PR that fails a test or errors the compiler.
* Random failure of the workflow can occasionally result in a CI failure. In this scenario a maintainer will manually restart the job.
### PR Feedback
### PR Feedback
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
@@ -134,5 +120,5 @@ Ryujinx uses some implementations and frameworks from other projects. The follow
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
- The license of the file is left in-tact.
- The license of the file is left in-tact.
- The contribution is correctly attributed in the [3rd party notices](https://github.com/KeatonTheBot/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.
- The contribution is correctly attributed in the [3rd party notices](distribution/legal/THIRDPARTY.md) file in the repository, as needed.
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017.
It was written from scratch and development on the project began in September 2017.
Kenji-NX is available on GitHub under the [MIT license](LICENSE.txt).
Kenji-NX is available on GitHub under the <a href="https://github.com/KeatonTheBot/Kenji-NX/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
<br><br>
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
<br><br>
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's <a href="https://git.ryujinx.app/ryubing/ryujinx">Ryujinx</a> fork and the more preservative <a href="https://git.ryujinx.app/archive/ryujinx-mirror">ryujinx-mirror</a> fork.
It brings over many of the front-facing features from the aforementioned forks with <i>additional</i> contributions from KeatonTheBot and others.
<br>
</p>
<p>
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
<img src="docs/shell.png">
</p>
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's [Ryujinx](https://git.ryujinx.app/projects/Ryubing) fork and the more preservative [ryujinx-mirror](https://git.ryujinx.app/archive/ryujinx-mirror) fork.
It brings over many of the front-facing features from the aforementioned forks with *additional* contributions from KeatonTheBot and others.
## Compatibility
## Compatibility
@@ -58,12 +53,12 @@ If you wish to build the emulator yourself, follow these steps:
### Step 1
### Step 1
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/10.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2
### Step 2
Either use `git clone https://github.com/KeatonTheBot/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files.
Either use `git clone https://git.ryujinx.app/projects/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3
### Step 3
@@ -125,7 +120,7 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
## Credits
## Credits
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [LibHac](https://git.ryujinx.app/projects/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
This repo includes several documents that explain both high-level and low-level concepts about Ryujinx and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
This repo includes several documents that explain both high-level and low-level concepts about Kenji-NX and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
Intro to Ryujinx
Intro to Kenji-NX
==================
==================
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
Kenji-NX is an open-source Nintendo Switch emulator written in C#. It is based on Ryujinx, which was originally created by gdkchan.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
* Audio output is entirely supported via C# wrappers for SDL3, with OpenAL & libsoundio as fallbacks.
All contributions to KeatonTheBot/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
All contributions to Kenji-NX repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
To merge pull requests, you must have write permissions in the repository.
To merge pull requests, you must have write permissions in the repository.
@@ -18,17 +18,13 @@ To merge pull requests, you must have write permissions in the repository.
## Pull Request Ownership
## Pull Request Ownership
Every pull request will have automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
Every pull request will automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
## Pull Request Builds
When submitting a PR to the `KeatonTheBot/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
## Review Turnaround Times
## Review Turnaround Times
Ryujinx is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
Kenji-NX is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
@@ -41,8 +37,7 @@ To re-iterate, make the review as easy for us as possible, respond promptly and
Anyone with write access can merge a pull request manually when the following conditions have been met:
Anyone with write access can merge a pull request manually when the following conditions have been met:
* The PR has been approved by two reviewers and any other objections are addressed.
* The PR has been approved by two reviewers and any other objections are addressed.
* You can request followup reviews from the original reviewers if they requested changes.
* You can request follow-up reviews from the original reviewers if they requested changes.
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of your PR.
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.