Dolphin Progress Report: November and December 2023, January 2024

With the conclusion of the holiday season, it's time for us at the blog to get back to work. And this time around, we have a smattering of changes covering just about everything you could imagine. For those looking to enjoy some of the latest homebrew with DSP-HLE, Dolphin now has support for the latest homebrew microcodes! For retail games, we also have a minor update to the Zelda-HLE microcode to fix a missing effect that's long overdue.

In some more important news, for those of you having disk space issues when running Dolphin on Windows since the last beta, a fix is now available. And for those looking for the clearest picture possible, Dolphin's mipmap heuristic has been backed down to allow for higher resolution mipmaps across more textures. And of course, if you're wanting that perfect image, Custom Aspect Ratios will allow for easier use of ultra-widescreen hacks and more!

Add to all of that a huge bugfix for older revision Steam Decks, another chapter in the Bounding Box saga, seeing a classic in an all new way, and yet another chapter in broken GPU drivers, and you've got yourself a Dolphin Progress Report.


Notable Changes

5.0-20353 - DSPHLE: Support 2023 libaesnd uCode by Pokechu22

libasnd and libaesnd are open source DSP microcodes for the GameCube and Wii, and are the standard DSP microcodes used by homebrew. When Pokechu22 reimplemented the libasnd and libaesnd microcodes in DSP-HLE back in 2022, we knew that if they were to ever be updated, the new versions would not automatically work in DSP-HLE. This is due to how DSP-HLE itself works - rather than emulating the DSP hardware and running the microcodes directly, DSP-HLE runs reimplementations of the microcodes themselves, made in C++. Thanks to a tremendous amount of work, this is just as accurate as the hardware-emulating DSP-LLE, yet many times faster. However, since DSP-HLE doesn't actually run the microcodes, Dolphin checks the hash of the microcode in the game to know what to use. If the hash of the game's microcode doesn't match any of the reimplemented microcodes, DSP-HLE will fallback to the reimplemented AX microcode, and in the case of homebrew probably not emit any sound at all.

This occurred in 2023, when libaesnd saw an update to address a few minor issues. These small fixes meant a new microcode version with a brand new hash which Dolphin did not recognize, resulting in audio not working under DSP-HLE in titles that used the new version of libaesnd. Specifically, it was the latest versions of the Sonic Mania Wii decompilation port that brought this update to our attention. As a fairly new project in active development, they are consistently updating their microcodes, and they are the first software we are aware of to use the new updates.

Thankfully, the updates to libaesnd were relatively minor and Pokechu22 mostly just had to document what was changed and add the 2023 hash to the libaesnd code paths in DSP-HLE. With that, users can enjoy Mania's Chemical Plant Zone theme in DSP-HLE once again!

Sonic Mania running in Dolphin, with sound in DSP-HLE!

5.0-20880 - Zelda-HLE: Fix Reverb Volume Factor by flacs

Sticking to the theme of DSP-HLE, we have a microfix from longtime contributor flacs. This in particular targets the missing reverb effects noticed in Mario Kart Double Dash!!. These effects were noted to be broken way back in 2015 but was marked as low priority amidst a massive Zelda-HLE rewrite. When the rewrite was complete, this bug remained as a minor issue.

flacs returned and has been hammering down bugs in all quadrants. This one turned out to be rather simple. The reverb volume was erroneously being multiplied by current volume twice, resulting in the effect becoming incredibly quiet. While the bug reporters originally thought the reverb was missing, they actually just weren't listening hard enough for it!

Once this oversight was fixed, the effect started working as intended.

5.0-20517 - Implement Send Mail by Sketch

Have you ever had an important work email that you needed to send right now but all you had at your disposal was an emulated Wii? This is a position I think we can say every single one of us have been at some point, but unfortunately in the past there was nothing you could do about it.

Thankfully, Sketch took note of the plight of our users and has been slowly working through the Wii Mail system, and while it's not entirely complete, those registered with the WiiLink service can send messages to other Wiis and even emails directly from Dolphin!

