cc.DrawNode + Custom Shader glUniform1f issue on native

Environment :

cocos2d-x 3.14.1

The code is very simple first create a cc.DrawNode instance and draw a something in a empty scene:

var drawNode = new cc.DrawNode();
this.addChild(drawNode);
drawNode.setPosition(cc.winSize.width / 2, cc.winSize.height / 2);
drawNode.drawDot(cc.p(0, 0), 150, cc.color(255, 0, 0, 255));

and there will be a dot at the center of the screen in red and this works correctly on both web and native:

Then, apply a custom shader to the cc.DrawNode instance:

var shaderProgram = new cc.GLProgram(
    "res/shader/shader_vert_drawnode.vsh",
    "res/shader/shader_frag_drawnode.fsh"
);
shaderProgram.link();
shaderProgram.updateUniforms();
drawNode.setShaderProgram(shaderProgram);

and the shader is very simple:

// .vert 
attribute vec4 a_position;

void main()
{
    gl_Position = CC_PMatrix * CC_MVMatrix * a_position;
}

// .frag
void main()
{
    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
}

After doing this, the red dot will become a blue rect and this alse works correctly on both web and native:

And the last step, add a uniform to the frag shader named u_test and set the value from the code:

// .frag
uniform float u_testValue;

void main()
{
    gl_FragColor = vec4(0.0, u_testValue, 0.0, 1.0);
}

and set the value from code :

var shaderProgram = new cc.GLProgram(
    "res/shader/shader_vert_drawnode.vsh",
    "res/shader/shader_frag_drawnode.fsh"
);
shaderProgram.link();
shaderProgram.updateUniforms();
drawNode.setShaderProgram(shaderProgram);
shaderProgram.use();

shaderProgram.setUniformLocationWith1f(
    shaderProgram.getUniformLocationForName("u_testValue"),
    1.0
);

But, this time, only in web I can get a green rect as expected :

In native, there will be nothing drawn on the screen and the reason is the rect is black which means the u_test value is not passed to the frag shader.

I found a post on this topic here:

And two issues on github that are already fixed:

I debugged the demo on native a little bit and here is what I think is weird :

[1] the onDraw function in DrawNode calls

getGLProgramState()->apply(transform);

[2] the apply function handle the uniforms

applyUniforms();

[3] where the uniforms will be applied:

void GLProgramState::applyUniforms()
{
    // set uniforms
    updateUniformsAndAttributes();
    for(auto& uniform : _uniforms) {
        uniform.second.apply();
    }
}

[4] and in my demo, there is one uniform in _uniforms that is u_test that need to be set and the code continues to

void UniformValue::apply()
{
    // ...
    case GL_FLOAT:
    _glprogram->setUniformLocationWith1f(_uniform->location, _value.floatValue);
    break;
}

[5] And I thinks here is where the issue happens, the updated value is true after calling the updateUniformLocation function but the value of f1 is 0 which I think should be 1.

void GLProgram::setUniformLocationWith1f(GLint location, GLfloat f1)
{
    bool updated = updateUniformLocation(location, &f1, sizeof(f1)*1);

    if (updated)
    {
        glUniform1f( (GLint)location, f1);
    }
}

This is where I get so far the issue I still can not figure out what went wrong here , any suggestion will be appreciated, thanks :slight_smile: