Dolphin Progress Report: November and December 2017

After the massive Hybrid XFB article that hit late November, we at the blog staff went into a bit of a hibernation. But after a short holiday break, we're back and ready for more. Before we get to the rest of November and December's changes, make sure you check out the absolutely massive Hybrid XFB article and the accompanying video.

With both Ubershaders, Hybrid XFB, and many of the other targeted features for the next release merged, a lot of users have started wondering when our next release will be announced. The answer to that is not soon. With these huge changes have come a lot of frustrating and annoying regressions that can't easily be solved without a lot of work. If we enter a feature freeze to work on those regressions, we'd be stagnating Dolphin and delaying the other large new features that are still being worked on without any guarantee that the regressions will be sorted out.

So for now, the plan is to just keep moving and wait for a better opportunity to start the release process.

Notable Changes

5.0-6101 - [Android] Support for Default Game Settings by JosJuice

One of our long term goals is to bring parity between our Android and PC versions. Considering just how many roadblocks there are in the way of that, Android is still pretty hard to use in many cases, especially since hundreds of games require manual settings adjustments to avoid known issues. A big contributor to that has been eliminated with GameINI support for Android!

On PC, whenever Dolphin boots a game it checks the INI for that game to make sure any needed settings are automatically loaded. Using this method, we are able to ship Dolphin with performance focused settings by default and only activate demanding accuracy settings when needed. In practice, this allows games to "just work" without adjusting settings, and for users to enjoy the maximum possible performance without encountering issues for every title.

Game INIs on Android is something we've wanted for quite a while, but there wasn't a clear solution for how to implement the feature. It can't be done the same way as on PC, and the earlier attempts mucked up the cross-platform code in a way that made them undesirable to merge.

Without GameINIs, games that are known to need certain settings won't have them enabled by default. In this case, without Store EFB Copies to Tex and RAM, Metroid Prime 2's scan visor thinks nothing is scannable.

JosJuice's solution is actually fairly nice, with the only downside being around 4MB of additional storage used. Considering all the benefits that game INIs give and the fact that most of the games take up so much space already, we believe that this is a more than fair tradeoff.

This may sound extremely simple, but one of the reasons this solution wasn't attempted before is that most of the people working on the Android UI specialized in Java, while this solution required both Java and C++ expertise to pull off. Thankfully, JosJuice was finally able to get this much wanted feature done.

For Android users, this means that Dolphin now enforces the same settings on Android as on PC. Dolphin will automatically enable MMU for games like Time Splitters 2/TimeSplitters: Future Perfect, and Rogue Squadron 2/3 so they can run just like on the PC version. But, considering that the ARM64 JIT falls back to interpreter for MMU emulation... performance may be even lower than you'd expect. Still, any step toward parity with the PC version is a step in the right direction.

5.0-5791 - Fix DTK Audio After Loading Savestate by JosJuice

Things have gone a bit silent on the DTK audio front in recent years. Disc TracK audio was a huge struggle for Dolphin for many, many years; with problems ranging from games resetting unexpectedly to games refusing to play more than one song. Even after completely rewriting everything, we discovered another bug involving DTK audio. Sometimes, after loading a savestate, any in progress DTK audio file playing would be gone.

For years, this was just ignored as one of the problems with DTK audio games until JosJuice discovered that savestates weren't saving the volume of the DTK audio that was playing. Thus, if you loadstate while the volume is set to 0 (such as during game boot) or while the game is fading out a DTK audio track, all DTK audio will be much harder to hear or completely gone.

After a quick tweak to savestates, the bug is fixed. As an odd aside, Dolphin's audio dumping was unaffected by this bug because it completely ignores DTK audio volume.

5.0-5821 - Fix Off-by-One in SDHC Detection by TBoshoven

Details are important and Dolphin was getting a fairly simple, yet incredibly important, detail wrong in the SDHC implementation added a few months ago. Namely, if you were to create a 2GB SD card (the maximum for non high-capacity cards) Dolphin would treat it as a SDHC card, meaning older Wii games can't detect it. The reason for it is simple, maybe you can spot the bug.