To get to this point, it's been a rather long ride, and a ton of the legwork was already done for WiiConnect24 emulation. Soon, we're hoping to have full parity between using WiiLink on a console and Dolphin, though there are still some missing features on the Dolphin side of things.

5.0-20589 - Rewrite LazyMemoryRegion by AdmiralCurtiss

Last Progress Report, we described a performance optimization that had the annoying side effect of taking up 32 GiB of disk space on Windows. Now AdmiralCurtiss has rewritten the code used on Windows to avoid side effects of this kind.

To summarize the problem from last time: Dolphin needed a 32 GiB memory allocation to efficiently keep track of where recompiled code was located. Most of it didn't need to be backed by real memory, but whenever Dolphin wanted to access a particular location, real memory had to be allocated on the fly so the access wouldn't fail. In the solution described in the previous Progress Report, we handled this by asking the operating system to allocate pages for us as needed. This worked well on almost every OS, but on Windows we ran into the problem that the system would force the page file to grow to match our huge 32 GiB allocation, in case we try to access all 32 GiB.

With the new solution, we're handling things more manually on Windows. AdmiralCurtiss's initial idea was to mimic what the operating system was doing by setting up a signal handler that runs when Dolphin tries to access an address that isn't backed by real memory – something Dolphin is already doing for the tried and tested fastmem optimization – and then allocating some real memory when the signal handler runs. But because Dolphin only writes to the 32 GiB region from two pieces of code, both of which run relatively infrequently, Progress Report reader PJB3005 was able to come up with a simpler solution that AdmiralCurtiss then implemented. Instead of using a signal handler, Dolphin now manually checks if it needs to allocate any real memory before it writes to the 32 GiB region. Parts of the 32 GiB region that aren't yet backed by real memory are pointed to a read-only page filled with zeroes, so that nothing will go wrong if Dolphin tries to read from a location that hasn't been written to.

Now Dolphin users on Windows are able to benefit from the JIT Block Lookup performance optimization without worrying about Windows making their page file balloon. Issues like not being able to download large files while Dolphin is running will no longer occur.

On operating systems other than Windows, Dolphin is still using the old approach where the OS allocates real memory on the fly, since we've only seen problems with that approach on Windows.

5.0-20745 - Disable Arbitrary Mipmap Detection by Default by iwubcode

As part of the essential hack that is raising Internal Resolution, Dolphin adjusts the mipmap level of textures. Mipmapping is the process of swapping to lower resolution versions of textures if they would appear too small in the final image. This is an old graphics staple - using maximum resolution textures everywhere leads to severe aliasing and moire on distant textures and textures at oblique angles. However, this is resolution dependent, and mipmap targets set for 480p will be intensely blurry at 4K. So Dolphin adjusts the mipmap levels to match the increased Internal Resolution, significantly improving overall texture quality of the final image.

However, some GameCube and Wii titles use mipmap shenanigans for effects, and by changing the mipmap levels, we were breaking these tricks. To have our high resolution cake and eat it too, in 2017 we added Arbitrary Mipmap Detection, a heuristic that attempts to detect mipmap mischief and drop to a more accurate mipmap implementation for only the textures involved in these effects. The result is that the specific textures used for these effects will be blurrier, but as it is correcting broken effects and should only affect the specific textures involved, it's a win win. Theoretically.

Galaxy 2 reads the mipmap level to control this fog effect in the sky.
Without Arbitrary Mipmap Detection, the fog is gone and the clouds repeat infinitely.

Unfortunately, this heuristic has proven to be problematic. It often has false positives, incorrectly detecting mipmaps as being used for effects and needlessly using blurrier versions.

With Arbitrary Mipmaps, the back of the ship in Skies of Arcadia is much blurrier than it should be.
Without Arbitrary Mipmap Detection, the ship is considerably crisper.

To account for this, in 2018 we added the Arbitrary Mipmap Detection toggle. On by default, this option gave anyone who was having trouble with the heuristic the ability to simply turn it off, and avoid any problems it may cause. It was a simple solution, and it has remained ever since.

