Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Darker textures on Android devices with Mali graphics when using Mipmaps (GLES3 only) #43342

Open
sergey-khrykov opened this issue Nov 5, 2020 · 18 comments

Comments

@sergey-khrykov
Copy link

sergey-khrykov commented Nov 5, 2020

Godot version:
v3.2.4.beta.custom_build.d3ffff3ad

OS/device including version:
Likely any Android device with Mali graphics. Tested on:

  • Samsung Galaxy A8 (Mali G71), A51 (Mali G72 MP3)
  • Huawei Honor 10 (Mali G72 MP12)
  • Huawei P30 lite (Mali G51 MP4)
  • Motorola OneAction (Mali G72 MP3)
    (all devices running Android 10 or 9)

Issue description:
Textures imported with Mipmaps setting turned ON appear darker than the same textures on a device with non-Mali graphics.
Turning Mipmaps off makes textures appear identical across all Android devices despite model or vendor.
The renderer used is GLES 3.

Steps to reproduce:

  • Run the project included on an Android device with Mali graphics. Note that the texture that is using Mipmaps is considerably darker.
    android_mipmaps_Mali

  • Run the same project on an Android device with Adreno or PowerVR graphics. Note that both textures have identical colors.
    android_mipmaps_Adreno

Minimal reproduction project:
Mali mipmaps issue.zip

@Calinou
Copy link
Member

Calinou commented Nov 6, 2020

Can you reproduce this when using the GLES2 renderer? Maybe the texture is incorrectly being rendered as sRGB.

@sergey-khrykov
Copy link
Author

sergey-khrykov commented Nov 6, 2020

Can you reproduce this when using the GLES2 renderer? Maybe the texture is incorrectly being rendered as sRGB.

On GLES2, everything looks Ok on both Mali and non-Mali. Colors are identical with and without using Mipmaps.

@lawnjelly
Copy link
Member

lawnjelly commented Nov 6, 2020

Sounds similarish to #39279 .

It could be it is simply not generating mipmaps and they are black, and the image is half way between the first layer and the first black mipmap.

You could test this by repeating the experiment with the sprite getting smaller and smaller and seeing if it goes darker to black.

Or an sRGB issue as Calinou says.

There's also an #ifdef GLES_OVER_GL section in the mipmap generation in GLES3 by the looks of things (although I'm not familiar with this code).

Generally this doesn't come up as much as you'd expect because it is normally recommended to run GLES2 on mobile, you are likely to run into other bugs in GLES3 even if this works.

Also it would be useful to know when this started happening, there have been a lot of changes to GLES3 in 3.2.4, does it occur in 3.2.3 (or an earlier stable build?). I suspect it will (because there have been no changes to mipmaps etc) but it would help narrow down.

@sergey-khrykov
Copy link
Author

sergey-khrykov commented Nov 6, 2020

Thank you for your hints!

Resizing the texture does not make it lighter or darker, so probably there is a problem with linear-nonlinear color space conversion.

android_mali_mipmaps_resize_test

Generally, I see good results with GLES3 rendering on Android, except this issue and another one, being slower rendering of polygons on Adreno GPUs (I have not filed this one yet, testing now if draw call batching brings any improvement).
GLES3 allows us to use some more advanced shading, and since our app is cross-platform (iOS-first, now adding Android), it is pretty reasonable for us to stick with GLES3, which also performs nice on iOS.

The problem is not 3.2.4-specific, I have encountered it as early as in 3.2.3, most likely even in 3.2.1.

@ghost
Copy link

ghost commented Dec 3, 2021

I have the same issue on the 3.4.stable.official version with Huawei Honor 9 STF-L09 (android 9, emui 9.1.0, Mali-G71 MP8) and Huawei Mate 20 lite SNE-LX1 (android 10, emui 10.0.0, Mali-G51 MP4).

@Calinou Calinou added this to the 3.5 milestone Dec 3, 2021
@ghost
Copy link

ghost commented Dec 4, 2021

It does not happen, however, with Samsung Galaxy A5 (2017) SM-A520F (android 11 [LineageOS 18.1], Mali-T830 MP3) on the 3.4.stable.official version.

@benjarmstrong
Copy link
Contributor

I can reproduce this issue on the Samsung Galaxy S10 SM-G973F (Mali-G76 MP12, Android 9) with Godot v3.4.2.stable.official

@grayhaze
Copy link

grayhaze commented Jul 3, 2022

I also just ran into this with a Galaxy S10, using 3.5 rc 5. Is there any update on what might be causing this and any workarounds?

@lawnjelly
Copy link
Member

lawnjelly commented Jul 3, 2022

Resizing the texture does not make it lighter or darker, so probably there is a problem with linear-nonlinear color space conversion.

Just to re-iterate what I was asking with more detail:

You could test this by repeating the experiment with the sprite getting smaller and smaller and seeing if it goes darker to black.

For the test to work you should not resize the texture. The texture should be exactly the same, instead you should resize the Sprite, by using scaling. The idea is to get OpenGL to use different mipmaps. If it goes black at some point, then it suggests the mipmaps are not being generated at all (all black), but if the color is always this same darkened version of the original, then it suggests an sRGB / linear type issue.

