ClippingNode Doesn't Work With Alpha on Some Specific Devices with Android 9?

Hello!

It’s my first time posting, so please let me know if I broke any forum rule or something. I will update/fix.

Recently some users of our app are reporting images not showing correctly. After some digging I found out it was ClippingNode not working as expected on the following devices with Android 9 (Pie).

Moto g(6) Play
Samsung Galaxy J4+
Samsung Galaxy J6+

One thing in common among them is they are all using Qualcomm Adreno 308 GPU.

Attaching two images: same code with different devices: Pixel 2 and Moto g(6) Play.


And here’s the code I’m using for the test above.

    auto clippingNode = ClippingNode::create();
    auto cloud = Sprite::create("cloud.png");
    clippingNode->addChild(cloud);
    clippingNode->setStencil(Node::create());
    clippingNode->setAlphaThreshold(0);
    addChild(clippingNode, 10);
    clippingNode->setPosition(getContentSize() * 0.5f);
    auto brush = Sprite::create("brush.png");
    clippingNode->getStencil()->addChild(brush);

I’m wondering if anyone is having similar issues. Any suggestions / guides will be appreciated. Current cocos2d-x we are using is 3.16, but I have tried upgrading it to 3.17.2, which didn’t help.

Sorry, i am not in office today. I have forwarded it to supporting team, and I will trace it too.

1 Like

Thank you!

Can you upload a sample? I make a simple demo and run on Mix2S (Android 9), but no present this issue.

What is the alpha range in brush.png?Maybe the precision that GLSL set no work well,you can set alpha threshold to 0.1f, and try.

1 Like

Thank you for your reply!

I tried changing the threshold to 0.1f, but still the same. Alpha range - it is either 1 or 0, please see “brush” below.

If possible, can you try testing on a device with Adreno 308 GPU please? Or one of the devices I listed above. (Moto g6 play, Galaxy j6+, or Galaxy j4+) Looks like Mix2S has Adreno 630.

Regarding the sample, what do you want me to upload? Will attach two images - “cloud” and “brush”. And also apk in case you prefer.

sprites.zip (185.0 KB)

MyTest-debug.apk.zip (4.8 MB)

Wonder if it has to do with any OpenGL depth/stencil configuration stuff. Maybe checking in that direction might help find something specific…

edit: Found this:

Wonder if this has any pertinent information for you. The device they had an issue with seems to also be an Adreno 3xx.

The problem was that the stencil buffer wasn't cleared correctly. It is necessary to set stencil mask glStencilMask(0xff) before calling glClear(GL_STENCIL_BUFFER_BIT) to clear all bits of stencil buffer. Some devices might ignore stencil mask and always use 0xff when clearing stencil buffer.

1 Like

Thank you for your suggestion! Will take a look at it. The issue I posted was fine on Android 8, and only happens on Android 9, so I’m guessing there’s something changed between 8 and 9, and some devices just can’t handle it yet.

@rlaghdejr have you fixed the issue? We found Adreno GPU also has problem when using depth texture. You can refer to https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/2d/CCRenderTexture.cpp#L726.

2 Likes

Hi @zhangxm, no I have not. Thank you for the reference! Any solutions / work-arounds to this issue? I have tried some myself, but still no luck :frowning:
Will try more tonight.

Yea, a work around is to use a custom shader instead that uses RGB data from the texture, and multiplies alpha from the mask and the texture, or replaces one with the other. You can find several examples around the net.

One example:

Using a shader will also let you mask with alpha/opacity which the ClippingNode cannot. ClippingNode uses a stencil only to cut out parts based on a threshold.

1 Like

The effect seems that stencil test takes effect, but the alpha test doesn’t work as expected. Can you just try alpha test on the devices?

1 Like

Hi, @zhangxm, do you mean just trying setOpacity, to see if alpha works on those devices? If so, yes i just tried, and alpha works fine those Adreno 308 GPU devices.

If you are talking about something else, can you please be more specific, please?

Hi @tdebock, thank you for the reference. I found that CCMask needs to be changed a lot to be compiled successfully, will also try making a custom shader as you suggested, it might take some time, though. Will give you an update.

1 Like

You can just piece apart the shader GLSL part, and follow the cocos logic into the newer syntax, whichever version you are using.

1 Like

@rlaghdejr i mean doing alpha test in shader, for example, when an alpha value less than some value, then discard it.

2 Likes

@zhangxm, yes with custom shader, i was able to do simple clippings and show clipped images without any issue on those Adreno 308 devices. Fragment shader is something like the following:

void main()
{
    // calculates texture coordinates for mask sprite
    float a = (((v_texCoord.x - 0.5) * texture_size.x + texture_pos.x - mask_pos.x) * cos_theta -
    ((v_texCoord.y - 0.5) * texture_size.y + texture_pos.y - mask_pos.y) * sin_theta) / mask_size.x;
    float b = (((v_texCoord.x - 0.5) * texture_size.x + texture_pos.x - mask_pos.x) * sin_theta +
    ((v_texCoord.y - 0.5) * texture_size.y + texture_pos.y - mask_pos.y) * cos_theta) / mask_size.y;

    // i passed bottom left point of the sprite, and calculated with center point of the sprite
    // now it moves to the bottom left corner again to fit 0~1 texture coordinates
    a = a + 0.5;
    b = b + 0.5;
    
    // get mask/masked sprite texture colors
    vec4 texColor = texture2D(u_texture, v_texCoord).rgba;
    vec4 maskColor = texture2D(u_mask, vec2(a, b)).rgba;
    
    // discards unwanted pixels
    if (a > 1.0 || a < 0.0 || b > 1.0 || b < 0.0)
        discard;
    
    // if at one pixel mask's alpha is greater than 0, we pick texColor
    // used 0.5 just to compare with the original mask sprite
    if (maskColor.a > 0.0)
        gl_FragColor = vec4(texColor.r, texColor.g, texColor.b, 0.5);
    else
        discard;
}

But now for me, I need to apply it to our game project, which is using 9-scale images and multiple-sprite clippings. I guess that’s another issue / problem, and currently trying to apply CCMask, which was suggested by @tdebock, to our project.

Thank you everyone for your help! Hopefully soon either cocos2d-x or android can have a patch regarding this issue. Will post another update when all fixes on my side are done, just wondering if I need to close or mark solutions to this post.

1 Like

@rlaghdejr it seems alpha test works. It is wired. But i can not find devices that uses Adreno 308 devices to reproduce the issue.

1 Like

@zhangxm, thank you for your help!

Just in case you need some logs, or you wanna try some fixes, i can definitely help test it on my side.

I will try it myself, too, when I have time for it.

We still haven’t been able to solve this issue even with updating to latest cocos game engine. Here is a list of devices that use Adreno 308: https://mobile.phonebunch.com/phone-filter/gpu/adreno-308/page/1/

@zhangxm here is a list of Adreno 308 devices.