Fast forward to late 2023, and iwubcode asked a question that shook us all: "how many games use arbitrary mipmaps for effects?" In the resulting back and forth, we realized the number of games that utilize mipmap hijinks is... not a lot. To our knowledge, only Nintendo used this technique. Of course these were games by Nintendo, titles that are flagships of the GameCube and Wii lineup, like Super Mario Galaxy and The Legend of Zelda: The Wind Waker. However, by being such core titles, we realized that the importance of detecting these effects was overestimated. As far as we are aware, a couple dozen games use the trick, and thousands of games do not. Considering just how common and pernicious false positives are with the heuristic, having the heuristic on by default for every game was probably causing more harm than good.

So we have decided to change that. Arbitrary Mipmap Detection is now off by default. From now on it will only be enabled by default in known cases, via our GameINI system. If you happen to spot any issues that are resolved by turning on Arbitrary Mipmap Detection, please let us know and we'll add it to the list of known mipmap tomfoolery.

5.0-20785 - Support Custom Aspect Ratios by Filoppi

Dolphin's Widescreen Hack is both amazing and terrible in equal measure. By expanding the View Frustum, it allows Dolphin to able to render any game at any aspect ratio, and thus fill any screen without stretching the image! However, the Widescreen Hack is only performed on the Dolphin side, and doesn't affect the game's logic at all. Frustum Culling, screenspace 2D graphics, and more are entirely unmodified. The result is large blank areas in the expanded space, stretched 2D elements, and aberrant pop-in are simply the reality of the Widescreen Hack.

Fortunately, we have an alternative - game-specific aspect ratio cheat codes. By editing the game itself through our cheat system, all of these quirks can be addressed and a much better result can be achieved.

Wasn't this room supposed to have walls?
Through the power of action replay codes, geometry is no longer being culled and we don't have to worry about pop in!

However, aspect ratio codes require the user to configure their aspect ratio. For example, to run Ralf's 16:9 Aspect Ratio code for Wind Waker, a user must set Dolphin's aspect ratio to Force 16:9. Simple enough.

But what happens if your display is an UltraWide? 21:9 codes are fairly common, but there is no "Force 21:9" option. To work around this, 21:9 display users can set the aspect ratio to "Stretch to Window" and enter fullscreen. This does the job, but this has some issues. Ultrawide aspect ratios are less a standard and more of a suggestion, so even within the 21:9 category, the actual ratios vary. In the real world, our little workaround usually results in minor distortion.

But worse still is Super UltraWide. 32:9 aspect ratio codes are few and far between, making the workaround above unviable. The best option available for 32:9 users was to combine a 21:9 code, windowed mode, and Stretch to Window Size, then very carefully size the window so that there was no stretching. Not great.

This works, but you have to hide the Windows Taskbar, Windows will not let you move the titlebar of the window off screen if you don't have a secondary monitor, it's a lot of faff to set up, and it requires you to void your wallpaper for the best result. It's not a great experience.

Filoppi decided that this will not do, and added a new Custom Aspect Ratio option to Dolphin. Using this feature, you can effectively force Dolphin's aspect ratio to whatever you want. Now, Super UltraWide screen users can enjoy 21:9 in fullscreen without any fuss or distortion!

Set up a 21:9 code, configure a Custom Aspect Ratio of 21:9, and just enter fullscreen like normal! It's that easy!

Plus, this change allows any aspect ratio on any display, so if you have a 16:9 display and want to play 21:9 on your OLED TV or something, you can do that! In fact, if a theorectical retro port to the GameCube or Wii has an incorrect aspect ratio, this could even be used to correct it! We haven't actually found any of those yet, but it's an intriguing possibility.

To use this feature, just set the Aspect Ratio to "Custom", and configure the ratio to whatever you like!

However, as we do whenever we give dangerous new powers to users, we must exit with a word of caution. The GameCube and Wii were never exactly 4:3, 5:4, or 16:9. Yes, on hardware. It was the days of analog displays and their crimes were all going to be overscanned away anyway, so game developers had no reason to care about being exact. Back when Dolphin assumed standard aspect ratios, every. single. game. was off to some degree. Remember the Melee shields?

