Dolphin, the GameCube and Wii emulator - Forums

Full Version: Dolphin Custom Texture MipMaps
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
(01-05-2018, 12:35 PM)AnyOldName3 Wrote: [ -> ]Okay, so here's a completely bizarre idea: allow mip levels for custom textures which replace mipmaps. This would mean that when a game would use the 256x256 mip level of a texture at 1x IR, we look for a series of textures which replace the 256x256 mip level in particular, and choose the one closest to the display resolution of the texture for the actual IR we're using. This would allow the separation of custom texture mip levels from original game mip levels, which basically seems to be what we want.

We'd probably want some way for either texture pack creators to specify that they want this behaviour for a specific texture (as otherwise, most textures would just be duplicates) or for Dolphin to only enable it when it detects that the original texture has non-trivial mipmaps.

In terms of the texture dumping and loading system, that could be done by making it consider non-trivial mipmaps of a texture to be a different texture. I think we could handle the GPU side texture selection by using the same maths as the GPU does under the hood to select mip levels, but instead of using the hardware provided screen-space derivatives, scale them to match 1xIR screen space and use that to select a texture from a sampler array.

I think the shader mods you are suggesting are the same as adding a lod bias of sqrt(IR) to the samplers in question? But you'd get possibly weird visuals as it would possibly select a significantly lower quality texture for the primitives that use said textures than others in the same scene.

I feel the best solution would be for custom texture authors to provide different mipchains for these specific textures for a range of IR scales (which probably isn't too many, with non integer IRs being kinda busted and hidden anyway), and either allow dolphin to select at runtime, or get the user to download or overlay the correct package for there IR.

Naturally, I'll lean towards no extra complexity in dolphin itself Smile
Thanks for all the info. It seems I was coming at this from the wrong angle, I was just looking for the easiest solution to control which mipmap levels we would see. Forcing a chain to load at specific intervals seemed the most ideal (like 1x IR does), but I can now see this is not the correct route.

(01-05-2018, 08:55 AM)JonnyH Wrote: [ -> ]- Games that (ab)use miplevels "effects" instead of just texture downsampling look different in different IRs.
^ This. And not only that, it's possible to create mipmap effects outside of games that used them by default. It's not a common practice, and I realize it's completely niche and maybe not even worth the effort, but it is done in some packs (Xenoblade pack, Mario Galaxy packs, hypatia's Wind Waker pack). Technically any game that has mipmap textures, texture creators can make use of this as a "feature". But the ability to change IR affects the consistency of the effect (e.g. where the effect appears).

