This year, we've hit an important milestone that's been in the works for nearly a decade. In late 2012, Sonicadvance1 began work on Dolphin's ARM JIT. Back then, there weren't any devices that had even a sliver of hope of running Dolphin close to full speed, but that wasn't really the goal. All he wanted to do was see if it could be done; it sounded like a fun, challenging project. However, as time passed the idea turned into more than just a passing curiosity. Users were more than happy to donate to cover the hardware cost of staying on the bleeding edge of a rapidly evolving ecosystem, allowing ARM development to flourish. By 2015, Sonicadvance1 astounded developers and the community alike with footage of Mario Kart: Double Dash!!'s time trial mode running close to full speed.
On that note, we're happy to announce that Dolphin's AArch64 JIT has finally reached feature parity with Dolphin's x86-64 JIT. This means that every PowerPC instruction that the x86-64 JIT supports along with every major JIT feature are now supported in the AArch64 JIT! And this is a great time for ARM in general, with each generation of processor pushing the boundaries and companies like Apple adopting the architecture for larger and higher power devices like their M1 Mac line. For those on mobile phones and tablets, Adreno powered devices provide decent enough graphics drivers to get a reasonable experience at this point. And with a critical bottleneck getting fixed just days ago, performance on Adreno GPUs has skyrocketed. You won't have to scroll far for that news, we promise.
But that's only the tip of the iceberg; we've had three months worth of changes pile up and some other important infrastructure news. We've improved the user experience on macOS significantly and restored support for older devices. In fact, enough has happened that we'll be detailing the status of Dolphin's macOS support near the end of the report.
And... we haven't even talked about any emulation fixes yet. The past three months have had tons of changes that would have normally been the highlight of a Progress Report. The three month gap between reports was not because of a lack of changes. Want to take Riivolution games on netplay? You can. Hate the EA VP6 bugs? Make them a thing of the past with a new option. Wish your favorite LogicOp game worked on GLES or MoltenVK? Odds are, it does now! The list goes on, but outlining everything would take way too long, so let's just dive in. Please enjoy the November, December, and January Progress Report!
5.0-15952 - Disable Primitive Restart on Adreno by The Dolphin Android Users¶
As stated in the title of this change, credit for this discovery can't go to any single developer or tester. This change happened because of the greater Android community that spends way too much time trying to get the very most out of their mobile devices. Over the past four years, Dolphin has gotten a lot of optimizations, fixes, and tons of quality of life features. Yet, despite everything a lot of users would swear by old forks and some have taken up the mantle of trying to retrofit them with modern features. Why go through all of that effort? Performance!
Unfortunately, these forks are often just personal endeavors with messy histories, sometimes incoherent changelogs, and some of them don't provide the source code at all (which is illegal, don't do that). Some users swear by these forks, and we could never know why because there isn't a good way to see how they are different. Yet one thing was for sure: numbers didn't lie, and users said that these old forks allowed their GPUs to run at much higher resolutions than the latest builds, even if it meant losing out on game compatibility and some CPU optimizations. No matter what we did, we couldn't bridge the gap, at least on the Snapdragon line of devices.
And now we know why.
Near the end of January, Gamer64ytb reported that the difference had finally been found. One of the changes in the old fork was removing an optimization called "Primitive Restart." In fact, the original creator of that fork, weihouya, tried to upstream this change to master, but their inexperience with contributing to Open Source projects, and a language barrier, left us with a rather messy change that had no reported benefits, it was simply because they didn't like the additional complexity Primitive Restart created. Testing of the time didn't reveal any conclusive benefits, yet it caused issues with Vulkan on Android, so Dolphin's developers declined to merge the change. However weihouya pushed it into their fork anyway and fixed Vulkan separately. And that is what set this all into motion.
Primitive restart functionality allows you to tell OpenGL that a particular index value means, not to source a vertex at that index, but to begin a new Primitive of the same type with the next vertex
On the surface, Primitive Restart should be a safe performance benefit. It allows Dolphin to reduce draw calls by merging primitives together. In fact, some GameCube/Wii games natively use Primitive Restart! Unfortunately, Primitive Restart being faster requires the GPU driver to handle things efficiently, and in the case of Adreno that simply was not happening. In fact, it had such a huge overhead, that it became the single biggest bottleneck while using the driver. And profiling the Adreno driver isn't all that simple, so we didn't have a very good way to even see that this was a problem. It was only after Gamer64ytb reached out to us about this discovery that we were able to go through and analyze things for ourselves.
The chart paints a very clear picture. This is one of the biggest across-the-board performance boosts we've seen in a very long time. This affects all supported Adreno devices, and should speed up Dolphin in any GPU limited situation. On mobile, this is most games, especially beyond 1x internal resolution. According to users and our personal tests, sometimes you'll see games that were lagging at 2x Internal Resolution now able to run at 4x Internal Resolution full speed! If you have an Adreno device and haven't tried Dolphin in a while, now's your chance. You might be pretty happy with the increased performance, along with all of the other changes that have brought compatibility roughly in line with that of desktop versions of Dolphin.
Unfortunately, disabling Primitive Restart is not a magic bullet for literally everything. Low-end Adreno devices with extremely weak CPUs aren't going to see a huge benefit. If you're not able to run a game at native resolution, odds are this won't help you. As well, Mali and Mediatek gain no benefit from disabling Primitive Restart. And on the Desktop side of things, as expected using Primitive Restart is slightly faster on NVIDIA devices and was already disabled on some AMD drivers and backends. This change and the performance implications only affect Adreno/Snapdragon devices. It's just that Adreno/Snapdragon devices also make up some of the best mobile devices that you can run Dolphin on currently.
Dolphin's AArch64 JIT has been highly capable the last few years, but as we've repeatedly noted, there were a few features missing here and there that caused it to be slower in certain titles. The biggest of those was the lack of MMU support.
The MMU is a part of the GameCube's CPU. Credit: Wikimedia user ZyMOS / CC by-SA 4.0
On the GameCube and Wii, rather than directly accessing available RAM, games interface with virtual memory which is then translated to physical memory by the Memory Management Unit (MMU). The MMU is programmable and gives games a wide array of options for manipulating virtual memory. Fortunately, to our benefit, most games didn't bother to take advantage of that feature and just used the default memory mappings of the MMU. As such, for the vast majority of games Dolphin can just directly translate the virtual memory to host memory, which is simple and speedy. However, a few impressive games did decide to go beyond the default mappings and write their own custom exception handlers to allow themselves to move things around in memory wherever they wanted. Star Wars: The Clone Wars even changed the Block Address Translations mid-game! Any game that takes advantage of the MMU requires Dolphin to slow down and pay attention so it can emulate all of these behaviors, creating a significant bottleneck on CPU emulation. While it will never be cheap, Dolphin's x86-64 JIT does everything it can to make this as fast as possible.
The AArch64 JIT completely lacked MMU support, forcing all of these instructions to be run through the interpreter instead. This meant that one of our most intensive emulation tasks was being run through our compatibility-focused interpreter, on power limited hardware! For games like Rogue Squadron 2, Rogue Squadron 3, and Spider-Man 2 to ever approach fullspeed on AArch64 devices, MMU supported needed to be implemented in the AArch64 JIT. This change essentially proves that, with huge performance gains across all MMU titles. Now that dream of running some of these games full speed on your favorite ARM devices isn't so far-fetched.
Note that this is an M1 Max, the most powerful AArch64 device on the market, and even it can't run Rogue Squadron 3 at full speed. This is because MMU titles are still much more demanding in general, and that particular game does everything that's hard to emulate. Still, all MMU games perform better and normal MMU titles may even be able to run full speed on high-end AArch64 devices.
If your raw performance is fine, the next thing most users want is for things to run as smoothly as possible. And that's where Codegen Space Reuse comes in. By marking spaces of invalidated code as reuseable, Dolphin can minimize costly JIT cache flushes and keep your game running smoothly, even when it's generating dynamic code. This feature has been present in Dolphin's x86-64 JIT for over a year, but now JosJuice has ported the feature over to the AArch64 JIT.
Overall, this is a targeted optimization that only targets certain games. Probably the most popular game that used to suffer from this issue was Metroid Prime and the other games on that engine. Nintendo 64 Virtual Console games have their very own JIT, so they generate tons of code and would hitch constantly before as the cache would get flushed once or twice every five minutes, but now will only require cache flushes every thirty minutes or so on average. And of course, we can't forget the memory management nightmare that is True Crime: New York City which used to do... this...
These issues are entirely resolved in most cases, and greatly reduced in the most extreme cases with Codegen Space Reuse. In most of the library, you should never see a JIT Cache Flush under normal play.
As a small aside, shortly after this feature was merged, users reported severe performance issues in a few select games, including Harry Potter and the Prisoner of Azkaban and F1 2002. This was due to some minor JIT implementation differences between the x86-64 JIT and the AArch64 JIT, and were quickly rectified by modifying the AArch64 JIT cache to take into account some differences in how certain instructions are handled.
The EA Sports Active games were EA's response to the Wii Fitness game craze. Despite having other franchises on the Wii such as Madden NFL, FIFA, Need For Speed and many, many others... according to Wikipedia, EA Sports Active is EA's top selling Wii game. Seriously. It was so popular that they made four EA Sports Active titles, including one that leveraged their NFL license.
Despite seeming like nothing more than simple exercise games, users trying to run the original EA Sports Active in Dolphin would find that things weren't exactly looking like they remembered.
This bug was reported in 2013, but was accidentally swept under the rug because EA Sports Active: More Workouts, EA Sports Active 2, and EA Sports Active: NFL Training Camp didn't suffer from this issue and their naming scheme was less than clear. Because of that, it was mistakenly marked as a duplicate of the more typical "VP6" video bug when there was actually a unique issue present only in the original game!
To what has seemingly become Pokechu22's specialty, they decided to investigate this bug in almost too much detail. If you care about exactly what was going on, what the developers were likely thinking, and exactly how the game renders, check out Pokechu22's writeup. For now, we'll just go into the basics.
This game uses the GameCube and Wii hardware feature "Copy Filter". While copying a rendered frame from the Embedded Frame Buffer (EFB) to main memory, the hardware can for free do some very basic effects to each line of the image. This can be used to blur the image slightly, such as the "Deflicker" filters in the Super Smash Bros. series, or to brighten/darken the image, as used in fade-out transitions in Rogue Squadron 2 or gamma adjustments in Metroid Prime. This is a non-programmable hardware feature, so after we implemented it a few years ago, we were confident that we had seen the last of Copy Filter related issues. However, we made a bit of an assumption that would come to bite us later.
With EA Sports Active, Pokechu22 discovered yet another clever use of the Copy Filter - Color Filtering! Thanks to their research, we can actually get a look at what the game looks like before and after the Copy Filter... filtering.
So how was EA Sports Active actually accomplishing this and what exactly were they doing? The game was making two different EFB copies for each frame. The first copy is configured to take the red and green channels of the image, and then the second copy takes the blue channel and uses the Copy Filter to take 1/16th the value of the current line. By separating the values out like this, the game is able to do some custom color/alpha blending to create more contrasty scenes with crisper colors.
When implementing the Copy Filter, we noticed that every known use of the Copy Filter was being done exclusively to XFB Copies, a special type of EFB Copy where the frame is moved to a specific region of Main Memory designated for scanout. So we assumed that copy filter effects could only be used for XFB Copies, and excluded standard EFB Copies from the Copy Filter entirely. EA Sports Active proved us wrong. By merely allowing EFB Copies to go through the Copy Filter, a trivial change, Pokechu22 corrected the issue and now EA Sports Active's custom color shenanigans all work as intended.
Surprisingly enough, after submitting the fix we found out that EA Sports Active isn't the only game that uses Color Filtering like this! The Last Airbender, based on the hit movie that Avatar fans love to bring up, used similar color filtering system, just with a much less interesting color palette.
As with any major change to emulation, adding this did cause a few minor issues here and there. Thankfully, the regressions were found and sorted out 5.0-15518. And then a few more were discovered and addressed in 5.0-15950. And one of our debug features was also broken and finally addressed in 5.0-15961.
Unfortunately there appears to still be a few quibbles to sort out. While working on this Progress Report, we noticed something was a little off about one of the characters and confirmed it does not occur on console.
If you want to see more details on this issue, please read Pokechu22's writeup on this bug. It goes into a depth that we could never manage in a Progress Report!
Fixing the discoloration of EA Sports Active was a win, but unfortunately there was still another problem that affected it and over one hundred other games. The breadth of games was huge, from EA's own sports titles, to the James Bond series, various Harry Potter games, several Need for Speed games, the eternal Just Dance series, and even strange outliers like Target: Terror. Odds are if you had a sizeable library of games, you probably had at least one that was affected by this bug... if you had certain hardware.
There are probably some readers scratching their head right now. It's very possible you've played many of the games we've mentioned and never noticed any kind of defect like this. That's because this primarily affected NVIDIA GPUs. There are exceptions, but if you haven't been using a NVIDIA GPU, odds are you haven't seen these issues. AMD graphics card users were almost entirely unaffected, and so were most phone and tablet users since Adreno and Mali are did not exhibit this bug.
That's because this is entirely due to texture sampling quirks. Texture sampling is the act of reading texture data (its color data, texture coordinates, etc) as well as texture filtering. As this is a feature that is going to be used, in scientific terminology, a bajillion times per frame, it needs to be extremely fast, so even the latest GPUs use fixed function hardware to accelerate this task. However, not all GPUs sample textures in the same way, but usually the differences from this are so small that they are limited to subpixel quirks.
The afflicted videos are comprised of many tiny and large textures that are combined together to build each frame of the video; a video that doesn't match the resolution the game is using. This already creates MANY opportunities for interpolation differences to crop up, but these video codecs takes things even further. The videos actually have color data from one texture produce an offset to the texture coordinates that are used when reading a second texture. This leads to cascading rounding errors, where even the tiniest differences can explode into view. We understand why they are doing this, but it makes these videos extremely fragile and they require extreme precision to reproduce accurately. In fact, if you look at the Bink Video changelog from this era, you can see them struggling with this on real consoles.
Why are some graphics cards unaffected? While we're not 100% sure, we can at least give some conjecture to why AMD based cards aren't affected. The GameCube and Wii have ArtX graphics processors inside of them, a company that was absorbed by and became ATi and then was later purchased by AMD. It appears as though texture sampling behaviors haven't changed since the days of the GameCube, so these issues don't appear on their modern hardware. This also extends to our Adreno users, as their hardware traces their roots right back to ArtX as well.
Unfortunately for Nvidia users, they had no such luck. They would see the visual issues in VP5, VP6, and Bink videos that used these techniques. Worse yet, the issue actually can extend to cases outside of FMVs, such as the text boxes in Mario Party 7 or the video gameplay elements in Target: Terror which uses multiple Bink Videos for animated sprites to emulate the look of a classic arcade shooter!
For all this time, Nvidia users have simply had to deal with these issues. Since this is tied to low level GPU hardware differences, how are we supposed fix this for them? Well, we just had to stop relying on the offending bit of the GPU's hardware and do texture sampling ourselves!
Note: The Open Source "RADV" drivers for AMD graphics cards do show the sampling bugs. While Texture Sampling is handled by low-level GPU hardware, it's entirely possible for the GPU driver to affect how that low-level hardware functions. Oddly enough, the RADV driver's defects in these situations look slightly different than the defects on every other graphics card, with the vertical lines looking more like they are made up of dots.
Sorting Through Sampling¶
For the most part, Dolphin didn't do anything all that strange when sampling a texture. Outside of the shader, Dolphin would tell its graphics backend what to do while sampling the texture, such as linear sampling, mip mapping, wrap horizontally, wrap vertically, etc, all based on the situation. Regardless of orders sent, the shader then calls upon the fixed-function GPU hardware to sample that texture with the selected settings. Given that this wouldn't work for every GPU in every situation, a new solution had to be devised. What Pokechu22 decided to do was to create a way to manually sample the texture instead of relying on the graphics card's texture sampling unit. While it was a fair bit more work and we were concerned about performance, Dolphin itself could read and filter the texture manually in order to ensure results were consistent and correct to precisely what we needed. From there, the shader can look at the texture configuration and find out about other nearby coordinates, mipmap levels, and more with greater accuracy.
The experiment was a huge success right away, but there was a ton of work that had to be done to support literally everything that Dolphin could do. It took literal months to work through everything, but the greater level of control meant that Dolphin could also start emulating some of the stranger behaviors of texture handling of the GameCube and Wii. Most of those cases do not usually occur in retail games, but sometimes happen in mods and homebrew tested in Dolphin. One example of this was when a developer of the Star Fox Adventures: Amethyst Edition reported that textures that worked fine in Dolphin were broken on console. However, with Manual Texture sampling, we have the ability to make these textures behave accurately without forcing people to use the software renderer. If you use Manual Texture Sampling at 1x Native Internal Resolution with Load Custom Textures disabled, you can now catch problems with irregular textures that would have rendered fine otherwise.
For those that want the most accurate picture possible, Pokechu22 has also added support for diagonal level of detail, which allows for more accurate selection of the correct texture mipmap if the game chooses to use it. This results in very minor differences that are only evident if you're directly comparing side by side with an identical screenshot from console. All of these cool features and fixes comes with no known regressions at this time, making it a rather safe option to try if you're interested in seeing if an annoying graphical issue is related to texture sampling! Just note that the enhancement "Anisotropic Filtering" is currently not implemented in Manual Texture Sampling, so that feature does nothing when Manual Texture Sampling is enabled.
We've talked about having higher accuracy, better picture quality, and less reliance on GPU quirks without any visual regressions. But we haven't talked too much about performance. Since we are bypassing dedicated hardware meant to make texture sampling as fast as possible, a performance hit was inevitable. However, the story is actually rather complicated - how Manual Texture Sampling behaves depends on your GPU's architecture and raw computing power, as well as the resolution you wish to play at. At lower resolutions, i.e. 1-2x Native Internal Resolution, there isn't much of a bottleneck at all. In fact, some games actually run faster on certain hardware. However this will change at a certain resolution, usually around 3-4x Native depending on your GPU, and it becomes a noticeable performance bottleneck.
Tip: You can hide or reveal items by clicking/tapping them in the legend.
If you have an absolute powerhouse GPU, odds are the performance impact won't affect you until you're at a resolution beyond reasonable. Those of us on more modest hardware are hit a bit harder. And those on older GPU architectures that are more sensitive to this, such as Pascal, are hit even harder. Considering that this only impacts certain hardware and can have a sizeable performance impact depending on your resolution and GPU architecture, we've mostly left this option disabled for now. In a few low impact games that heavily rely on FMVs (e.g. Just Dance) we have decided to enable it by default, as they aren't GPU limited in general and see almost no benefit from higher resolution. If every graphics card were affected, the decision of when to enable this would be a lot easier, but that's just not the case.
Eventually, we may need to come up with a conditional default, depending on the user's hardware, much like a driver details bug, but this time handled per-game. For now, if you have an afflicted card, "Manual Texture Sampling" resides in the "Advanced" area of the Graphics Settings Menu. If you enable Manual Texture Sampling, Dolphin will then Manually Sample Textures along with enabling all of those other accuracy bonuses. Our current plans are to find games that have heavy glitches with "Fast Texture Sampling" to the point that they are unplayable, and slowly enable Manual Texture Sampling on a case by case basis. Unfortunately, this does mean that some users with Graphics Cards/Drivers that did not have the error may have the setting enabled despite not really needing it. We'll continue to try to make smart decisions when to enable this feature, especially as we get more data on what games it effects and how it performs on all the vast variety of machines that our users play Dolphin on.
5.0-15520 and 5.0-15604 - Riivolution Fixes, Additions, and Netplay Support by AdmiralCurtiss¶
When Dolphin added High Level Emulation (HLE) for launching and configuring Riivolution mods, users quickly embraced the feature and we saw a huge influx of both appreciation and support requests. The initial implementation was fairly good, but there was no way we could test every mod and find every edge-case. Over the past three months, AdmiralCurtiss has been busy fixing Riivolution mods that didn't run on Dolphin and adding a few much requested features. Most of these bugs were very silly, and had to with things like "case sensitivity" of filenames and paths, duplicate files in the mod, and were mostly centralized to haphazardly constructed mods.
On the side of new features, AdmiralCurtiss has brought some big hitters to the table. First of all, you can now create Game list Entries for Riivolution mods, letting you boot preconfigured mods directly from your game list!
This may not seem like a huge deal at first, but this was one of the major requirements for booting Riivolution mods on Netplay! Once a Riivolution configuration is in your game list, you can use it for netplay. As long as all players in the netplay session have the Riivolution mod configured correctly, it'll work like any other game on netplay.
Note: Wii Remote Netplay is still experimental, and only works with Emulated Wii Remotes. Even then, some actions, such as Wii Remotes disconnecting, may not behave properly on netplay and improperly configured netplay sessions may hang on boot. Riivolution Mods for GameCube games and Wii games that support GameCube controllers are much easier to setup and synchronize properly.
Note 2: If you are planning on using Wii Netplay, please use revision 5.0-15559 or newer for reasons that we'll get to... right now!
5.0-15549 and 5.0-15559 - Netplay Shutdown and Wii Save Fixes by AdmiralCurtiss¶
After all of these years, Wii Netplay is still in a rather experimental state. There are a lot of challenges surrounding it, such as the Wii's internal memory, system files, and of course, those pesky Wii Remotes. Dolphin's netplay infrastructure was designed before the idea of taking Wii games onto netplay was even considered a possibility, so a lot of Dolphin's Wii netplay are tacked on top of an aging foundation. Syncing memory cards is one thing, but how do you synchronize a NAND that can be 500 MB and can contain copyrighted data? Well, that's actually the crux of a lot of bugs on Wii Netplay - synchronizing the NAND.
In order to avoid both legal and bandwidth issues, Dolphin sets up a "Blank" NAND for netplay, and then imports the necessary savefiles for the games the users want to play on netplay. This keeps the footprint small and avoids all the legal issues. When Netplay is over, these files are then exported back to the original NAND if the user has turned on "write saves"... which is actually where a nasty problem cropped up, one that could actually affect your actual NAND's save.
Due to an unfortunate race condition, mixed with Wii Remotes' propensity to want to crash Netplay in general, it was possible for the original save to be lost during the export process due to a race condition. While cleaning up part of the codebase for Riivolution games to function on netplay, AdmiralCurtiss noticed a bunch of these problems and found himself unable to figure out how the code was actually supposed to work. This may sound outrageous, but it's a fairly common occurence when you dive into the older parts of a project that has had this long of a lifespan. The only option at that point was to rewrite and fix up the code to at least make it work again. As it was, it seemed like Dolphin's Netplay was making assumptions that were no longer true due to changes in other parts of the codebase.
The save loss bug is fixed to the best of our knowledge in the latest builds, meaning it should be safe to take your saves on netplay again. Your original save from your real NAND should never get lost again. However, if Dolphin crashes during netplay, the updates to save files done during netplay will not exported to the main NAND. Do not panic if this happens! Your save data from the netplay session can still be retrieved in a Wii.backup folder contained in Dolphin's user files and manually converted. Do note that starting Dolphin and booting up another game will clear these files.
Most of the time, Single Core is Dolphin's accuracy option that helps with most random crashes and hangs. But in a few rare games, Dual Core is actually the more stable option. One of those games is Bomberman Jetters, and the reason why is pretty interesting.
One thing to note is that the GameCube and Wii are single core consoles, so there's only a limited amount of things we can try to parallelize from the main workload. However, early Dolphin developers realized that the GPU-related CPU work, such as sending graphics data and the like, was reasonably safe to split into a second host CPU core. After all, the CPU side of things doesn't interact with the GPU-related CPU work all that often. This meant they could run in parallel on separate host CPU cores for a time and only sync up at important moments (such as specific interrupts) in order to greatly improve performance. While today we know of Dual Core as the source of many random crashes, when it was initially implemented Dual Core mode wasn't as problematic as it is nowadays; usually the GPU thread was more than fast enough to keep up and users were always limited by the CPU thread. Ever since TEV_Fixes_New Dolphin's performance profile has flipped, with the CPU thread now actually being faster where as the GPU thread has a lot more to do thanks to improved emulation.
This creates a scenario where the CPU thread may run too far ahead of the GPU thread, and if the GPU thread is too far behind when an interrupt happens, you may run into synchronization issues. There's not much we can do about this problem - the reason why Dual Core is fast is because the threads run without much syncing. If we add more syncing to fix the crashes, performance would drop. Besides, at this point Single Core has been optimized pretty well and on a lot of computers works well enough without any of the risks. It's a properly deterministic option for when a game is problematic on Dual Core.
Bomberman Jetters is one of the games where Dual Core's lack of synchronization is actually a good thing. This game expects GPU FIFO processing to take time. In Dual Core, this happens out of pure happenstance because the CPU thread and the GPU thread only meet up once in a while. Single Core executes everything exactly in order on a single thread with no delays whatsoever. Worse yet, the execution time would be backdated to when the FIFO command was first sent, meaning that zero time had passed since the game issued the command!
Rather than trying to emulate the whole pipeline correctly, phire came up with a little bit of a hotfix that makes FIFO execution a bit closer to correct on Single Core. With this change, FIFO execution is fed through an interrupt scheduler that can delay and make sure interrupts happen at the right time. Here, we just force a minimum wait time so that those interrupts that were happening instantly now happen a tiny bit into the future from when they were issued. It doesn't exactly address the core issue, but it's good enough to get the game booting. Unfortunately, this game is still prone to random hangs even with the initial hang fixed. But the good news is that there is a work-around now - lowering the emulated CPU clock by a small amount significantly (perhaps completely) reduces the likelihood of the game hanging.
This also affects some Datel Products and Resident Evil 3 when running in Single Core, preventing game breaking hangs from happening. This is important because these Datel Products were actually broken on Dual Core too, so having them working at all is rather nice. Resident Evil 3 is kind of in-between. It works on Dual Core, but depending on your device, there's a very small chance of hanging if things go wrong in just the right way. In our limited testing, we were unable to cause any hangs at all in Resident Evil 3, but some transitions appear to take an abnormally long time, including the initial first door where the game was hanging previously. If this issue is similar to Bomberman Jetters, it's likely that slightly reducing the Emulated CPU Clock would smooth out any remaining issues if there are any.
Some users and developers love using the Wii Menu (commonly referred to as the System Menu). It's a lot of fun to go through some of the channels and see various animated game banners that aren't shown from the typical Dolphin GUI. However, if you boot a game and then return to the Wii Menu, the game you were playing wouldn't be present in the Disc Channel. This is because Dolphin was clearing RTC (Real Time Clock) flags on reset, so the emulated console didn't know that it should update the Wii Menu's cache and refresh the inserted disc, leading to stale data being used. Pokechu22 made a quick correction to this behavior, so that the correct disc appears in the disc channel after reset.
This is a workaround for missing LogicOps support in Metal (MoltenVK) and the many mobile drivers (Adreno, Mali, etc.) that do not support the OpenGLES and Vulkan extension. However, this time around, we're not trading one broken game for another; OatmealDome has taken advantage of an improving situation on Android alongside a small hack to MoltenVK to get correct output in LogicOps titles on the afflicted devices.
While OatmealDome is best known for working on Apple features, including a fork of Dolphin designed to run on iOS devices, they've also taken over the burden of helping maintain Dolphin's macOS builds. They've submitted fixes for MoltenVK, helped update the buildbot, and have generally improved the macOS user experience. In this case, they wanted to fix LogicOps features on MoltenVK, but then stumbled into the fact that OpenGLES environments (Android on Non-NVIDIA) suffer from the same problem. A while back, Stenzek added LogicOps approximation through blending to fix Mario Kart Wii on Windows 7 D3D11 and OpenGLES devices.
Unfortunately, restoring some remedial emulation broke things in other situations, and left some games like Kirby Air Ride looking a little dark.
Why exactly is this happening in Kirby Air Ride? To answer that, we need to talk about LogicOps and how they work on the GameCube/Wii. LogicOps (Logical Operations) are a more complex version of Blending operations, allowing a game to perform a wide variety of binary commands in the blending stage. The GameCube and Wii support this natively (based on the OpenGL implementation). In the hardware, they are bitwise operations that use the output color from TEV and/or the current color of the framebuffer and use them in various ways. The result of the operation is then written to the framebuffer and used.
Kirby Air Ride uses the alpha value on the framebuffer to determine where to draw shadows on the screen. At the start of the frame, the game sets the alpha of the rectangle 255. However, it also uselessly uses the SET logic op, which sets the output color to the current TEV color. This is fine if the system supports one of Dolphin's proper LogicOp paths. However, this goes completely wrong under Dolphin's LogicOps approximation with blending path. In this case, Dolphin sets the source and destination factors for the color, but does not set factors for the alpha. This causes the alpha to be set to zero for the entire frame. Even when the game attempts to modify the value to mark where shadows should be drawn, it remains at zero.
If you feed in black rather than the alpha value, instead of lightening the scene, it instead gets shrowded in darkness. Emulating LogicOps with blending is already a last resort, so to improve the situation, OatmealDome had to go another route. With macOS and MoltenVK, Metal does not support LogicOps, so OatmealDome modified our MoltenVK implementation slightly to enable SPIRV-Cross to convert Vulkan's subpass inputs into a framebuffer fetch. This allows Apple Silicon GPUs to support LogicOps, but unfortunately all other macOS GPUs still will not work as they do not support this function. For OpenGLES, there is an extension to support LogicOps, but of course no mobile drivers bother to support it. Instead, we rely on
GL_ARM_shader_framebuffer_fetch, which can give us the colors of the framebuffer and then we can handle the LogicOps logic in the shader itself. This is slightly slower than native support, but much better than using blending approximation.
Note: The modifications to MoltenVK will not be upstreamed. This is because the behavior we're utilizing is specific to what Dolphin needs. It works for our purposes, but chances are that other programs probably wouldn't want this. Eventually MoltenVK should mature to the point that this hack won't be necessary, but for now this helps make the game's playable on Apple Silicon.
5.0-15680 - TextureConverterShaderGen: Set alpha to 1 on intensity formats if EFB lacks alpha by Pokechu22¶
Sometimes an obscure game can lead you to some rather interesting effects. Rygar: The Battle of Argus was a cash-in port of an already six year old PS2 game, Rygar: The Legendary Adventure which was a follow up to Rygar (Arcade), which is playable on the Wii Virtual Console Arcade. Based on the reviews people gave to Rygar: The Battle of Argus, that might actually be the better Rygar game on Wii.
And that's just about all the information we could find on this game. However, any game, no matter how good or bad, can become notable to emulation developers. All it has to do is have one thing that confuses everyone. For Rygar: The Battle of Argus, that ended up being what made it fun for us. An issue report mentioned that some screens would be washed out in Dolphin, which eventually was tracked down to its bloom effect. Initial experimentation with the effect and how it worked led us to wonder if the effect even worked on console. But, that was easily tested and it turned out that it was yet another weird edge-case.
Pokechu22 took interest and you can probably guess what happened next if you've been reading these reports. A hunch was quickly surmised that this problem might be related to other visual glitches throughout the game. After testing things in the latest development versions, Pokechu22 found that the bug was present in most scenes throughout the game with varying degrees of aggressiveness.
Rather than just trying to see what was wrong in Dolphin, they instead did a deep dive into exactly how the game was rendering the effect. Once the effect was understood, the answer to what was going wrong would be simple. It turns out the game's bloom actually uses a clever trick to work around a hardware limitation - that the GameCube and Wii can only work with a single framebuffer. If a developer wishes to make other computations using the GPU, such as creating a texture for dynamic shadows, then they will need to draw on top of what's already been drawn on the screen. This is similar to the difficulties and problems Heavy Iron Studios ran into when rendering the shadows in Spongebob Squarepants: The Battle for Bikini Bottom.
Long story short, because the game was having to render over what it had already rendered, it created an EFB Copy without an alpha channel. Because of that, the alpha channel would return 1, or totally opaque. While that's normally correct, Rygar was making an EFB copy from a texture using an intensity format. While normal textures as EFB copies would usually be 1, when using an intensity format, Dolphin was setting it to zero! This completely changes how things are rendered in Rygar: The Battle of Argus, and is the key to their rather interesting dynamic bloom technique.
As custom after running into a unique issue, Pokechu22 started looking through fifologs and issue reports to see if there were any other bugs that were potentially related. Oddly enough, they stumbled into a much more widely known game: Pokemon Battle Revolution! For the past couple of years, it had been suffering with a regression that caused the screen to shift whenever a special effect that used the EFB was on screen.
Unfortunately, we had no real leads as to what was wrong, but we didn't end up needing any. Fixing Rygar: The Battle of Argus also fixed Pokemon Battle Revolution. However, because no one knew why Pokemon was fixed, the job wasn't completely done. It turns out, what was happening here was actually two separate bugs, and one of them actually happens on console! The screenshifting a huge amount was a Dolphin bug, but many of the special effects were also broken on console to a degree. That's because the game accidentally crops the bottommost and rightmost row of pixels, and then because of texture clamping, those rows get used for anything that would use content off of the screen.
Pokechu22 found their bug and created a game patch, which caused a bunch of special effects to render like they were intended for the first time.
And with that, our dive into these two games was complete. . . . Except it wasn't. Shortly after investigating Rygar: The Battle of Argus, it was noted that the game no longer worked in the latest development builds, crashing with a backpatch error unless full MMU was enabled. This regression was fixed in 5.0-15699 to return the game to normal.
5.0-15928 - Add Online Wii System Update Functionality to Dolphin on Android by Simonx22 and OatmealDome¶
Another major feature lands in the Android GUI. If you're looking to see some of the Wii's more advanced features or run homebrew, having a full assortment of System Files is necessary. On Android, getting those System Files could be a bit tricky, as actually updating the emulated Wii wasn't as simple as on Desktop versions of Dolphin. Simonx22 and OatmealDome teamed up to rectify this issue, with Simonx22 handling the Android side of things and OatmealDome helping with the C++ part of the implementation.
Once you've run a Wii System Update, you'll be able to access the Wii Menu and be able to boot channels, games, and even things like the Open Homebrew Channel!
For most users, this won't be too important, but it does allow for easy access to the Wii Menu and will allow booting discs and channels from it without the need for a PC for downloading or copying files.
Mario Party 5 players have been complaining to us for many years about a very peculiar bug. "Why does Dolphin crash when I use a Wiggler Orb"?
Technically, Dolphin wasn't crashing, but notifying the user of an unknown opcode. While this did interrupt play, all the user had to do was proceed through the message boxes and the game would keep going as if nothing happened. Over the years we found this to be a harmless occurrence and no cause for concern, but we didn't want to remove the message. After all, it was correct and pointed to a likely bug in Dolphin's GPU emulation.
However we couldn't really investigate the scene further, as Dolphin's Fifoplayer was unable to record scenes with unknown opcodes. At least it wasn't... until very recently. We've said this name a lot, but once again Pokechu22, has found time between investigating all of these issues to renovate our Fifoplayer with fixes and new features. One such consequence of their fixes is that the Fifoplayer can now record scenes with unknown opcodes. What mysteries would be awaiting us with the Wiggler Capsule after it had evaded our gaze for all of these years? For this, we'll let Pokechu22's own writeup explain.
Basically, the Wiggler capsule's animation draws a bunch of rings. Each ring has 128 vertices in it, with positions moving around a circle and texture coordinates going up by .03125 (1/32) for each horizontal step. The position, color, and texture coordinate data for each vertex is indexed into several arrays, with the first set of 4 vertices using indices 0, 1, 3, and 2. However, after all 128 vertices are written, the game writes data for 4 more vertices, again using indices 0, 1, 3, and 2. But since the game said it would only draw 128 vertices, not 132, those 4 vertices are instead interpreted as graphics commands. Opcode 0 is a NOP, and my brief hardware testing indicates that opcodes 1-7 are also treated as NOPs, so on real hardware these are ignored, but Dolphin didn't like that extra data. ...
If we modify the FIFO data to say that there are 132 vertices, then the first part of the ring is drawn twice, which indicates that vertices 129-132 normally go unused.
This confirmed a rather exciting event! For the first time in many, many years, this is a case of an "Unknown Opcode" popup actually caused by an Unknown Opcode in a retail, licensed game. Most of the time these popups are disregarded as Dual Core misbehaving or strange GPU timing issues. There's a reason the message written by developers well over a decade ago seemingly disregard that the popup could be caused by an actual unknown opcode.
How exactly did this slip by the game's developers? Well, our best guess is this effect was programmed rather haphazardly and developers didn't realize how broken it was. The effect is broken in multiple ways, one of which is visual in the form of a texture defect. While normally this would be very, very difficult to see on console, Pokechu22 devised a way to use the HW Fifoplayer (a Fifoplayer that runs on an actual console) along with some fancy stitching of XFB copies to create high resolution screenshots on console. This isn't perfect but it does give us a chance to get a very high quality look at how this effect renders on console and confirms that Dolphin is emulating it right.
With this game's issues fully understood and Opcodes 0x1 -> 0x7 confirmed to be Nops (No Operation), the Unknown Opcode popups have been disabled for these Opcodes. This means that in the latest development builds, you no longer have to worry about the Wiggler Capsule causing any interruptions to your gameplay experience. As this is a strange behavior, Dolphin will continue to log Unknown Opcodes 0x1 -> 0x7 behind the scenes as it can give us a clue toward other bad behaviors and potential visual issues.
lynxnb returns with another Android centric change, this time an alternative control scheme for Touchscreen Pointer. Currently in Dolphin, you control the IR pointer by touching the screen, and then the cursor moves to the approximate point your finger tapped. This isn't very exact due to how different games are calibrated differently, and how large fingers are relative to the targets on screen. This change adds a second mode, where instead of the Infrared Pointer following your finger's position, it instead follows your finger's movements - like a touchpad. This is especially useful in shooters where you're going to do a lot of turning.
The Scoped Storage situation on Android has turned out to be a confusing, frustrating place for both users and developers alike. Depending on your phone, manufacturer, and the version of Android that you're on, your experience with Scoped Storage and its problems are going to vary. Some manufacturers seem to lock down app specific directories entirely, even preventing users from copying files in from a desktop computer. This means that users can't copy in saves, setup Riivolution mods, or backup their data in a meaningful way whatsoever. Given that this was a rather dire situation, JosJuice decided to rush in an option that will at least give users something they can use to import and export their user settings.
Do note that we're not going to implement our own file manager just to handle user settings. Currently, Dolphin can import .zip files that contain the user directory. A "Dolphin.ini" must be present in the "Config" folder for it to be considered valid user data. Do note that importing User Data will overwrite and delete all existing User Data. When exporting your User Data, it will be exported into the same kind of zip file that Dolphin expects for importing, so you can use that as a guide to see how the zip file should be laid out. Currently, support is a bit spotty, so making as "basic" of a compressed zip file as possible is for the best. We'll continue to explore other avenues for managing User Data now that we know this is going to be a problem from here on out.
This is an overhaul that was quite overdue. Essentially, Dolphin's Panic Alert system had a few minor bugs. Namely, sometimes they wouldn't display all of the information we intended and translations weren't working, meaning even though some of the Panic Alerts were translated, the translations would never get shown regardless of the user's language. In between solving all of those crazy graphics bugs, pokechu22 found time to fix them up a bit.
Port Settings to new Configuration System by AdmiralCurtiss¶
We haven't talked about the new configuration system in quite a while. To be honest, it's actually not that new anymore, now is it? This summer, it'll actually be five years old, the Layered Configuration System (Layered Config) is a more powerful configuration system that allows layers of overrides while also keeping multiple settings in mind. To harken back to a simpler time, Layered Config is an overlay configuration system with multiple layers - like an onion - and each layer lays over the one beneath it. Even though Dolphin only acts on the final result of all of the layers, each layer exists at all times in the config system, allowing Dolphin to know what settings layer is affecting what and why. This allowed users to make changes on the fly, without actually overriding the defaults as soon as they opened the menus. Unfortunately, once the important settings were ported over, progress of moving things over to Layered Config stalled and we have two active configuration systems for the past five years. The classic, fast, but limited SConfig, and the newer, more robust, but sometimes difficult to optimize Layered Config.
The fact that Dolphin has two very different Configuration Systems has led to a bit of technical debt, and has limited Dolphin's ability to move forward in some ways. Want a "Return to Default Settings" button? Well, that's not easy to do because there are two active configuration systems. Want to add a certain setting to your Game Config? SConfig settings aren't guaranteed to work in GameINIs! Want to change a setting while playing Dolphin on Android? Well, if that setting is handled by SConfig, odds are you'll have to stop emulation first. The list goes on, but simply moving everything over was a rather big task.
In recent months, AdmiralCurtiss has taken the mantle to finally remove all of the remaining reliances on SConfig and simplify Dolphin's configuration system in general. The end goal of all of this will be new, easier ways to manage Dolphin's settings so that you don't need to be an expert to get the most out of your Dolphin experience. But right now, we're still porting over a few stragglers in preparation for bigger things. Stay tuned.
Redump Has Made the Wii Database Public!¶
While this isn't directly a Dolphin change, it's a change that affects disc verification. Dolphin's disc verifier can now verify good dumps of Wii games by making use of the redump.org Wii database. In builds with the disc verification feature, notice that Dolphin can now tell you when you're using a good dump of a Wii game. This actually extends backwards to builds before the database was public, as the functionality had been prepped for this eventual release.
macOS Gets Some Love¶
macOS has been in an odd position with Dolphin the past few years. We've had to deal with Apple deprecating their already neglected OpenGL support, ignoring Vulkan to set up their own graphics API, and Bluetooth changes to macOS 12 Monterey that took connecting Real Wii Remotes from occasionally possible on a good day to no chance in hell. Add in their strict security measures, and it's been very difficult to give users on macOS a good experience when using Dolphin. While there are still some problems, OatmealDome, along with a few others, have taken up the mantle of maintaining and renovating macOS support in Dolphin. These past three months saw two significant steps forward for the OS.
Maybe someone should have checked that¶
Under macOS, our official minimum supported version is macOS 10.13 High Sierra. We do have a High Sierra system on hand for verification, however, after the recent move to the new Universal Builds, we never actually got around to trying those builds on the High Sierra machine. Intel machines were tested, of course, but never ones running older versions of macOS. Since Universal Binaries go all the way back to macOS 10.4.4 Tiger, we weren't worried about it.
Six months after the Universal Builds were introduced and two months after the Intel-only mac builder was turned off, we recieved an issue report of macOS failing to launch on a macOS 10.14 Mojave system. Well, there was only one way for us to respond. After digging through a shelf and wiping off some dust, the High Sierra system was retrieved and finally got to see the new Universal Builds. They didn't work. With great irritation our eyes immediately glared toward Qt, after all it was what forced us to a minimum of High Sierra in the first place, but Qt wasn't to blame. TellowKrinkle found that the Universal builder was set up with a new SDL version that had a minimum support of macOS 11, a year-old version of macOS. That's not acceptable at all! Fortunately, once this issue was discovered it was pretty simple to resolve, and now the latest builds of Dolphin run on High Sierra once again.
Our macOS builds have been signed for years and years, so Gatekeeper's slowly tightening jaws didn't matter to us. That was until macOS 10.14.5 turned on the notarization requirement. Signing your application was no longer enough, now macOS developers were expected to also send a copy of their builds to Apple to have Apple themselves scan it for malware and verify the signing key. We were not very enthusiastic about these strict new requirements. It clashed with our buildbot systems of the time and it would have been non-trivial to implement, so the maintainer chose to not to. Unfortunately for our users, that meant that Gatekeeper now treated our builds as if they weren't even signed.
So for the past two years, users could not simply double click to open new Dolphin builds. Gatekeeper would complain saying that it could not be sure that it was safe and refuse to let Dolphin load. To bypass this, users had to ctrl-click Dolphin and click Open, then click Open in the resulting prompt. Then Dolphin would open... or the prompt would disappear and require the user to double click on Dolphin manually. If anyone knows why it did that sometimes please let us know, that quirk made explaining this process to new users an absolute nightmare.
Regardless of the problems of the past, OatmealDome sorted out most of the pain with notarization and the new Universal buildbot was painlessly updated to include it. Now the latest builds will run on macOS without all of those annoying popups and workarounds. Just double click Dolphin and it works, how novel!