This is the hell we used to live in.

This was a tremendous headache for us, and to resolve it required months of effort from very skilled engineers, testers, esports communities, and more. It was an enormous undertaking.

The result of all that work is that Dolphin reads the exact Aspect Ratio the game is instructing the console to scan out and displays precisely that. And to make sure users see it without distortion, all of our aspect ratio modes used these corrections, with only Stretch to Window bypassing it. Well, now there is a second way to bypass it. A Custom Aspect Ratio will give you exactly what you enter, no matter what. So if you are playing in ordinary 4:3 or 16:9, and you configure the custom aspect ratio to 4:3 or 16:9, you are bypassing Dolphin's aspect ratio adjustment and you will be distorting the image in all cases.

Please use this power responsibly.


5.0-20849 - VideoCommon: Apply "Force 24-bit Color" to EFB Copies by flacs

"Force 24-bit Color" is an enhancement that reduces banding by forcing the emulated hardware to the highest bitdepth possible. However, there were some cases where turning on the enhancement did not improve banding at all! This change fixes that, but to explain why, we're going to have to get technical.

To understand this problem, we need to go over how post-processing works on the GameCube and Wii. This first paragraph may be a little familiar, but bear with us. While rendering, the ArtX GPU in the GameCube and Wii rasterizes to the "Embedded Frame Buffer" (EFB), a 2MiB chunk of extremely fast working memory that resides in the GPU itself. While some basic post-processing can be applied while the frame is in the EFB, any effect that involves reading then distorting the frame cannot be done while it is in the EFB. So for most post-processing effects, games will execute an EFB Copy to transfer the frame to main memory, then read the frame as a texture from which to render again on top of. However, the consoles primarily render in 6-bits per channel RGBA6, but cannot read a texture in that format. To deal with this discrepancy, it is common for games to convert the frame to 8-bits per channel RGBA8 during the EFB Copy to maintain full visual quality.

However, a fullscreen image at RGBA8 is HUGE for this hardware. Assuming a 640x480 render target, that would be 9830400 bits, or 1.17MiB! And for post-processing effects, multiple renders need to be made! The GameCube's Main Memory is only 24MiB, and the game needs to live in that space too. So many games opt to EFB Copy some images into main memory in the RGB565 format. A 640x480 RGB565 image is only 4915200 bits in size, or 0.59MiB. That's half the size!

But of course, this came at a cost. Most games render in RGBA6. 6-bits per channel is 64 values per color, for 262144 total possible colors (ignoring the alpha channel). RGB565 has two channels at 5-bits (32 values per color), combining to a total of 65536 total possible colors. RGB565 has significantly fewer colors making banding much worse, and it is missing the alpha channel entirely, limiting its uses. However, when the benefit was halving an image's RAM usage on a chronically memory-starved machine, this was a option that many developers utilized.

A certain brave developer tried to maximize visual quality by switching between RGBA8 and RGB565 EFB Copies depending on how much memory was available. This was the equivalent of playing hot potato with a hand grenade. Click the explosion above to read that story!

And now we return to Dolphin. In Dolphin, we support the original RGBA6 that games usually render with, and all other formats for rendering and EFB Copies. However, the hardware we are running on is almost guaranteed to be 8-bits per channel RGBA8 or better, so we have an enhancement called Force 24-bit Color. This mode forces the emulated console into a hybrid RGBA8-ish mode where the color channels are 8-bits per channel, and the alpha channel remains at 6-bits. This is mildly inaccurate, but it is not that far removed from what the console can do, and it substantially reduces banding. It's a relatively safe enhancement that can significantly improve image quality.

However, for Luigi's Mansion, Force 24-bit Color did not affect banding at all.

This was the game with Default settings.
And here it was with Force 24-bit Color. Yes they are not the same image, we are sure.

