#StackBounty: #libgdx #android #shaders #glsl #fragment-shader Weird shader behavior on different devices

Bounty: 50

I’m trying to combine an ordinary shader with a Single Distance Field shader (for fonts and scalable icons) into one shader program.
The idea is simple – if uv.x is less than 1.0, it is drawn as usual, and if more than 1.0 then SDF is used (using GL_REPEAT uv.x and uv.x + 1.0 look similar)

Fragment shader code:

precision mediump float;
precision mediump int;

uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_texCoords;
uniform float u_smoothing;

void main() {
  // SDF
  float distance = texture2D(u_texture, v_texCoords).a;
  float alpha = smoothstep(0.5 - u_smoothing, 0.5 + u_smoothing, distance);
  vec4 sdfColor = vec4(v_color.rgb, alpha * v_color.a);

  // Regular
  vec4 regularColor = v_color * texture2D(u_texture, v_texCoords);

  // Making a choice
  gl_FragColor = mix(regularColor, sdfColor, step(1.0, v_texCoords.x));
}

It works and looks fine on desktop and most of popular Android devices but not on Oneplus One, Xiaomi Redmi 4A and Moto G devices.
This is how it must look like and how it actually looks on desktops and many other devices (Samsung S8, Xiaomi 3s, Pixel 2 etc.):
Normaly rendered

And this is how it looks like on Moto G, Oneplus One & some others:
enter image description here

I tried to find a problematic function, but without success.
First I tried to use the usual condition instead of mix():

void main() {
  // ...

  // Making a choice
  // gl_FragColor = mix(regularColor, sdfColor, step(1.0, v_texCoords.x));
  if (v_texCoords.x < 1.0) {
    gl_FragColor = regularColor;
  } else {
    gl_FragColor = sdfColor;
  }
}

Nothing has changed – this shader works well on most devices and is still bad on some others.
I decided that the problem lies in the calculation of sdfColor and changed fragment shader code a bit to check:

void main() {
  // ...

  // Making a choice
  gl_FragColor = sdfColor;  // Always using SDF
}

But this shader worked equally on all devices, which indicates that sdfColor is calculated correctly. This next screenshot was taken on Moto G:
enter image description here

Then I tried to differentiate the regions of textures with different colors:

void main() {
  // ...

  // Making a choice
  if (v_texCoords.x < 1.0) {
    gl_FragColor = regularColor;
    gl_FragColor.r = 1.0;  // Full red channel for regular texture regions without SDF (UV.x < 1.0)
  } else {
    gl_FragColor = sdfColor;
    gl_FragColor.r = 0.0;  // No red channel for SDF 
  }
}

On Moto G and other devices it looks as expected:
enter image description here

It seems to me that using mix() or conditions implicitly changes something else.


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.