diff options
Diffstat (limited to 'src/effects/private/qgfxshaderbuilder.cpp')
-rw-r--r-- | src/effects/private/qgfxshaderbuilder.cpp | 293 |
1 files changed, 233 insertions, 60 deletions
diff --git a/src/effects/private/qgfxshaderbuilder.cpp b/src/effects/private/qgfxshaderbuilder.cpp index d1902a2..22975b5 100644 --- a/src/effects/private/qgfxshaderbuilder.cpp +++ b/src/effects/private/qgfxshaderbuilder.cpp @@ -60,6 +60,7 @@ #endif QGfxShaderBuilder::QGfxShaderBuilder() + : m_coreProfile(false) { // The following code makes the assumption that an OpenGL context the GUI // thread will get the same capabilities as the render thread's OpenGL @@ -82,6 +83,7 @@ QGfxShaderBuilder::QGfxShaderBuilder() int components; gl->glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &components); m_maxBlurSamples = components / 2.0; + m_coreProfile = context.format().profile() == QSurfaceFormat::CoreProfile; } else { int floats; gl->glGetIntegerv(GL_MAX_VARYING_FLOATS, &floats); @@ -182,6 +184,15 @@ static void qgfx_declareBlurVaryings(QByteArray &shader, QGfxGaussSample *s, int } } +static void qgfx_declareCoreBlur(QByteArray &shader, const QByteArray& direction, QGfxGaussSample *s, int samples) +{ + for (int i=0; i<samples; ++i) { + shader += direction + " vec2 "; + shader += s[i].name; + shader += ";\n"; + } +} + static void qgfx_buildGaussSamplePoints(QGfxGaussSample *p, int samples, int radius, qreal deviation) { @@ -259,6 +270,38 @@ QByteArray qgfx_gaussianVertexShader(QGfxGaussSample *p, int samples) return shader; } +QByteArray qgfx_gaussianVertexCoreShader(QGfxGaussSample *p, int samples) +{ + QByteArray shader; + shader.reserve(1024); + shader += "#version 150 core\n" + "in vec4 qt_Vertex;\n" + "in vec2 qt_MultiTexCoord0;\n\n" + "uniform mat4 qt_Matrix;\n" + "uniform float spread;\n" + "uniform vec2 dirstep;\n\n"; + + qgfx_declareCoreBlur(shader, "out", p, samples); + + shader += "\nvoid main() {\n" + " gl_Position = qt_Matrix * qt_Vertex;\n\n"; + + for (int i=0; i<samples; ++i) { + shader += " "; + shader += p[i].name; + shader += " = qt_MultiTexCoord0"; + if (p[i].pos != 0.0) { + shader += " + spread * dirstep * float("; + shader += QByteArray::number(p[i].pos); + shader += ')'; + } + shader += ";\n"; + } + + shader += "}\n"; + + return shader; +} QByteArray qgfx_gaussianFragmentShader(QGfxGaussSample *p, int samples, bool alphaOnly) { @@ -307,6 +350,182 @@ QByteArray qgfx_gaussianFragmentShader(QGfxGaussSample *p, int samples, bool alp return shader; } +QByteArray qgfx_gaussianFragmentCoreShader(QGfxGaussSample *p, int samples, bool alphaOnly) +{ + QByteArray shader; + shader.reserve(1024); + shader += "#version 150 core\n" + "uniform sampler2D source;\n" + "uniform float qt_Opacity;\n"; + + if (alphaOnly) { + shader += "uniform vec4 color;\n" + "uniform float thickness;\n"; + } + + shader += "out vec4 fragColor;\n"; + + qgfx_declareCoreBlur(shader, "in", p, samples); + + shader += "\nvoid main() {\n" + " fragColor = "; + if (alphaOnly) + shader += "mix(vec4(0), color, clamp(("; + else + shader += "("; + + qreal sum = 0; + for (int i=0; i<samples; ++i) + sum += p[i].weight; + + for (int i=0; i<samples; ++i) { + shader += "\n + float("; + shader += QByteArray::number(p[i].weight / sum); + shader += ") * texture(source, "; + shader += p[i].name; + shader += ")"; + if (alphaOnly) + shader += ".a"; + } + + shader += "\n )"; + if (alphaOnly) + shader += "/thickness, 0.0, 1.0))"; + shader += "* qt_Opacity;\n}"; + + return shader; +} + +static QByteArray qgfx_fallbackVertexShader() +{ + return "attribute highp vec4 qt_Vertex;\n" + "attribute highp vec2 qt_MultiTexCoord0;\n" + "uniform highp mat4 qt_Matrix;\n" + "varying highp vec2 qt_TexCoord0;\n" + "void main() {\n" + " gl_Position = qt_Matrix * qt_Vertex;\n" + " qt_TexCoord0 = qt_MultiTexCoord0;\n" + "}\n"; +} + +static QByteArray qgfx_fallbackCoreVertexShader() +{ + return "#version 150 core\n" + "in vec4 qt_Vertex;\n" + "in vec2 qt_MultiTexCoord0;\n" + "uniform mat4 qt_Matrix;\n" + "out vec2 qt_TexCoord0;\n" + "void main() {\n" + " gl_Position = qt_Matrix * qt_Vertex;\n" + " qt_TexCoord0 = qt_MultiTexCoord0;\n" + "}\n"; +} + +static QByteArray qgfx_fallbackFragmentShader(int requestedRadius, qreal deviation, bool masked, bool alphaOnly) +{ + QByteArray fragShader; + if (masked) + fragShader += "uniform mediump sampler2D mask;\n"; + fragShader += + "uniform highp sampler2D source;\n" + "uniform lowp float qt_Opacity;\n" + "uniform mediump float spread;\n" + "uniform highp vec2 dirstep;\n"; + if (alphaOnly) { + fragShader += "uniform lowp vec4 color;\n" + "uniform lowp float thickness;\n"; + } + fragShader += + "\n" + "varying highp vec2 qt_TexCoord0;\n" + "\n" + "void main() {\n"; + if (alphaOnly) + fragShader += " mediump float result = 0.0;\n"; + else + fragShader += " mediump vec4 result = vec4(0);\n"; + fragShader += " highp vec2 pixelStep = dirstep * spread;\n"; + if (masked) + fragShader += " pixelStep *= texture2D(mask, qt_TexCoord0).a;\n"; + + float wSum = 0; + for (int r=-requestedRadius; r<=requestedRadius; ++r) { + float w = qgfx_gaussian(r, deviation); + wSum += w; + fragShader += " result += float("; + fragShader += QByteArray::number(w); + fragShader += ") * texture2D(source, qt_TexCoord0 + pixelStep * float("; + fragShader += QByteArray::number(r); + fragShader += "))"; + if (alphaOnly) + fragShader += ".a"; + fragShader += ";\n"; + } + fragShader += " const mediump float wSum = float("; + fragShader += QByteArray::number(wSum); + fragShader += ");\n" + " gl_FragColor = "; + if (alphaOnly) + fragShader += "mix(vec4(0), color, clamp((result / wSum) / thickness, 0.0, 1.0)) * qt_Opacity;\n"; + else + fragShader += "(qt_Opacity / wSum) * result;\n"; + fragShader += "}\n"; + + return fragShader; +} + +static QByteArray qgfx_fallbackCoreFragmentShader(int requestedRadius, qreal deviation, bool masked, bool alphaOnly) +{ + QByteArray fragShader = "#version 150 core\n"; + if (masked) + fragShader += "uniform sampler2D mask;\n"; + fragShader += + "uniform sampler2D source;\n" + "uniform float qt_Opacity;\n" + "uniform float spread;\n" + "uniform vec2 dirstep;\n"; + if (alphaOnly) { + fragShader += "uniform vec4 color;\n" + "uniform float thickness;\n"; + } + fragShader += + "out vec4 fragColor;\n" + "in vec2 qt_TexCoord0;\n" + "\n" + "void main() {\n"; + if (alphaOnly) + fragShader += " float result = 0.0;\n"; + else + fragShader += " vec4 result = vec4(0);\n"; + fragShader += " vec2 pixelStep = dirstep * spread;\n"; + if (masked) + fragShader += " pixelStep *= texture(mask, qt_TexCoord0).a;\n"; + + float wSum = 0; + for (int r=-requestedRadius; r<=requestedRadius; ++r) { + float w = qgfx_gaussian(r, deviation); + wSum += w; + fragShader += " result += float("; + fragShader += QByteArray::number(w); + fragShader += ") * texture(source, qt_TexCoord0 + pixelStep * float("; + fragShader += QByteArray::number(r); + fragShader += "))"; + if (alphaOnly) + fragShader += ".a"; + fragShader += ";\n"; + } + fragShader += " const float wSum = float("; + fragShader += QByteArray::number(wSum); + fragShader += ");\n" + " fragColor = "; + if (alphaOnly) + fragShader += "mix(vec4(0), color, clamp((result / wSum) / thickness, 0.0, 1.0)) * qt_Opacity;\n"; + else + fragShader += "(qt_Opacity / wSum) * result;\n"; + fragShader += "}\n"; + + return fragShader; +} QVariantMap QGfxShaderBuilder::gaussianBlur(const QJSValue ¶meters) { @@ -323,73 +542,27 @@ QVariantMap QGfxShaderBuilder::gaussianBlur(const QJSValue ¶meters) QVariantMap result; if (samples > m_maxBlurSamples || masked || fallback) { - QByteArray fragShader; - if (masked) - fragShader += "uniform mediump sampler2D mask;\n"; - fragShader += - "uniform highp sampler2D source;\n" - "uniform lowp float qt_Opacity;\n" - "uniform mediump float spread;\n" - "uniform highp vec2 dirstep;\n"; - if (alphaOnly) { - fragShader += "uniform lowp vec4 color;\n" - "uniform lowp float thickness;\n"; - } - fragShader += - "\n" - "varying highp vec2 qt_TexCoord0;\n" - "\n" - "void main() {\n"; - if (alphaOnly) - fragShader += " mediump float result = 0.0;\n"; - else - fragShader += " mediump vec4 result = vec4(0);\n"; - fragShader += " highp vec2 pixelStep = dirstep * spread;\n"; - if (masked) - fragShader += " pixelStep *= texture2D(mask, qt_TexCoord0).a;\n"; - - float wSum = 0; - for (int r=-requestedRadius; r<=requestedRadius; ++r) { - float w = qgfx_gaussian(r, deviation); - wSum += w; - fragShader += " result += float("; - fragShader += QByteArray::number(w); - fragShader += ") * texture2D(source, qt_TexCoord0 + pixelStep * float("; - fragShader += QByteArray::number(r); - fragShader += "))"; - if (alphaOnly) - fragShader += ".a"; - fragShader += ";\n"; + + if (m_coreProfile) { + result[QStringLiteral("fragmentShader")] = qgfx_fallbackCoreFragmentShader(requestedRadius, deviation, masked, alphaOnly); + result[QStringLiteral("vertexShader")] = qgfx_fallbackCoreVertexShader(); + } else { + result[QStringLiteral("fragmentShader")] = qgfx_fallbackFragmentShader(requestedRadius, deviation, masked, alphaOnly); + result[QStringLiteral("vertexShader")] = qgfx_fallbackVertexShader(); } - fragShader += " const mediump float wSum = float("; - fragShader += QByteArray::number(wSum); - fragShader += ");\n" - " gl_FragColor = "; - if (alphaOnly) - fragShader += "mix(vec4(0), color, clamp((result / wSum) / thickness, 0.0, 1.0)) * qt_Opacity;\n"; - else - fragShader += "(qt_Opacity / wSum) * result;\n"; - fragShader += "}\n"; - result[QStringLiteral("fragmentShader")] = fragShader; - - result[QStringLiteral("vertexShader")] = - "attribute highp vec4 qt_Vertex;\n" - "attribute highp vec2 qt_MultiTexCoord0;\n" - "uniform highp mat4 qt_Matrix;\n" - "varying highp vec2 qt_TexCoord0;\n" - "void main() {\n" - " gl_Position = qt_Matrix * qt_Vertex;\n" - " qt_TexCoord0 = qt_MultiTexCoord0;\n" - "}\n"; return result; } QVarLengthArray<QGfxGaussSample, 64> p(samples); qgfx_buildGaussSamplePoints(p.data(), samples, radius, deviation); - result[QStringLiteral("fragmentShader")] = qgfx_gaussianFragmentShader(p.data(), samples, alphaOnly); - result[QStringLiteral("vertexShader")] = qgfx_gaussianVertexShader(p.data(), samples); - + if (m_coreProfile) { + result[QStringLiteral("fragmentShader")] = qgfx_gaussianFragmentCoreShader(p.data(), samples, alphaOnly); + result[QStringLiteral("vertexShader")] = qgfx_gaussianVertexCoreShader(p.data(), samples); + } else { + result[QStringLiteral("fragmentShader")] = qgfx_gaussianFragmentShader(p.data(), samples, alphaOnly); + result[QStringLiteral("vertexShader")] = qgfx_gaussianVertexShader(p.data(), samples); + } return result; } |