(01-05-2018, 02:25 PM)JonnyH Wrote: [ -> ]I feel the best solution would be for custom texture authors to provide different mipchains for these specific textures for a range of IR scales (which probably isn't too many, with non integer IRs being kinda busted and hidden anyway), and either allow dolphin to select at runtime, or get the user to download or overlay the correct package for there IR.
This is actually a viable solution, definitely better than what I was proposing. It would be somewhat inconvenient to have to provide multiple packs for each IR (some people play at 2x, some at 3x, some at 4x, some at 5x, who knows where it ends). But if several versions of the same texture could be provided in the same pack, and Dolphin could select the proper one based on IR, then that would be fantastic.

I have no idea how difficult it would be to implement such a feature, and we would need some way to actually define which texture to use like:
tex1_64x64_m_4f420ff297b21e70_14_2xIR.dds
tex1_64x64_m_4f420ff297b21e70_14_3xIR.dds
tex1_64x64_m_4f420ff297b21e70_14_4xIR.dds

But I guess it also presents the issue if someone switches IR during game play. Reloading textures on IR switch seems like it can get messy, so the only time the check would be worth it is when textures are first loaded. Broken effects from switching IR would just be a minor consequence to how it is now (which is only one IR with correct effects).

I suppose there is also the alternative of just providing separate "IR" folders in packs as "addons" to overwrite textures. This is a solution so simple that I failed to see it. But of course this opens the door to user error (selecting the wrong IR folder, deciding later on that they can use 3x instead of 2x without swapping textures). But, this is an immediate solution that works without changes to Dolphin, so I guess at this point it's whatever the devs decide.

Edit: Actually, I'm just going to accept defeat on this one, scratch the idea because it just isn't worth it at this point. I didn't realize adjusting the AF also affects draw distance. So that's yet another variable. This is the same sky in SMG at 1x, 4x, and 16x AF, all at the same 3xIR.

[Image: hUbXZ4W.jpg]
Ok so I didn't admit defeat just yet. I really don't know what I'm doing, but I was able to modify and build Dolphin for the first time! I changed this line here: https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/VideoCommon/TextureCacheBase.cpp#L1091


To something like this:
Code:
bool custom_arbitrary = false;

if (hires_tex)
{
  bool custom_arbitrary = true;
}
entry->has_arbitrary_mips = arbitrary_mip_detector.HasArbitraryMipmaps(dst_buffer) || custom_arbitrary;

And custom textures behave exactly like I want, they draw at a fixed distance at any IR and any AF setting. Obviously this is bad in its current state because it forces all custom textures to behave like this, but its a proof of concept that the arbitrary mipmap fix does indeed work for custom textures with almost no modification.

So I go back to my original idea of having some flag in the texture name to trigger this, like "_carb" (custom arbitrary mipmap texture, but really anything would suffice) to tell when to draw a custom texture at a fixed distance. This will not work in its current state because I have no idea how to modify the texture loader to see this flag, and I don't even know if its written correctly because I googled how to check a string within a string, but like...

Code:
bool custom_arbitrary = false;

if (hires_tex)
{
  bool custom_arbitrary = (basename.find("_carb") != std::string::npos);
}
entry->has_arbitrary_mips = arbitrary_mip_detector.HasArbitraryMipmaps(dst_buffer) || custom_arbitrary;

Is this a viable option? Is there any reason why this can't be done or added as a feature?

Edit: I put up some screens of why I think this is useful / why I want it. Using the modified version above, I'm able to match exactly (or at least very close) to the original effects with custom textures at any IR/AF setting. Or, at least control where the effect appears for textures that didn't originally use mipmap effects (like the Xenoblade texture examples).

[Image: v8iVEMF.jpg] [Image: WNtxasy.jpg] [Image: jrZddIm.jpg] [Image: 0wuJhVf.jpg]

[Image: SsKni5m.jpg] [Image: Y76Rubb.jpg] [Image: fUMfVy8.jpg] [Image: Y7xDeTG.jpg]

[Image: PeaXk6m.jpg] [Image: cC9Ilyi.jpg] [Image: IlvLE7I.jpg] [Image: IYabPMH.jpg]
So here is a complete working implementation + source code:
http://www.mediafire.com/file/baf8u98dla69kzx/Dolphin+5.0-6157+%5BCARBMM%5D.7z

What currently happens in Dolphin master:
Textures that are detected with arbitrary mipmaps are dumped with the "_arb" suffix. Textures with this suffix currently will not load as custom textures. There is also no way to force arbitrary mipmap detection for custom textures.

What this build does:
This allows loading custom textures with the "_arb" suffix. It also tells Dolphin to treat these custom textures the same way as it does with stock textures that have arbitrary mipmaps, meaning mipmaps are stationary at all IR/AF settings. Textures without the "_arb" flag will behave the same as always, meaning mipmaps slide in/out with different IR/AF settings.

Bonus Feature:
The "_arb" suffix can be added to any custom texture to treat it as if it has custom arbitrary mipmaps. It can be removed from textures that are dumped with the suffix to handle them in the normal way.

What is the point:
Absolute control over which custom textures will get the arbitrary mipmap method applied to them (meaning, loading mipmaps at a fixed distance).

Highlighted Code Changes:
The implementation was actually quite simple. Below are the files with the modifications highlighted.

HiresTextures.h - Adds a bool that can be referenced in TextureCacheBase to know if the "_arb" flag is present.
HiresTextures.cpp - Check for "_arb" flag on update. Add the bool to be referenced.
TextureCacheBase.cpp - A little over halfway down, force arbitrary mipmap detection if "_arb" flag is present.

Final Thoughts:
I see no reason this should not be a feature, and I think by now I've thoroughly stated my argument for it. It's a simple change (less than 10 lines of code), Dolphin is already dumping textures with the "_arb" suffix, so why not make use of this suffix in a useful way. While it may not have an immediate use, in the long run it can only mean better texture packs. I personally want to fix some of the textures in SMG/Xenoblade packs to look correct at any IR, which is impossible without this, and I would prefer not to have to make a fork just for this one feature. I can't make a pull request as I don't know how, but if someone who can will, feel free to do so. There's probably even better ways to code it, but this is the best as I could do.
Please open a PR with it Wink
Hm, this implementation seems a bit odd to me. If I'm reading it right, if at least one texture has a name with _arb, every custom texture will be treated as having arbitrary mipmaps, not just the textures that are marked _arb. Is that unintentional?

I can work on a PR for you if you want to, but I'd like to make sure that I understand what the behavior you want is, since I haven't been dealing much with custom textures myself Smile
It's still missing the thing from the suggestion I made earlier where the mipmaps could have mipmaps. Without mipmaps for the 'mipmaps but not really as they're different to the big versions' you're going to end up with noise if the replacer for the arbitrary mipmap is bigger than the display resolution for the texture. Even if we don't allow these to be created as part of a texture pack (by allowing instead of just one set of _arb textures an _arb_0, _arb_1 and _arb_2 etc.), we should probably autogenerate some when the texture is sent to the GPU.
(01-10-2018, 03:59 AM)JosJuice Wrote: [ -> ]Hm, this implementation seems a bit odd to me. If I'm reading it right, if at least one texture has a name with _arb, every custom texture will be treated as having arbitrary mipmaps, not just the textures that are marked _arb. Is that unintentional?
You are right, I'm not good with C++ at all. That is unintentional and definitely not the desired behavior, the idea would be control for each texture individually. It took me like 8 hours to come up with that small change, much of that was just gaining a brief understanding of what's going on. And it would probably take me 8+ more to try to figure out how to do it properly. When I was testing it, I was just testing a single set of textures, so it looked like it was working correctly.

(01-10-2018, 06:03 AM)AnyOldName3 Wrote: [ -> ]It's still missing the thing from the suggestion I made earlier where the mipmaps could have mipmaps. Without mipmaps for the 'mipmaps but not really as they're different to the big versions' you're going to end up with noise if the replacer for the arbitrary mipmap is bigger than the display resolution for the texture. Even if we don't allow these to be created as part of a texture pack (by allowing instead of just one set of _arb textures an _arb_0, _arb_1 and _arb_2 etc.), we should probably autogenerate some when the texture is sent to the GPU.
That's a good suggestion, although it might be complex for PNG files and I have no idea how hard it would be to implement. Right now a bit of noise seems ideal over broken effects, as the idea of arb mipmaps is niche and I don't think many textures or artists will take advantage of the effect. There are only 3 packs at the moment that make use of them, and very light use at that. I have no idea how to implement it, but if someone else could it would be great. For DDS it could be very clean, all "mipmap" files could technically have mipmaps built in such as...

tex_256x256_hash_14_arb.dds
tex_256x256_hash_14_arb_mip1.dds
tex_256x256_hash_14_arb_mip2.dds
tex_256x256_hash_14_arb_mip3.dds
tex_256x256_hash_14_arb_mip4.dds
....

But even then, the texture loader will have to distinguish between mipmaps in mipmaps, or just mipmaps. I guess having "_arb" could work as that switch.

PNG would be more messy. You could end up with something like...

tex_256x256_hash_14_arb.png
tex_256x256_hash_14_arb_mip1.png
tex_256x256_hash_14_arb_mip1_1.png
tex_256x256_hash_14_arb_mip1_2.png
tex_256x256_hash_14_arb_mip1_3.png
.....
tex_256x256_hash_14_arb_mip2.png
tex_256x256_hash_14_arb_mip2_1.png
tex_256x256_hash_14_arb_mip2_2.png
tex_256x256_hash_14_arb_mip2_3.png
.....
tex_256x256_hash_14_arb_mip3.png
tex_256x256_hash_14_arb_mip3_1.png
tex_256x256_hash_14_arb_mip3_2.png
tex_256x256_hash_14_arb_mip3_3.png
.....

Which would work, and all the files would be easy to auto-generate with my script. But actually having Dolphin make use of this is beyond me. I am willing to keep trying, as it's been entertaining attempting to learn the code. But I'm not against anyone doing it properly. Tongue
(01-10-2018, 06:03 AM)AnyOldName3 Wrote: [ -> ]It's still missing the thing from the suggestion I made earlier where the mipmaps could have mipmaps. Without mipmaps for the 'mipmaps but not really as they're different to the big versions' you're going to end up with noise if the replacer for the arbitrary mipmap is bigger than the display resolution for the texture. Even if we don't allow these to be created as part of a texture pack (by allowing instead of just one set of _arb textures an _arb_0, _arb_1 and _arb_2 etc.), we should probably autogenerate some when the texture is sent to the GPU.

To be honest, this is the same behavior than providing different custom textures for each IR. Only the IR will select which of those mipmap levels should be used. So I wouldn't call it "mipmaps for mipmaps", I'd call it different upscaling factors for the same texture.
That's one of the ways I described it in my first post about it, but the only person who responded to that misunderstood. However, at the end of the day, what are mipmaps if not different scaling factors for the same texture?

Also, when it was brought up as 'having different textures for different IRs' sometimes it was done so with the idea that you'd only have one version installed at once and other times that each version would be labelled with the IR it was supposed to go with. Both of these allow greater scope for user error leading to use of the wrong size of texture when a better match is available (as the texture pack creator would need to know which size was appropriate for which IR) compared to recycling our mipmap naming suffix and having Dolphin decide which version is appropriate. Also, if an IR is selected that would best match a non-power-of-two texture size (which is likely as very few numbers are integers, let alone powers of two), if we treat the different versions as mipmaps we can do trilinear filtering but if we pick the one that is labelled with the current IR setting, it would be weird if we also loaded another one.
Pages: 1 2