Qt World Summit: Submit your Presentation

[SOLVED]Qml OpenGL Shaders requirements

  • I made litle shaders example on Qml (QtQuick 2.2). It runs perfectly on my desktop. Then i deployed it on my phone (HTC One V, Android 4.1). All looks fine, but shader effect just draws pink rectangle instead of himself. Graphics processor on the phone Adreno 205, i believe. It supports OpenGL ES 2.0. So im interested if is it normal? Am i missing something? What is requirements of shaders?

  • Moderators

    On Desktop you are problably using OpenGL (not ES!) and on Android you are using OpenGL ES. They have different shader syntax.

  • Here is code, that i used:
    @ ShaderEffect {
    id: shader

        <some code>
        fragmentShader: "
            #define M_PI 3.1415926535897932384626433832795
            varying highp vec2 qt_TexCoord0;
            uniform lowp sampler2D source;
            uniform highp float range;
            uniform highp float maxRange;
            uniform highp float cX;
            uniform highp float cY;
            uniform highp float depth;
            uniform highp float shift;
            float f(float x)
                return -sin(x/M_PI*10);
            void main() {
                highp float x = qt_TexCoord0.x - cX;
                highp float y = qt_TexCoord0.y - cY;
                highp float r = sqrt( pow(y, 2) + pow(x, 2) );
                if ( r < (range - depth) || r > (range + depth) ) return;
                highp float ang;
                highp float dr;
                ang = atan(y/x);
                if (x < 0) ang += M_PI;
                highp float k = (r - range) / depth;
                dr = f(k) * depth * shift * (1 - (r/maxRange));
                highp float dx = dr * cos(ang);
                highp float dy = dr * sin(ang);
                highp vec4 texpixel = texture2D( source, vec2( qt_TexCoord0.x + 0, qt_TexCoord0.y + dy ) );
                gl_FragColor = texpixel;

    Can i use it on android? or what i need to use istead of it?

  • It should work, but try verifying your device with a simple shader first. (e.g. start with having nothing but the texture2D call, and once that's proven to work, try restoring the other calculations gradually)

  • Moderators


    Try using medium precision.

  • [quote author="p3c0" date="1398761747"]Hi,

    Try using medium precision.[/quote]

    I made all lowp, no result.

    varying highp vec2 qt_TexCoord0;
    uniform highp sampler2D src;

            void main(void)
                highp float x = qt_TexCoord0.x;
                highp float y = qt_TexCoord0.y;
                highp float dx = x * 0.1;
                highp vec4 texpixel = texture2D(src, vec2(x + dx, y) );
                gl_FragColor = texpixel;


    This looks fine. Looking for bad code...

  • It toke frome me 1.5 hours to find out, that type conversion do not working on my phone. Had to replace 3 to 3.0, 0 to 0.0 etc. But picture on the phone looks like this anyway >_<
    Shader itself looks fine, but not the picture under it... strange. Is it means phone just cant draw shaders properly?

  • Got it! there was another compiler difference. I always have to initialize gl_FragColor.
    This code works perfectly fine:
    @ #define M_PI 3.14

                varying highp vec2 qt_TexCoord0;
                uniform mediump sampler2D source;
                uniform lowp float range;
                uniform lowp float maxRange;
                uniform lowp float cX;
                uniform lowp float cY;
                uniform lowp float depth;
                uniform lowp float shift;
                float f(float x)
                    return -sin(x/M_PI*10.0);
                void main() {
                    lowp float x = qt_TexCoord0.x - cX;
                    lowp float y = qt_TexCoord0.y - cY;
                    lowp float r = sqrt( x*x + y*y );
                    lowp float dx;
                    lowp float dy;
                    if ( r > (range - depth * 3.0) && r < (range + depth) ) {
                        lowp float ang;
                        lowp float dr;
                        ang = atan(y/x);
                        if (x < 0.0) ang += M_PI;
                        lowp float k = (r - range) / depth;
                        dr = f(k) * depth * shift * (1.0 - (r/maxRange));
                        dx = dr * cos(ang);
                        dy = dr * sin(ang);
                    else {
                        dx = 0.0;
                        dy = 0.0;
                    lowp vec4 texpixel = texture2D( source, vec2( qt_TexCoord0.x + dx, qt_TexCoord0.y + dy ) );
                    gl_FragColor = texpixel;

    Thanks all for helping!

  • all of these are no surprise. whatever driver you're using on desktop, it sucks. likely it's nvidia, and they let just about any bad-behavior code go..

    if ( r < (range - depth) || r > (range + depth) ) return;

    ^ that should result in garbage data, which it did. either you always define gl_fragcolor, or you use discard and the fragment shader will not run for that fragment.(which could potentially result in garbage).

    same with the explicit type usages, one should always be explicit in any type conversions. it's just the way glsl is, and nvidia is very annoying in the sense that they allow broken code.

Log in to reply