While we prefer to get these progress reports shortly after the turn of the month, sometimes things happen out of our control. June wasn't exactly a slow month, but it was backloaded with tons of changes that we weren't expecting to get merged so soon.
Sometimes delays are inevitable, but the notable changes that we were able to include thanks to extending the deadline should more than make up for the several day wait. You've been waiting long enough - without further delay, please enjoy this month's notable changes.
We usually try to keep things in close to chronological order for Progress Reports, but this one is a bit of an exception. DolphinQt has been developing at a pace that none of us could have anticipated. With spycrab0 at the helm and many others pitching in, there have been hundreds of changes and fixes merged in the past few months. That's not to say there hasn't been some growing pains, but Qt has slowly been winning over users in recent development builds. Excitement mounted as DolphinQt went from a curiosity to the dominant backend in the last couple of months.
As DolphinQt blossomed, DolphinWx was relegated to the secondary executable. While we did not promise to maintain it, keeping it around came at a cost. A lot of the major GUI changes that have been long awaited had to bide their time a little bit longer until Wx was completely removed. Further more, many developers were tepid toward the idea of working on features that would require GUI work while there were two GUIs to worry about. Dolphin was marching toward a stalemate with the Qt GUI reaching maturity sooner than expected.
Many times over, we've opened ourselves up to criticism by removing features that were still in heavy use. Some removals have gone smoother than others, but it's never easy. You can find controversies around the removal of asynchronous audio, the sudden decision to axe the x86-32 JIT, D3D9, D3D12, and many, many others of varying magnitude. DolphinWx joins the litany of others that line a graveyard of features spanning a decade and a half. Was its removal sudden? Absolutely. Did it have to happen right then? Not necessarily.
The other side of the argument was that while Qt had only been the default for a couple of months, it was already the majority GUI among all development builds! When we narrowed down the numbers to only include revisions where Qt was the default GUI, the landscape became much clearer.
By all accounts, Wx was a deprecated GUI hemorrhaging users, especially in the most recent of builds. It didn't really made sense to keep it around if it meant stagnating Qt. And since the Wx removal, work has already started on more drastic departures from Dolphin's classic GUI, such as a visual controller configuration page along with some initial ideas to make editing Dolphin's many INI files easier going forward. Last, but not least, with DolphinWx gone, we can finally continue work on Dolphin's configuration rewrite that got stalled in order to make the transition easier.
All we can ask going forward is that users keep voicing their displeasures about DolphinQt until it does everything that DolphinWx did but better. Later on in this Progress Report there are a litany of Qt changes that mostly came from suggestions and reports that we heard on the forums and social media from concerned users. For those of you already content and especially those that have reported issues, we thank you for riding out the initial rollout of this feature and hope you'll enjoy many of the exciting additions yet to come.
Qt Feature Roundup¶
Over the course of June there were a lot of smaller Qt changes that have greatly improved the user experience. Here's a list of some of the improvements you can see right now!
- 5.0-8138 - Greatly improve performance. Makes the Gamelist run much more smoothly, especially when changing window size.
- 5.0-8199 - General housekeeping. Fixes duplicate options, memcard manager blocks remaining not immediately updating and more.
- 5.0-8251 - Fix gamelist column resizing issues. Resizing the various gamelist columns in Qt actually works as intended now.
- 5.0-8271 - Add ability to create a memcard if one does not exist when selecting a memory card file.
- 5.0-8273 - Add multi-select feature to gamelist. Select and do actions on multiple games in the gamelist, such as compress/uncompress.
- 5.0-8291 - Fix address search focus issues.
- 5.0-8303 - Reduce startup time by changing how the graphics window is initialized.
- 5.0-8311 - Reduce startup time by changing how the hotkey configuration window is initialized.
You may note that some of these features were merged after the cut-off for the Progress Report. When DolphinWx was dropped, there was a wave of (valid) complaints about why they were hesitant to move over to Qt. And the ones we mentioned here are just the beginning - there have been hundreds of Qt changes over the past couple of months that didn't make it into the Progress Report as various minor issues were chipped away. Adding to that is that there are even more on the docket to come forward fixing some edge-cases and features that aren't as commonly used.
5.0-8009 - JIT64: Fix and Enable Accurate Double2Single Conversion by JMC47, degasus, and phire¶
This writeup originally had some errors in what was happening that have since been corrected.
This is a bug report that would have never reached Dolphin had it not been for some incredibly devoted Super Mario 64 players hunting for their white whale - a run without pressing the A button. For this task, they've investigated every single avenue, including Nintendo's various ports of the game. This isn't the first time the Virtual Console version of Super Mario 64 has come into play, as there were previous strategies that relied on differences present in Nintendo's Wii N64 emulator. But no one expected to find the key to completing a 70 Star zero A button press run. How exactly did we get to this point?
Super Mario 64's A Button Challenge¶
One of the more interesting uses for emulators are TASes (Tool Assisted Speedrun). While most of these superplays are actually speedruns, several groups have taken toward completely crazy goals in some of our favorite games. The Legend of Zelda: Ocarina of Time recently had its "No Doors" challenge completed and many fighting games have glitch exhibitions that would drop the jaws of casual observers. One particular group of Super Mario 64 TASers has taken up the task of completing Super Mario 64 in as few A presses as possible. Considering that the A button is used for jumping, this challenge has become legendary for producing crazy solutions to once simple platforming problems. In their endeavors, they have warped time itself and explored parallel universes all in the name of saving single A presses. Some of the most popular videos have over a million views as the challenge has captured the hearts of gamers around the world.
How exactly did Dolphin get dragged into this? It all started one night when a video was linked to the team of a new glitch discovered in the Virtual Console version of Super Mario 64 that would potentially allow them to bypass that final A press. This bug was a bit peculiar - it only happened in the Wii version of the game. Not the Wii U, not the N64, only Wii. So when people showed up saying that Dolphin didn't emulate the bug, of course it drew some interest.
Floating Up to Zero¶
Within Bowser in the Fire Sea, a certain type of platform would float up and down in the lava presenting Mario a challenge to cross it without getting burned. On the Nintendo 64, these platforms worked as expected floating up and down as one would expect. On the Nintendo Wii, however, the platforms would slowly oscillate toward the origin (0,0,0). Because Bowser in the Fire Sea was a level with vertical progression, the origin was actually above where the player spawned. That meant the bottom level of platforms would very slowly drift upwards during their oscillations. If you were to wait 3 days for the platform to rise, you could combine that with Vertical Speed Conservation from a lava boost and punch your way to the next part of the level!
This behavior didn't happen in Dolphin! After hearing someone say that Dolphin wouldn't ever be able to emulate the feature, JMC47 dove into the issue head first. He quickly came up with a test and within hours had Dolphin reproducing the bug just fine while falling back on several instruction sets. After another day of testing, he had narrowed it down to an issue with converting Doubles to Singles.
Our readers that love our technical pieces are going to be happy, since we can't pull any punches with this one!
To really understand this glitch and the solution, you'll need to understand a bit about Floating Point Math. Floating Point is basically a speed hack for mathematics, akin to Significant Figures. It essentially trades accuracy for speed through controlled rounding. The "controlled" part is how far the decimal point goes before it is rounded; that is precision of the floating point calculation. For example, "Doubles" (Double Precision Floating Point, 64-bit) has both higher precision (more decimal places) and range (larger min and max values) than "Singles" (Single Precision Floating Point, 32-bit). This all may seem counter intuitive, but Floating Point allows efficient calculation at the scale of the universe or size of an atom level numbers. Of course, the tradeoff for that imprecision is the potential for rounding errors. For a full and proper explanation of Floating Point and how it is computed, please see this excellent video on the topic.
This is a rather tough problem that requires a deeper look at Super Mario 64. All objects in the game are tracked via floating point numbers, and move via floating point calculations, but weirdly enough the calculation for the platform is initially performed in Doubles, and then converted to Singles. We have no idea why it does this instead of just using Singles, but it does! Looking at the actual problem on the Wii, the platform itself is only supposed to move up and down in a sine wave to imply that it is floating in lava. That's where floating point imprecisions sneak in - it has a very small chance that the new start position after a loop will be slightly higher than the previous loop, causing the platform to very slowly rise up over time. On the N64, the processor is set to Round to Nearest which prevents the platform from ever leaving its intended area. Our initial assumption was that, for some reason, the emulator was setting the wrong rounding mode, causing those floating point imprecisions to now matter and Dolphin, for some reason, wasn't respecting the rounding mode correctly.
But as we investigated the issue, things didn't line up. The Wii VC version was already correctly setting the Wii CPU to Round to Nearest which meant it should produce the correct results. In fact, we already knew that it did produce the correct results when running on Dolphin! But wait a second, then why was the Wii VC version rounding differently on Wii???
That's where things got even more confusing and we had to dig into the behaviors of the Wii's Floating Point Registers (FPR). A PowerPC FPR can store either a single or a double. If you write a single to an FPR, you can still read it back later as a single or a double, and the CPU will automatically convert it to double precision if necessary. But what about doing the opposite? What if you stored a double to a FPR and then read it back as a single? Well, that's actually not allowed according to documentation and marked as undefined behavior. How this slipped in is unclear, but the most likely this is just how the original game did things, and the bug didn't manifest on the N64 processor due to different rounding behaviors. Unfortunately for them, this undefined behavior results in a conversion that is almost correct, but not correctly rounded on the Wii CPU. In particular, the lower bits of the mantissa are simply discarded. This is effectively the same as rounding toward zero, which is why we initially suspected the wrong rounding mode was being used.
Figuring out all of this on hardware would have been tricky. Once we knew it had to do with Double to Single, writing a hardware test would have been trivial, but getting to that point would not have been. Thankfully, we didn't have to - Dolphin's interpreter already emulated this correctly, which let us compare the JIT instructions to the interpreter instructions without needing to even check on a physical Wii. This gave us a lead and we were able to narrow the difference down to the slow-path for performing Double to Single floating point conversions. The main difference between the fast path and the slow-path was that the fast-path more or less skipped the guts of the conversions and just did things correctly - which isn't what we wanted in this case. A fast-path's job is to do things as correctly as possible without doing anything that would massively slow-down performance. A lot of the time, this means doing what you think the game wants to do, but skipping most of the steps to get there. Dolphin has a lot of optimizations that work by doing things in more optimal ways that might not produce the same results on extreme edge-cases, but work correctly 99% of the time. That was the case for Dolphin's fast-path for Double to Single Conversion. Rather than doing the process, it would just round based on the set rounding mode during conversion!
So what was essentially rounding to zero on hardware, would round to nearest in Dolphin! This was correct behavior in terms of what Super Mario 64 wanted, but not in what the Wii was actually doing. But it's our job to be a Wii emulator, so everyone jumped into action to make sure we emulated this weird CPU behavior to ensure that Dolphin was as accurate of a reference as possible. JMC47 verified that the fast-path was responsible for this inaccuracy, and discussed the issue with the team. His way of fixing it was disabling the instruction in the JIT so that Dolphin would fallback to the slow-path version of the instruction implemented in the interpreter, which didn't have this flaw. degasus and others on the team realized there was a better way of doing this - phire had already written a software-based Doubles to Singles conversion for the JIT many years ago. Because it was disabled and thought to have no real impact on any games, it had fallen into disrepair in recent years so it couldn't just be enabled. Instead, degasus repaired phire's code to work in modern Dolphin and JMC47 did his own test and passed it around for others to verify.
And just like that, the platform finally behaved correctly in Dolphin with the JIT!
With phire's repaired code proving to be more accurate, it replaced the previously active fast-path in Dolphin. The performance difference was so minor within games that there was no visible change in framerate! Despite making a difference in Super Mario 64, no one should expect any major differences in other games. This case was a very strange one that no one could have anticipated! On a final note, if you're curious how the finished run would look, the TASers have hacked the glitch into the version of Mupen64 they use for TASing in order to demonstrate how the level would be completed without a single A press.
Much like some previous Virtual Console only strategies, it's possible in the future they'll find a way to get past this blockade on Nintendo 64. Regardless of if they do or not, their efforts have helped make Dolphin a little bit better. And for that, we thank them.
Over the past month or so, we've gotten a lot of reports on Twitter of what Discord thinks of Dolphin.
Unfortunately, Dolphin is not an Atari game. Discord has been made aware of this and will hopefully address it on their own for our 5.0 users, but yourWaifu came onto the scene to address it in our own way! By using Discord Rich Presence, we can directly tell Discord what we are and have it display in Discord users status messages. But we can do even more, and show precisely which game they are playing in Dolphin!
For users that do not want to show what game they are playing, this feature can be disabled directly in the emulator, or you can just disable the playing a game option entirely in Discord itself.
Note: Disabling the "Display currently running game as a status message" option within Discord will not stop it from recording what games you're playing, only displaying it for others to see. The only way to keep the information away from Discord is to disable it in Dolphin. Or turn off Discord.
A few months ago, Dolphin was given the ability to examine a game's mipmaps to see if they were being used simply as downscaled textures or if they had been edited for a graphical effect. After the merge, we discovered that a lot of Nintendo's first party titles used mipmaps for effects, such as The Legend of Zelda: The Wind Waker, The Legend of Zelda: Twilight Princess, Super Mario Sunshine, Super Mario Galaxy and Super Mario Galaxy 2.
In those games, the new feature worked as anticipated. Dolphin detected when games were using mipmaps in order to perform special effects, but would otherwise scale how far out higher resolution textures/mipmaps are used based on internal resolution. This was great when it worked and allowed those games to render more more closely as they did to console on Dolphin even at higher resolutions. Unfortunately, that wasn't the case for every game.
Skies of Arcadia Legends and many of it's Sega brethren completely fool Dolphin's mipmap heuristic. This is because they use DXT compression on extremely small mipmaps of textures, adding enough noise that the heuristic thinks it is a mipmap effect. The result is that Dolphin determines that it has to show the mipmaps at the correct distances to preserve a special effect that isn't there, making things blurrier for no reason. Unfortunately, there isn't much that can be done about this other than giving users the ability to disable the option if a game manages to fool the heuristic in this manner.
Another serious issue was discovered when a bug report struck that Metroid Prime Trilogy was stuttering upon loading rooms. After going through the typical culprits, testers narrowed it down to the fact that enabling GPU Texture Decoding fixed their stutter. Additional information from the bug report (including a bisect) centered around the mipmap heuristic! It turns out that Metroid Prime 3 streams enough large textures in rapid succession that it can bottleneck Dolphin on the mipmap heuristic! After all the work that was done to make shader compilation stuttering disappear, no one was thrilled to see a new stuttering bug. While disabling the heuristic will alleviate the extra stuttering, developers also greatly optimized the heuristic so that it wouldn't cause slowdowns in the games that needed it.
As you can see, even with the new optimizations, Metroid Prime 3's nightmare case is still slightly slower than with the arbitrary mipmap detection disabled. While the feature can be optimized further, please keep this in mind when enabling it for games with heavy texture streaming. Going forward, it is likely that Dolphin will be getting some game INI changes that will disable the heuristic in games where it's known to cause issues. The long-term goal is that it will become a silent feature that users don't have to worry about, but until all the kinks are worked out, the best compromise is to simply give users the power to decide if they want to use it or not.