if (m_card.GetSize() < SDSC_MAX_SIZE)

If you spotted that < sign and wondered, Hey, where's the equal sign? then you're a winner. A simple off-by-one error in detection was causing SD cards that were exactly 2GB to be treated as SDHC cards. The corrected code reads like this:

if (m_card.GetSize() <= SDSC_MAX_SIZE)


Note: It's important to enable SDHC mode when using bigger SD cards. On the other side, it's also important to make sure that SD cards smaller than 2GB are treated as standard non-HC. Not doing so causes many weird behaviors because some older IOSes (and thus older Wii games) only support SD cards and not SDHC.

Oddly enough, this limitation wouldn't have been present in Dolphin last year due to IOS-HLE being far more primitive and not actually emulating the various differences between IOS versions.

5.0-5833 - [UI] Remove fullscreen resolution UI by Helios

Dolphin is over 14 years old now, and there are a lot of legacy concepts that we've grown accustom to that aren't exactly optimal to users today. In this instance, Dolphin presented two resolution settings to users, but only Internal Resolution actually controls Dolphin's rendering resolution! The other option was known as Fullscreen Resolution, and it controlled the final resolution of the display - an important feature for getting a clear image on CRTs. LCDs, which overtook CRTs as the majority display technology ten years ago, make this option completely unnecessary and even somewhat harmful due to their poor scaling. Still, it had always been there, and we forgot about it. Besides, users wouldn't blindly change an option without knowing what it was for, right?

Frankly, we should have seen this coming. Most of our users use their gaming PCs for Dolphin, and PC games present a single resolution option that is always rendering resolution, and always critically important for users to adjust. And we were presenting users with a setting with resolution in the name, even though it wasn't the rendering resolution. Of course users would feel like they had to adjust it! This has lead to a lot of user confusion and forum posts over the years, not to mention some very strange settings combinations.

There are still some niche use cases for overriding the display's resolution, like competitive smashers and their Trinitrons. So instead of removing the feature outright, we removed it from the UI but left the INI settings. This removes the confusion for the bulk of our players but still gives power users the option.

5.0-5874 - Hybrid XFB by iwubcode and phire, and Hybrid XFB Followups

Hybrid XFB was one of the biggest changes to Dolphin in 2017! If you want to learn more about this feature, check out the feature article we wrote mid November. As you may have noticed, there are quite a few followup commits that change various behaviors. Instead of retreading what we already went into great detail on in the Hybrid XFB article, we're going to talk about some of the oversights and changes since then.

INI Changes

The simplest of these changes are a bunch of INI changes, including one that is a change in philosophy. In the original Hybrid XFB article, we stated that we had put "Immediately Display XFB Copies" in certain game INIs to help them be lower latency for competitive reasons. Unfortunately, that was a bit shortsighted and we ended up affecting some of our core users. By enforcing it in those games, features like the GameCube Main Menu would malfunction again much to the confusion of users. It also set a very sketchy precedent of purposely making emulation worse without any noticeable benefit for most users.

If you absolutely require low latency in a game, you can turn on Immediately Present XFB Copies in the hacks menu or re-add it to your INI manually. This makes it so any GameCube game booted in Dolphin with the Main Menu enabled will display correctly.

Abstract Staging Textures - 5.0-5968 by stenzek

This is a huge change that goes beyond just touching up parts of Hybrid XFB. Abstract Staging Textures increases performance and rewrites portions of Dolphin that will allow for a big feature down the road! Unfortunately, on its own users won't see much of a difference, and its biggest increase in efficiency is only noticed because of an intentional performance regression in Hybrid XFB. Without this change waiting in the wings, it's possible that Hybrid XFB would have been delayed even longer as we tried to iron out inefficiencies.

Abstract Staging Textures comes to us from Stenzek, who was also one of the key reviewers of Hybrid XFB. What this change does is allow asynchronous read/write of textures when latency is not a concern. For something strenuous like framedumping, asynchronous staging textures gives a massive 50% performance boost over the slower implementation in the Hybrid XFB merge and a 10% boost over older builds. In addition, it repairs regressions in the D3D backend's frame and texture dumping functionality.