Apologies if this is what was tested before, but it wasn't clear from the reply by @sergey-khrykov . I'm also asking this because in #61565 it looks more like the mipmaps are not being generated at all, so it would be nice to see if these two issues are the same.

Another thing to try is uncompressed texture.

This could also be a case where we need to generate mipmaps on the CPU rather than rely on glGenerateMipmap (I've heard of this problem before with implementations not supporting it correctly):
https://stackoverflow.com/questions/43967363/glgeneratemipmap-with-gl-srgb8-in-opengl-es-3-results-in-black-texture

Good news is I have this reproducing on my Samsung Galaxy S6 Lite Tablet, so it should make it easier to investigate.

@grayhaze
Copy link

grayhaze commented Jul 3, 2022

For the test to work you should not resize the texture. The texture should be exactly the same, instead you should resize the Sprite, by using scaling. The idea is to get OpenGL to use different mipmaps. If it goes black at some point, then it suggests the mipmaps are not being generated at all (all black), but if the color is always this same darkened version of the original, then it suggests an sRGB / linear type issue.

I just retested this as a basic project using GLES3 on a Samsung Galaxy S10 in 3.5 rc 5, making sure to just use scaling on the sprite and not the image itself, and still the same result. No mipmap levels go black, and the image doesn't get any darker the smaller the sprite is scaled.

GLES3 Mipmap Test

@grayhaze
Copy link

grayhaze commented Jul 3, 2022

From testing with my game, it seems to me that maybe the image is being rendered with the top 128 levels of RGB, rather than the full 256 levels, then stretching them out to 256. This makes any colour value at 127 or less just get changed to 0, and anything above gets effectively double contrast.

Edit: Okay, that proved to be incorrect. Here's a better example of the effect on colour values.

GLES3 Mipmap Test 2

@lawnjelly
Copy link
Member

Testing it now on my tablet.

  • Setting the import setting for icon_mipmap.png explicitly to sRGB disable doesn't fix it.
  • When sRGB is set to enable in the import section for icon.png, the left hand side looks exactly the same as the right, which would seem to be suggestive of it being an sRGB / linear issue.

@wacyym
Copy link

wacyym commented Oct 15, 2022

Tested in Godot 3.5, on Samsung Galaxy a32 (sm-a325f, GPU Mali-G52 MC2), and has this problem too.
Is there any workaround available?

@grayhaze
Copy link

Tested in Godot 3.5, on Samsung Galaxy a32 (sm-a325f, GPU Mali-G52 MC2), and has this problem too. Is there any workaround available?

Currently the only workaround is to use GLES2 for Android builds. This is going to become a problem with Godot 4.x though, as they're dropping GLES2 support in the first releases.

@Calinou Calinou changed the title Darker textures on Android devices with Mali graphics when using Mipmaps Darker textures on Android devices with Mali graphics when using Mipmaps (GLES3 only) Oct 15, 2022
@Calinou
Copy link
Member

Calinou commented Oct 15, 2022

Tested in Godot 3.5, on Samsung Galaxy a32 (sm-a325f, GPU Mali-G52 MC2), and has this problem too. Is there any workaround available?

The fix likely involves detecting whether a Mali GPU is used, then converting linear to sRGB in the shader, but only for mipmapped textures. This likely requires core changes to be done, unless you manage to do this using VisualServer.get_video_adapter_vendor() to detect Mali GPUs and adjust custom shaders accordingly.

@wacyym
Copy link

wacyym commented Oct 16, 2022

Thanks, i found linear to sRGB shader and seems its work well.
Maybe it will be helpful for someone who search for Godot-ready workaround:

shader_type canvas_item;

vec4 fromLinear(vec4 linearRGB)
{
    bvec4 cutoff = lessThan(linearRGB, vec4(0.0031308));
    vec4 higher = vec4(1.055)*pow(linearRGB, vec4(1.0/2.4)) - vec4(0.055);
    vec4 lower = linearRGB * vec4(12.92);
    return mix(higher, lower, cutoff);
}
void fragment()
{
  COLOR = fromLinear(texture(TEXTURE, UV)); 
}

@grayhaze
Copy link

It's a nice workaround, but cumbersome in that you'd need to add it to every single textured node in your game, and only if the user is on a Mali GPU. Given this primarily affects older Android devices, all those shaders will stretch the device too. I'm really hoping a proper fix can be added to the engine soon.

@wacyym
Copy link

wacyym commented Oct 16, 2022

Yes, unfortunately the workaround is not the ideal solution of this problem anyway.

but cumbersome in that you'd need to add it to every single textured node in your game

Another workaround that comes to mind is:

  1. Turn on mipmaps on all textures, UI textures, fonts
  2. add CanvasLayer + ColorRect nodes
  3. Add to ColorRect node same shader material as above, but for screen texture/UV:
void fragment()
{
COLOR = fromLinear(texture(SCREEN_TEXTURE, SCREEN_UV)); 
}

And wait for proper engine fix...

@lawnjelly lawnjelly modified the milestones: 3.5, 3.x Dec 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants