What a year huh? Captain, it’s only August.
So much happened in July that it felt infinitely longer than a measly 31 days. A new Xenoblade, Digimon (yep all 5 of you), patreon goals finally coming to fruition; we truly had a month to remember. So what do we have in store for this progress report? We’ve got a regular rundown of all the changes, a bit of a discussion on AMD (seems like a segment lately) and also, not to ignore the elephant, a big sign asking you to read the dedicated Vulkan blog post!
No point delaying further so before we start please take a look at our patreon goals.
Vulkan GPU Backend - MERGED!
We made a dedicated blog post about this so check it out here!
ARB Shaders - Goal reached in April 2021.
Work is ongoing, please wait a little while longer until we are able to deliver this update into a state we are happy with.
ARB shaders will further reduce stuttering on the first run by improving the shader compilation speed on NVIDIA GPUs using the OpenGL API.
$2000/month - Texture Packs / Replacement Capabilities - almost there!
This will facilitate the replacement of in-game graphics textures which enables custom texture enhancements, alternate controller button graphics, and more.
ETA once the goal is sustained: ~3-4 weeks
$2500/month - One full-time developer - Not yet met.
This amount of monthly donations will allow the project's founder, gdkchan, to work full-time on developing Ryujinx. All our contributors currently only work on the project in their spare time!
$5000/month - Additional full-time developer - Not yet met.
This amount of monthly donations will allow an additional Ryujinx team developer to work full-time on the project.
Cool? Let’s dive in.
Resolution scaling fixes get us out the gate this month, with riperiperi resolving a particularly annoying bug when scaling certain games, such as A Hat in Time and Cruis’n Blast. These titles would smear the screen with red when scaled beyond native resolution, making scaling these games a bit of a double-edged sword. Luckily the solution here is to simply avoid scaling these rebel textures while continuing to scale everything else.
The SD Gundam Battle Alliance Demo booted at release but unfortunately crashed when in-game. The cause was tracked down to a bug in the fast path for DMA linear texture copies, but by forcing the FindTexture method to only match linear textures with an exact copy height, the game now boots and looks to function great.
An issue in how we manage sampler pools finally emerged this month with some poor performance in Super Zangyura. Considering how visually basic the game is, it was a surprise that it struggled to reach over 30FPS on modern hardware. The texture pool cache had a hard limit of 4, which means that if a game needs to use more than this, one of the 4 is deleted and will need to be recreated when needed, causing some major performance dips on creation. By creating a sampler pool cache and better evaluating when pools can be safely disposed of, the performance in games that overload the limit of 4 is greatly increased. Most games only use a single texture pool so don’t expect this to affect much beyond this one.
JUMP FORCE Deluxe is a game that has been so close to being graphically accurate for a fair while now, with the only remaining major visual bug being large green lights appearing in the scene.
The issue here is a simple data loss error on the shader. As the decoder did not consider branch instructions in some scenarios, the shader code generated would skip some vital information. By fixing this omission, gdkchan finally put a nail in this particular coffin.
On the topic of large light sources where they probably shouldn’t be: Tokyo Mirage Sessions had rather significant, shall we say, solar activity resulting in the game being virtually unplayable. This was an issue with the bloom the game uses and once again was an issue with a generated shader. By supporting conditional exits our retinas were saved!
The new Monster Hunter Rise DLC required some difficult changes in order to render, which are gradually being rolled out. The first of these allow the game to reach its splash screen by extending bindless elimination to shaders that are combined with a constant handle.
The second of these fixes the flicker in the new Sunbreak DLC by extending the shader optimizer to propagate phi nodes. Unfortunately, we don’t have an image comparison here, as to even render the game a few more WIP changes are needed. Hopefully in a future report there will be a full set of before and after comparisons for the entire DLC package!
Since shader cache 2.0, some old changes in the backlog were finally able to be completed, including the addition of alpha to coverage dithering. For anyone unaware: ‘dithering’ refers to an effect in computer graphics where objects or textures get this spotty look to them:
In retro video games this was used to add depth to otherwise muddy textures; it eventually became quite standardized as a way to make solid objects appear translucent when a camera shifts behind so as to keep the player in view.
Pokémon Legends Arceus makes use of dithering on environment models such as trees and rocks, but previously this effect was not emulated as it required the new shader specialization introduced in the new shader format. gdkchan attempted a fix at this before the cache rewrite, but without shader specialization the dithering emulation would need to be present on every single fragment shader, even if the shader would never use it. Those issues are all resolved in this new implementation.
Some redundant allocations in the DMA handler were also removed this month, which may result in some small optimization in FMV (Full-Motion Video) playback due to lower GC stutter during playback. Results here are hard to measure, but this hopefully removes one of the simpler bottlenecks in video playback.
To close out the GPU section we have the piddling addition of a Vulkan backend. Not too big, no serious changes here and only 40,000 lines of code. Rookie numbers, if you ask us. Anyway if you want to hear more of this topic check out the full blog post!
The flatpak needed a quick update to make sure it didn’t crash upon selecting Vulkan and we now avoid adding shader buffer descriptors for unused constant buffers; a change that affects OpenGL too but may give a minor performance bump for Vulkan.
July also brought some new CPU and service fixes, implementations and stubs; the first of which are a couple of BSD (network sockets) fixes. The DontWait flag can now be used in the ‘Recieve’ methods and the case where the byte size options are exchanged over a network are now handled. The second of these changes is partially required by the newly released Super Mario Odyssey Online mod, and fixes a crash regression in Divinity Original Sin 2.
As we attempt to emulate the entire Switch, there are some services that most users may not even think of for a PC emulator. One of these is the aptly named ‘GetTemperature’ service which, you likely guessed it, reports back the Switch’s internal temperature in degrees celsius. This service was causing the homebrew launcher to crash during boot as it attempted to probe for this data. The stub sets a constant temperature of 42 degrees celsius (69 was taken apparently…) and this seems to satisfy homebrew’s environmental needs.
With the release of the Portal collection on Switch, two issues were found in both our service and CPU emulation. The first of which was an inaccuracy in our Vi services which were quickly resolved with RE from gdkchan, and the second was the implementation of FCVT Half to Double conversion instructions. With these changes both Portal 1 and 2 boot, with Portal 1 being largely bug-free. Portal 2 still has some graphical issues with objects culling when they shouldn’t.
User interface development was hot in the street in July although not many regular users will have seen much going on. We’ve mentioned our shift to Avalonia multiple times by now and just recently we pointed out part 1 of the project being merged.
Well, part 1 can take its leave because July merged both part 2 and 3, thus bringing the new UI on par with the current GTK implementation.
Part 2 implemented the complete settings windows:
Part 3 added the remaining context windows:
But while these were core changes, they very much opened the floodgates for fixes, additions and tweaks that any contributor can now bring. The project files were cleaned up once, twice and then some quality of life adjustments were made.
This included enabling ‘tiered-compilation’ for all projects. Avalonia is a fully ‘JITed’ framework, compared to GTK which is considered ‘Native’, and this means that the .NET runtime usually has to do a lot of work on the first run even after the program is compiled; tiered-compilation allows .NET to boot applications without applying all of it’s code optimizations, thus speeding up GUI boot-times and reducing app latency in general. As the program is booted more and more often, .NET can gradually start to perform these optimizations over time instead of dumping them all at once. This has been enabled for GTK too, but as a ‘native’ framework GTK doesn’t need to do nearly as much work on GUI launch as Avalonia does. We saw a reduction from 14 seconds down to 3 seconds the first time we ran the Avalonia application with this enabled.
‘Ahead-of-Time’ compilation also accomplishes a similar task as tiered-compliation to provide latency reductions by shifting some of the first-run costs into the compilation process. The downside to this approach are file size increases of up to 3x, a cost the development team felt was too much for what turned out to be a minor improvement over tiered-compilation.
Emmaus (lead UI developer) has also started to branch away from GTK now that feature parity has been achieved. The user profile editor now uses a single content dialog box instead of new individual windows per option. This means a much more fluid experience with less clutter and latency between opening and closing windows, and also lays the groundwork for further such content dialogs for upcoming data managers (a save manager is already in the works).
A lot of other miscellaneous changes were made in addition to these, including:
- A couple of grammar fixes to the tooltips and options, including GTK.
- Tooltips for Avalonia were revamped and then backported to GTK.
- The simplified Chinese locales were updated and traditional Chinese added.
- Borders were added the flyout menus.
- Bug fixes to mouse input, show console toggle, and cursor hiding were implemented.
- A workaround to allow menu items to be toggleable on-click instead of just in their checkbox was added (will be removed when Avalonia addresses this oversight).
- Fixed a bug where the program would crash when trying to switch a controller mid mapping.
As you can likely see, it’s all kicking off and we already have an even longer list of bugs and problems to be resolved before Avalonia can become the default UI that everyone is greeted to when they boot. Once those are addressed, the process of changing the updater to deliver you all the new UI project instead of the old one will commence. For now, you’ll have to remain patient while the work to make it a seamless experience continues in the background!
To close us out of the changes this month. our project’s infrastructure and QoL had a few major revisions including:
- Ensuring we load the latest FFmpeg libraries first (avoids crashes due to outdated dependencies).
- Removing the FFmpeg dependency entirely for Windows and packaging our own bindings.
- Relicense and reformat the Ryujinx.Audio project to the MIT License in line with the rest of the project. This is required for the above ‘tiered-compilation’ feature to be compatible with our licensing.
- Resolution scaling can now be adjusted via hotkeys. Defaults to unmapped but will be mappable when Avalonia is merged or currently can be mapped by directly editing the ‘config.json’ in the Ryujinx data folder.
A particular change that a lot more of you will be interested in is the unofficially dubbed “Windows 11 FixTM”. Users noticed that upon updating to Windows 11 Ryujinx became nigh unplayable in some games due to large and constant stutters that dropped FPS for apparently no reason.
Due to the way Horizon OS operates there are a number of quirks that operating systems like Windows need to step around in order to be accurate; one of these is that we need to map memory in 4Kb sizes. Windows 11 appears to have a unique bug where this process can sometimes take hundreds of times longer than it did on Windows 10, and we still have no idea why this is.
By moving the memory unmapping handler to a native handler we can massively reduce the number of these problematic 4Kb mappings, and thus salvage Windows 11’s woes.
“Hey Ryujinx Team, we heard that AMD finally fixed their OpenGL drivers?”
Well it finally happened. AMD has acknowledged the existence of OpenGL. As you can imagine it was a day of celebration. We ordered pizza, popped open the champagne, shared blissful memories of darker days when AMD GPUs only managed 13FPS in Super Mario Odyssey…
Wait, what? Not only is it still bad but AMD somehow managed to break rendering on the Odyssey too? Siggghhhhhhhhhhhh
To return to more serious discussion: it isn’t all as bad as what’s seen on SMO here, and in some games we do have to give AMD credit where it’s due for the dramatic OpenGL improvements in some cases.
Those of you who have read our Vulkan blog should be familiar with this graph, but added here is the “NGL” dataset which you could read as “New GL” for AMD’s new 22.7.1 driver. Performance is bumped across the board everywhere we tested other than, weirdly enough, SMO, where both performance and graphics rendering regress. Mario Kart 8 Deluxe has a large performance bump but likewise suffers from brand new visual bugs.
Vulkan remains the best choice for AMD GPU systems, but at least OpenGL is a viable option in some titles. Metroid Dread is actually the outlier here with a staggering 269% increase over the old driver and even improving on Vulkan by 143% (although we’re fairly certain this is just due to an API bottleneck, as even Nvidia sees much greater OpenGL performance in this title).
Either way we hope this clears up that question. We’re happy that AMD has finally done something to address their performance roadblocks, but this should be regarded as just the first of many improvements. Claiming OpenGL is ‘fixed’ would be quite premature, and we’d all like to see AMD continue to focus on the remaining performance issues, rendering bugs and lack of extensions (this one applies to Vulkan too!).
That's about it! For those of you looking for Xenoblade Chronicles 3 news you’ll have to wait for next month, but the gist of it is that there are currently random crashes on Vulkan, and OpenGL is so slow at shader compile you can hardly watch some cutscenes! Other than that, performance appears fine but we wouldn't call it enjoyable to play just yet. You can check out the compatibility report here.
Emulators are built and maintained on thousands of hours of work encompassing everything from reverse-engineering, CPU and GPU emulation, service HLE and all the way up to UI and UX. Our door is always open to anyone who has an interest in applying themselves to a truly unique project at the cutting edge of both Switch emulation and C# in general. If this sounds even the slightest bit like your cup of tea, then check out our Github or join or Discord.
See you all next month!