Only use the "Scaled EFB Copy" setting for EFB, not XFB - 5.0-6074 by JosJuice

This is actually a very funny change that made players of games like Super Mario Sunshine somewhat upset. In that game, you can turn off Scaled EFB Copies to make a certain effect look much better at higher resolution.

With Scaled EFB Copies on at a high resolution, the graffiti looks rather retro.
With it off, the graffiti is correct! ...though the distance blur is much stronger and pixelated.

Our oversight is that now XFB Copies were using the same codepath as EFB Copies! This meant that the Scaled EFB Copies setting was affecting XFB copies as well. XFB copies are the final stage before output, meaning your game would be locked to 1x internal resolution, much like turning on XFB Real in older builds!

Fortunately Dolphin already keeps track of whether an EFB copy is an XFB copy or not, so JosJuice was able to create a simple patch to restore the old behavior for now. The long-term goal is to fix these effects at higher resolutions so that this exception does not need to exist.

Fix PAL Vertical Scaling - 5.0-6084 by iwubcode

This is actually a reappearance of an issue from over two years ago, and quite an embarrassing one to let slip in. Basically, a lot of PAL games were crashing on boot as of the Hybrid XFB merge.

We fully blame this regression on Factor 5, as neither Rogue Squadron 2 nor 3 PAL run into this issue, and they accounted for most of our PAL testing. To make matters worse, most of Nintendo's first party titles weren't affected either, making it so this regression took a little extra time to come up and identify.

What's happening here can be explained most easily with code. Here is a simplified example of what the change does:

BEFORE: float num_xfb_lines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);

AFTER: float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale;

If you pay attention to the order of operations, you can probably see that those two equations can make vastly different answers. The afflicted games were using a yScale of 1.196262 and a height of 553 pixels. The order of operations affect the result, and if the XFB can't fit into memory, the game crashes.

BEFORE: float num_xfb_lines = ((453 + 1.0f) * 1.196262) = 543.1 = 543

AFTER: float numb_xfb_lines = 1.0f + 453 * 1.196262 = 542.9 = 542

By being one row too tall, the XFB can't fit where the game is putting it and the game now crashes. If not for booto recognizing that the crash behavior was something he'd seen before, this could have been a terrifying bug to figure out. So, no long term damage was done with this bug but it's still troubling that it slipped past testing and review.

Fix Frame Logic - 5.0-6060 by iwubcode

When using XFB Real back in the day, the framelimiter couldn't see the internal framerate. So a game like Wind Waker would show 60 FPS/60 VPS, even though it's a 30 FPS game. Hybrid XFB carried over that behavior for some titles in the initial release. iwubcode quickly repaired the issue with a small fix, so that now FPS represents the number of frames the game is actually outputting regardless of your XFB settings.

5.0-5904 - HIDv5 Support (USB Keyboard in Dragon Quest X!) by leoetlino

Dolphin's keyboard passthrough now works for Dragon Quest X!... Unfortunately, by the time you're reading this, Dragon Quest X's Online Mode for the Wii has already been shutdown. Still, having HIDv5 support is useful for typing in your character's name in the time being. If there is ever a way to get this game working online again in the future, the keyboard support will be waiting.

We didn't get any footage of this feature before the game's online was shutdown, so... here's a picture of the Dragon Quest X keyboard!

HIDv5 was an interesting challenge that required leoetlino to once again dive into reverse engineering a module. It actually shares more in common with VEN (USB2.0 Microphone) than it does with the older USB keyboard support in titles like the Internet Channel. Interestingly, some of the unused values in VEN finally find a use in HIDv5, which was the main issue with actually implementing proper support.

If you're wanting to try this out, it'll be quite difficult. Dragon Quest X is the only title to use this module.

5.0-5934 - Always Calculate Lighting on Both Channels by stenzek

Cel Damage has perplexed Dolphin developers for years and years. Despite huge fundamental rewrites to how Dolphin displays graphics, a lighting bug in this game was stubbornly unaffected.

