[SOLVED] Unable to Use GLSL Extensions in Fragment Shader

I need to use #extension GL_OES_standard_derivatives:enable in a few fragment shaders, but I’m running into a problem on Android devices that only support medium precision floating point. The issue is that the extension directive must occur before any other non-preprocessor instructions so naturally I put the directive at the beginning of the file, but when the Android device doesn’t support high precision floats jME puts precision mediump float; at the top of the shader, above the extension directive, causing shader compilation to fail with Extension directive must occur before any non-preprocessor tokens.

So how does one go about using GLSL extensions in jME?

1 Like

I was able to solve this issue for my app. My solution may not be the best for everyone, but it works for me because I already have precision mediump float; or precision highp float; in my shaders where necessary.

I re-compiled jME3-core with the following change to GLRenderer:

if (source.getType() == ShaderType.Fragment
        && !source.getSource().contains("precision mediump float;")
        && !source.getSource().contains("precision highp float;")) {
    // GLES2 requires precision qualifier.
    stringBuf.append("precision mediump float;\n");
}

Previously this was simply:

if (source.getType() == ShaderType.Fragment) {
    // GLES2 requires precision qualifier.
    stringBuf.append("precision mediump float;\n");
}

P.S. Testing this through Amazon’s app testing service shows green check marks across the board :smiley:

The thing is your shader can’t work on desktop anymore. It may be not an issue in your situation, though.
We had another issue with extensions not being put at the beginning of the shader IMO we should have something that parses the code for extensions and put them at the beginning of the file.
I made a change in the shader node generation in this regard, but I didn’t test on android, so the issue might still be there…

@Momoko_Fan, we really should address this issue.

Technically it will still work on desktop because I use

#ifdef USEAA
    #ifdef GL_ES
        #extension GL_OES_standard_derivatives:enable
        #ifdef GL_FRAGMENT_PRECISION_HIGH
            precision highp float;
        #else
            precision mediump float;
        #endif
    #endif
#else
    #ifdef GL_ES
        precision mediump float;
    #endif
#endif

This way it only specifies the precision if it’s running on OpenGL ES, but yeah the change to GLRenderer was just a quick job meant to support just the Android app I’m working on right now.

Err actually just the Android app I finished a couple of hours ago ;).

1 Like

I noticed that the code causing this issue is still present in the master branch at 1216:

if (source.getType() == ShaderType.Fragment) {
    // GLES2 requires precision qualifier.
    stringBuf.append("precision mediump float;\n");
}

How I’ve ultimately fixed this was to get rid of that entirely and edit all the shader files included with jME adding the following at the top of each:

#ifdef GL_ES
    precision mediump float;
#endif

I’m not sure if that would be a viable long term solution for jMonkeyEngine, but it should be rather performance friendly and it would allow each shader to specify medium or high precision as needed. The only issue, I think, is that it’d break compatibility with older custom shaders when running on Android or iOS if they don’t specify a floating point precision.

mhh you still have the issue?
Because on master there has been a change to always put extensions at the beginning of the shader.

I haven’t tested it with master, but I didn’t notice that. Although a couple of my shaders require high precision, does inserting precision mediump float; above a precision highp float; instruction cause it to use medium or high precision?

Well… I’d say high precision… but it can depend on the drivers, so basically android version and so on and so on…It may even crash…

Yeah, I’m thinking having both defined would be handled differently depending on the device. I noticed that even though the spec indicates extention directives must occur at the beginning of a shader some devices allowed it if it wasn’t at the beginning and some didn’t.

yep definitely…
that’s the curse of fragmentation