V4.0 glsl-optimizer for Metal and some other issues

V4.0 glsl-optimizer for Metal and some other issues


I wanted to reply to this thread but unfortunately it’s closed :frowning:

Anw, thank you cocos2d-x team for bringing Metal support in v4.0! I have been using it and it works fine out of the box.
However, i have bump into an issue with my custom shaders. For example in this code snippet.

void main()
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;

    vec2 flowDir = vec2(texture2D(u_flowTexture, a_texCoord).rg);
    vec4 pos = a_position;
    pos.xy -= flowDir * u_time;
    gl_Position = u_MVPMatrix * pos;

After going through the glsl-optimiser, the vec2 flowDir is swapped with a type of half4 instead of float4. And since gl_Position underwent some operation with vec4 pos, which underwent an operation with flowDir, this resulted in gl_Position being declared as a half4 and not float4 and this will cause the Metal shader to fail to compile because vertex shader has to return a float4 gl_Position.

Basically, if the gl_Position is calculated from anything that derives from a variable that derives from a half, it will have the precision reduced to half instead of float. And I notice that anything that results from texture2D operation always result in a half.

Has anybody came across this issue and found a solution for it?

I had a temporary fix for this on a leaner project, whereby I have a separate file for the Metal shader that I manually corrected the variable type. But I had to perform some edit to the engine’s renderer codes so that it takes in a separate file.
But I don’t think this is a viable solution when it comes to a big project. The ideal case is to manage just 1 file for each shader instead of having to manage different shader language versions of it.

I’m a new user of the v4.0 GLSL-optimizer based on Cocos2D-x, I can’t figure out why I use GLSL3.00, it works, but when I use GLSL1.00, ’ const char* metalShader = glslopt_get_output(glslShader);’ will return null, while ’ glslopt_shader* glslShader = glslopt_optimize(mCompilier, shaderType, mSource.c_str(), 0);’ is always works.

Hi @liangzi10101, you have any code snippet to show how do you set GLSL1.00 or 3.00 in code?
and in what ocassion do you need GLSL1.00? How about just use OpenGL 2?

Actually, I just use glsl-optimizer like this:

mCompilier = glslopt_initialize(kGlslTargetMetal);
glslopt_shader_type shaderType = mType == GFXShaderType::Vertex ?
kGlslOptShaderVertex : kGlslOptShaderFragment;

glslopt_shader* glslShader = glslopt_optimize(mCompilier, shaderType, mResult.data(), 0);
if (glslShader) {
    const char* metalShader = glslopt_get_output(glslShader);
    if (!metalShader) {
        NSLog(@"[Shader Error] : Can not get metal shader:\n");
        return Status::Error;

So, metalShader is NULL when ‘mResult.data()’ is GLSL1.00, but it can work when ‘mResult.data()’ change to GLSL3.00, T_T.
The occassion is I want to use GLSL1.00 to match the standard of WebGL1

Hmm… i’ve been using glsl #version 100 shaders from cocos2d-x and there is no problem.
Is there any error message?
And when you change from 3.00 to 1.00, did you change the in / out to attributes / varying ?