Here is the Cel Damage on console, showing the cartoony graphics.
Dolphin changed the aesthetic just a little bit.

And now we finally know why. Cel Damage does something very unusual with its lighting system. Every model has a diffuse texture, and vertex colors (untextured but colored polygons, like Mario 64). Having both textures and vertex colors on a single mesh is very common in games, as the vertex color can be blended with the texture for baked shading and other effects. Except Cel Damage doesn't use the vertex color as a color at all; it uses the vertex color as a control to manipulate the object's texture coordinates within a color palette texture to finely control the lighting of the characters!

If you're not familiar with how games do graphics, this may seem like a bit much. So let's break it down a bit. A texture is a 2D plane, so to texture a 3D model it must first be unwrapped and flattened then placed onto the texture. To achieve this, vertices are assigned to pixels on the X and Y axis in the texture via texture coordinates.

Here is one of the many ways to unwrap a cylinder onto a texture.

In Cel Damage, each object has an additional texture that serves as a color palette, with multiple pre-made brightness levels in cells. The game uses the the vertex color's brightness to move the vertices of the object within the palette texture to select a specific shade, then blends that shade from the palette with the object diffuse map to form the final look. This is an extremely clever way of doing things and allows for precise control over the color of a character through a huge variety of different lighting conditions. This is still a tricky problem in cel shading today, so we were surprised to see such a complicated solution in a GameCube game! Despite this impressive system, it doesn't seem like the game did too much with it beyond a few nifty special effects here and there.

stenzek sorted through all of this and forced Cel Damage to render correctly a long time ago, but had to get around to hardware testing to find out what console was actually doing in this odd situation. He discovered that on console, changing XFMEM_SETNUMCHAN register between 1 and 0 had no effect on the lighting pipeline.

Up until now, Dolphin assumed that XFMEM_SETNUMCHAN controlled the number of lighting processes. If it was set to zero, then the lighting system would be disabled and colors would be passed through as is. This is a very logical assumption, and hadn't caused any problems for thousands of games. Except for Cel Damage with its trick for controlling brightness. Even though it set XFMEM_SETNUMCHAN to 0 for the vertex color channel, as it was not going to use it as a color, it is still using the data from it in the vertex stage before the rasterizer discards it. Dolphin on the other hand detected the register at 0 and just didn't run the lighting system at all for the vertex color channel, instead sending a default value, 100% pure white, in its place. So when game used the vertex color to pick the brightness of the characters, they were always at absolute maximum brightness.

Thanks to stenzek's hardware tests, we knew exactly how to fix this. When XFMEM_SETNUMCHAN is at 0, we still run the lighting system. If a game uses the vertex color for texture coordinates, then it will be used as such then discarded before it reaches rasterization, just like on hardware. If the game doesn't use vertex color for texture coordinates (basically every game but Cel Damage) the graphics driver will just optimize it out, so there isn't even a performance penalty.

Now this is the zany look we remember!

On top of shining (or in this case, blocking out) a light on Cel Damage, this fix also addressed a few other minor issues in games, such as Mini Ninjas' grey characters. There are probably even more fixed bugs that we haven't found yet!

5.0-6016 - Fix Wii Remotes on macOS 10.13 High Sierra by amolloy

Due to an API usage change in macOS 10.13 High Sierra, Wii Remotes were no longer functioning. With a distinct lack of macOS developers on the project currently, this went unfixed for quite a while until amolloy appeared with this fix.

The issue was caused by a change in threading in macOS. Thankfully, the revised behavior that works correctly with High Sierra also works fine with older versions of macOS, resulting in a happy solution for everyone. Wii Remotes should now work the same in High Sierra as any other version of macOS.

Last Month's Contributors...

Special thanks to all of the contributors that incremented Dolphin from 5.0-5757 through to 5.0-6106!

Gellir parhau'r drafodaeth yn edyn fforwm yr erthygl hon.

Cofnod nesaf

Cofnod diwethaf

Cofnodau tebyg