Cocos4 - Shaders on a non metal device not working

I finally managed to get my cocos rebuild of the game of TestFlight last night. This morning one of my testers sent the first report. It looks like the shaders are not firing on a non metal device, or are not working correctly. The rendering is obviously working but you can see from the screenshot that the character is not rendering correctly, nor is the terrain. I have included a comparative screenshot running on my XR phone.

The users device is and iPad Air 2 running iOS 14.2

Any guidelines?

Not working

Working

Cocos2d-x v4 for iOS is compiled with the Metal renderer, so there is no runtime selection between OpenGL and Metal. If the device didn’t have the Metal API, then your app shouldn’t have worked at all.

It’s really strange though that it is rendering everything but the shaders. Are these custom shaders that aren’t working? Are the Cocos2d-x built-in shaders working?

It could be that there is shader code that may not be supported by those older devices, so you need to figure out what that is and change the code so it works on the lowest device version you’re willing to support. Once you do that it should also work on the newer devices.

Ok. That’s a little disappointing, hadn’t realised I was going to lose a certain level of devices.

How do I let iTunes Connect know that my app requires Metal? Is there a capability somewhere.

And last, here is the shader code… nothing complex…

uniform vec4 p_colour;
uniform float p_alpha  ;
uniform float p_fade  ;

#ifndef saturate
#define saturate(v) clamp(v, 0.0, 1.0)
#endif

void main()
{
    vec4 c = texture2D(u_texture, cc_FragTexCoord1).rgba;
    vec4 n;

    vec4 b = vec4( 0.0, 0.0, 0.0, 0.0 ) ;
        
    vec3 fragRGB = c.rgb; // current color

    // convert to non-PMA
    fragRGB = saturate(fragRGB / c.a);
    
    b.a = 1.0 - (c.a*p_fade) ;
    b.r = (p_colour.r * b.a) ;
    b.g = (p_colour.g * b.a) ;
    b.b = (p_colour.b * b.a) ;
    
    n.r = b.r + (fragRGB.r*(c.a*p_fade)) ;
    n.g = b.g + (fragRGB.g*(c.a*p_fade)) ;
    n.b = b.b + (fragRGB.b*(c.a*p_fade)) ;
    n.a = c.a * p_alpha;

    fragRGB = n.rgb * n.a; // Premultiply alpha
    gl_FragColor = vec4(fragRGB.rgb, n.a);

}

The good news is that I can replicate on an old iphone6 for dev. Again the app runs fine it’s just my shaders. What would be the best/easiest way to test some cocos shaders on my sprites?

Ah… I might be wrong I think these devices DO have metal it is supported on older devices than I thought. On iOS it looks like everything since 2013.

It looks more like a PMA issue. Something different on those devices as opposed to newer ones?

Turns out I need to add c.a check - not sure why it works without it on later devices.

uniform vec4 p_colour;
uniform float p_alpha  ;
uniform float p_fade  ;

#ifndef saturate
#define saturate(v) clamp(v, 0.0, 1.0)
#endif

void main()
{
    vec4 c = texture2D(u_texture, cc_FragTexCoord1).rgba;
    vec4 n;

    vec4 b = vec4( 0.0, 0.0, 0.0, 0.0 ) ;
        
    vec3 fragRGB = c.rgb; // current color

    // convert to non-PMA
    fragRGB = saturate(fragRGB / c.a);
    
   if(c.a!=0.0)
   {
        b.a = 1.0 - (c.a*p_fade) ;
        b.r = (p_colour.r * b.a) ;
        b.g = (p_colour.g * b.a) ;
        b.b = (p_colour.b * b.a) ;
    
        n.r = b.r + (fragRGB.r*(c.a*p_fade)) ;
        n.g = b.g + (fragRGB.g*(c.a*p_fade)) ;
        n.b = b.b + (fragRGB.b*(c.a*p_fade)) ;
        n.a = c.a * p_alpha;
    }
    fragRGB = n.rgb * n.a; // Premultiply alpha
    gl_FragColor = vec4(fragRGB.rgb, n.a);

}

Divide by zero errors won’t crash your shader, but the results are undefined, hence the check for alpha = 0.

Shouldn’t the if statement surround the saturate as well?

// convert to non-PMA
fragRGB = saturate(fragRGB / c.a);

Yes, arguably it should… but it didn’t seem to make a difference. It works with the if where it is, and not without it!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.