flacs noticed this discrepancy and looked into it. Force 24-bit Color forces the initial render to use the RGBA8 mode. However, Force 24-bit Color did nothing to EFB Copies, which every frame will undergo at least once! If the game used the typical option of EFB Copying into RGBA8, then Dolphin would take an RGBA8 image and EFB Copy it into an RGBA8 image, and the enhancement would still be in effect. But if the game chose to go with RGB565 (or RGB5A3... we're not going to talk about that one), Dolphin would follow the game's instructions and decimate the RGBA8 rendered image into RGB565, completely destroying the enhancement in the process!

Due to the color compromises, most games use RGB565 sparingly, saving it for secondary post processing of effects that only partially cover the screen. Most of the time, the RGB565 pieces of an image would be difficult to spot. Not so with Luigi's Mansion, as it EFB Copies the entire framebuffer in RGB565! This decimates the entire screen, rendering Force 24-bit Color effectively useless!

So flacs has corrected this oversight. Now, whenever Force 24-bit Color is enabled, EFB Copies will also use RGBA8 within Dolphin. Thanks to this change, we can see Luigi's Mansion as we never have before!

First Image Active Image

Click/Tap and hold to see the banding improvement Force 24-bit Color can now achieve!

Force 24-bit Color will be improved in any title that uses lower quality EFB Copy formats such as RGB565. Players using the feature should look for reduced banding in their favourite titles! However, most games only use these lower quality EFB Copy modes for part of the screen, so most titles that are improved will see a less dramatic change than Luigi's Mansion.

5.0-20923 - Steam Deck: Pad out feature report to 64 bytes by endrift and ArcaneNibble

In the previous Progress Report, we covered 5.0-20148 - Periodically Re-enable Steam Deck Gyro. Current versions of SteamOS will try to shut down gyros that it thinks are not being used. This gave us a lot of issues, so this change addressed this by making Dolphin re-enable the gyro on Steam Decks roughly once per second.

However, due to SteamOS quirks, it's not easy for users to run Development builds on Steam Decks. Most Steam Deck users get Dolphin builds through Flatpaks of our Beta builds. So while the change was tested by the developers before being merged, it was only after the Report and the Beta release that the Flatpaks were updated and this change was finally able to reach wide adoption in users' hands.

And almost immediately, we started to get reports of doubled inputs in the latest version of Dolphin. Uh oh.

The author of the change, ArcaneNibble, immediately retested and couldn't reproduce it. And yet reports kept pouring in. So more of our developers tried it, and they couldn't reproduce it either. A few of our users and testers tried it, and weren't able to reproduce it either. Yet more and more reports kept pouring in. What was happening!?

This back and forth continued for weeks, until finally, we stumbled upon the answer. Older Steam Decks were affected, and newly built Steam Decks were not. It turns out that the Steam Deck LCD had a major revision in the fall of 2023! The revision completely changed the Deck's internals, with significantly different PCBs and component parts! And sure enough, the Deck's Steam Controller controller chip was refreshed too. Steam Decks made before fall of 2023 use an Atmel controller, while Steam Deck LCDs made after fall of 2023, and all Steam Deck OLEDs, use a Renesas controller. Once we realized this potential source, we asked users to run a command that reported the controller in their Deck. In all of our samples, Steam Decks with Atmel controllers always had the issue, and Decks with the Renesas controller never had it.

Now that we knew how to reproduce the issue, we asked developers who work on the Deck for help. endrift, mGBA author and Dolphin contributor, has been working on the Deck a lot lately. She came in and worked with the author of the change for a thorough debugging. It turns out, ArcaneNibble made an tiny oversight and didn't fill in one value.

Broken Code:

const unsigned char pkt[] = {0x00, 0x87, 0x03, 0x30, 0x18, 0x00};

Working Code:

const unsigned char pkt[65] = {0x00, 0x87, 0x03, 0x30, 0x18, 0x00};

ArcaneNibble forgot to pad the packet size of the feature report packet. That's it. Here's endrift explaining what happened:

When Steam tells the Steam Deck (or previously the Steam Controller) to change a setting, it uses something called a HID feature report. Feature reports can be up to 64 bytes long in USB 2.0, and the size of a device's report is described in the suitably named report descriptor, which is specified by the HID standard.

Feature reports can be split out into up to 256 different IDs, each of which can have a separate size as described in the descriptor. However, for a dynamic system like the Steam Deck, sometimes devices just define a longer-than-used 64 byte report size and just pad the end out with zeroes, then define the ID outside of the descriptor.

Steam always sends a fully padded 64 byte report, in accordance with the report descriptor. However, by sending a feature report with less than 64 bytes, the implementation on the USB device end gets confused. Quite possibly later feature reports get misinterpreted as a result, and one of these misinterpreted reports from Steam causes this issue.

However, Renesas chips don't appear to get confused and just internally assume the report should be padded to 64 bytes even when fewer are sent.

This resulted in Atmel controllers entering a glitched state where they operated in both "Lizard Mode" (the default fallback controls for when Steam is not running) and normal mode at the same time, doubling every input. Renesas controllers, on the other hand, were entirely unaffected.

So endrift tested a fix and made a quick PR, and now the double input issue is resolved! While the solution may have ended up being very simple, this bug was a very difficult one to identify. It took the entire Dolphin Steam Deck community chasing this bug for us to figure it out and get it sorted. Thank you to everyone who reported and helped us chase this sneaky bug!

5.0-20941 - SDL: Add GameController API, cleanup by SuperSamus

SuperSamus has given our SDL input backend some love. First, they added support for the GameController API, an abstraction that allows consistent mapping across different controllers. Users will be able to switch controllers, i.e. a DualSense to a Switch Pro Controller, seamlessly without remapping! SuperSamus also cleaned up our SDL input backend, cleaning up a bunch of workarounds for old SDL versions that are no longer applicable to our current SDL2 input backend. SDL is now better than ever before, on all operating systems!

In fact, as of this change SDL has once again been enabled by default in our Linux builds! SDL has come a long long way.

5.0-20961 - Only initialize Bounding Box if supported by GPU/driver by AdmiralCurtiss

"Renderer" was an abstraction in Dolphin's code that functioned as an interface for video plugins. However, when the video plugins were merged with Dolphin's code and became video backends, Renderer became a dumping ground, filling up with tons of miscellaneous code and features. So, last year, Phire set off with the mission to kill Renderer entirely, refactoring enormous amounts of Dolphin's graphics code.

Kill Renderer moved a lot of code around.

We covered Kill Renderer here on the blog, both because it was a huge achievement, but also because any change that touched that much of Dolphin's codebase was likely to have unforeseen consequences. And that is what we come to today.

After Kill Renderer, we received reports from users on very old GPUs that Dolphin no longer worked for them. Now, any game they attempted to run would fail to start, with the error "Failed to create BoundingBox Buffer."

This occurred after running Super Smash Bros. Brawl. That game doesn't even use Bounding Box!

After Kill Renderer, Bounding Box was always initialized whether the hardware supported it or not. This doesn't affect most of our userbase, as >99% of our users' hardware supports the feature, but for any hardware that doesn't support Bounding Box, this regression completely broke Dolphin!

AdmiralCurtiss looked into this and made a quick fix. As of this change, Dolphin will perform the same as it did before Kill Renderer on those GPUs - Dolphin runs again and games work, but if a user attempts to run a Bounding Box title, they are in for a buggy good time.

Mario refuses to be associated with the Intel HD Graphics 3000.
Now that's an air ship.
Unlike the GameCube, Intel HD Graphics 3000 cannot handle this many sprites at once.

Notice for Nvidia Users

We've received reports of texture corruption in D3D11 on Nvidia GPUs with their latest drivers. This is still developing, as we have yet to properly isolate and analyze this, but we believe it to be some sort of driver issue. For now, we recommend Nvidia users avoid our D3D11 backend.

Last Month's Contributors...

Special thanks to all of the contributors that incremented Dolphin from 5.0-20349 through to 5.0-21088!

Entrada postrera

Entraes paecíes