src/opengl/gl2paintengineex/qglengineshadermanager.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qglengineshadermanager_p.h"
       
    43 #include "qglengineshadersource_p.h"
       
    44 
       
    45 #if defined(QT_DEBUG)
       
    46 #include <QMetaEnum>
       
    47 #endif
       
    48 
       
    49 
       
    50 QT_BEGIN_NAMESPACE
       
    51 
       
    52 static void qt_shared_shaders_free(void *data)
       
    53 {
       
    54     delete reinterpret_cast<QGLEngineSharedShaders *>(data);
       
    55 }
       
    56 
       
    57 Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
       
    58 
       
    59 QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
       
    60 {
       
    61     QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
       
    62     if (!p) {
       
    63         QGLShareContextScope scope(context);
       
    64         qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
       
    65     }
       
    66     return p;
       
    67 }
       
    68 
       
    69 const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = {
       
    70     0,0,0,0,0,0,0,0,0,0,
       
    71     0,0,0,0,0,0,0,0,0,0,
       
    72     0,0,0,0,0,0,0,0,0,0,
       
    73     0,0,0,0,0
       
    74 };
       
    75 
       
    76 QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
       
    77     : ctxGuard(context)
       
    78     , blitShaderProg(0)
       
    79     , simpleShaderProg(0)
       
    80 {
       
    81     memset(compiledShaders, 0, sizeof(compiledShaders));
       
    82 
       
    83 /*
       
    84     Rather than having the shader source array statically initialised, it is initialised
       
    85     here instead. This is to allow new shader names to be inserted or existing names moved
       
    86     around without having to change the order of the glsl strings. It is hoped this will
       
    87     make future hard-to-find runtime bugs more obvious and generally give more solid code.
       
    88 */
       
    89     static bool qglEngineShaderSourceCodePopulated = false;
       
    90     if (!qglEngineShaderSourceCodePopulated) {
       
    91 
       
    92         const char** code = qglEngineShaderSourceCode; // shortcut
       
    93 
       
    94         code[MainVertexShader] = qglslMainVertexShader;
       
    95         code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
       
    96         code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;
       
    97 
       
    98         code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
       
    99         code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
       
   100         code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
       
   101         code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
       
   102         code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader;
       
   103         code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader;
       
   104         code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader;
       
   105         code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader;
       
   106         code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader;
       
   107         code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader;
       
   108         code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader;
       
   109         code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader;
       
   110 
       
   111         code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO;
       
   112         code[MainFragmentShader_CM] = qglslMainFragmentShader_CM;
       
   113         code[MainFragmentShader_MO] = qglslMainFragmentShader_MO;
       
   114         code[MainFragmentShader_M] = qglslMainFragmentShader_M;
       
   115         code[MainFragmentShader_CO] = qglslMainFragmentShader_CO;
       
   116         code[MainFragmentShader_C] = qglslMainFragmentShader_C;
       
   117         code[MainFragmentShader_O] = qglslMainFragmentShader_O;
       
   118         code[MainFragmentShader] = qglslMainFragmentShader;
       
   119         code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;
       
   120 
       
   121         code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
       
   122         code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
       
   123         code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
       
   124         code[CustomImageSrcFragmentShader] = ""; // Supplied by app.
       
   125         code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
       
   126         code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
       
   127         code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
       
   128         code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader;
       
   129         code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader;
       
   130         code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader;
       
   131         code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
       
   132         code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;
       
   133 
       
   134         code[MaskFragmentShader] = qglslMaskFragmentShader;
       
   135         code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
       
   136         code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
       
   137         code[RgbMaskWithGammaFragmentShader] = ""; //###
       
   138 
       
   139         code[MultiplyCompositionModeFragmentShader] = ""; //###
       
   140         code[ScreenCompositionModeFragmentShader] = ""; //###
       
   141         code[OverlayCompositionModeFragmentShader] = ""; //###
       
   142         code[DarkenCompositionModeFragmentShader] = ""; //###
       
   143         code[LightenCompositionModeFragmentShader] = ""; //###
       
   144         code[ColorDodgeCompositionModeFragmentShader] = ""; //###
       
   145         code[ColorBurnCompositionModeFragmentShader] = ""; //###
       
   146         code[HardLightCompositionModeFragmentShader] = ""; //###
       
   147         code[SoftLightCompositionModeFragmentShader] = ""; //###
       
   148         code[DifferenceCompositionModeFragmentShader] = ""; //###
       
   149         code[ExclusionCompositionModeFragmentShader] = ""; //###
       
   150 
       
   151 #if defined(QT_DEBUG)
       
   152         // Check that all the elements have been filled:
       
   153         for (int i = 0; i < TotalShaderCount; ++i) {
       
   154             if (qglEngineShaderSourceCode[i] == 0) {
       
   155                 int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName");
       
   156                 QMetaEnum m = staticMetaObject.enumerator(enumIndex);
       
   157 
       
   158                 qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i)
       
   159                             << "(shader" << i << ") missing!";
       
   160             }
       
   161         }
       
   162 #endif
       
   163         qglEngineShaderSourceCodePopulated = true;
       
   164     }
       
   165 
       
   166     // Compile up the simple shader:
       
   167     simpleShaderProg = new QGLShaderProgram(context, this);
       
   168     compileNamedShader(MainVertexShader,              QGLShader::PartialVertexShader);
       
   169     compileNamedShader(PositionOnlyVertexShader,      QGLShader::PartialVertexShader);
       
   170     compileNamedShader(MainFragmentShader,            QGLShader::PartialFragmentShader);
       
   171     compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader);
       
   172     simpleShaderProg->addShader(compiledShaders[MainVertexShader]);
       
   173     simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]);
       
   174     simpleShaderProg->addShader(compiledShaders[MainFragmentShader]);
       
   175     simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]);
       
   176     simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   177     simpleShaderProg->link();
       
   178     if (!simpleShaderProg->isLinked()) {
       
   179         qCritical() << "Errors linking simple shader:"
       
   180                     << simpleShaderProg->log();
       
   181     }
       
   182 
       
   183     // Compile the blit shader:
       
   184     blitShaderProg = new QGLShaderProgram(context, this);
       
   185     compileNamedShader(MainWithTexCoordsVertexShader,     QGLShader::PartialVertexShader);
       
   186     compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader);
       
   187     compileNamedShader(MainFragmentShader,                QGLShader::PartialFragmentShader);
       
   188     compileNamedShader(ImageSrcFragmentShader,            QGLShader::PartialFragmentShader);
       
   189     blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]);
       
   190     blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]);
       
   191     blitShaderProg->addShader(compiledShaders[MainFragmentShader]);
       
   192     blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]);
       
   193     blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
       
   194     blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   195     blitShaderProg->link();
       
   196     if (!blitShaderProg->isLinked()) {
       
   197         qCritical() << "Errors linking blit shader:"
       
   198                     << blitShaderProg->log();
       
   199     }
       
   200 }
       
   201 
       
   202 void QGLEngineSharedShaders::shaderDestroyed(QObject *shader)
       
   203 {
       
   204     // Remove any shader programs which has this as the srcPixel shader:
       
   205     for (int i = 0; i < cachedPrograms.size(); ++i) {
       
   206         if (cachedPrograms.at(i).srcPixelFragShader == shader) {
       
   207             delete cachedPrograms.at(i).program;
       
   208             cachedPrograms.removeAt(i--);
       
   209         }
       
   210     }
       
   211 
       
   212     emit shaderProgNeedsChanging();
       
   213 }
       
   214 
       
   215 QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader::ShaderType type)
       
   216 {
       
   217     Q_ASSERT(name != CustomImageSrcFragmentShader);
       
   218     Q_ASSERT(name < InvalidShaderName);
       
   219 
       
   220     if (compiledShaders[name])
       
   221         return compiledShaders[name];
       
   222 
       
   223     QByteArray source = qglEngineShaderSourceCode[name];
       
   224     QGLShader *newShader = new QGLShader(type, ctxGuard.context(), this);
       
   225     newShader->compile(source);
       
   226 
       
   227 #if defined(QT_DEBUG)
       
   228     // Name the shader for easier debugging
       
   229     QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName"));
       
   230     newShader->setObjectName(QLatin1String(m.valueToKey(name)));
       
   231 #endif
       
   232 
       
   233     compiledShaders[name] = newShader;
       
   234     return newShader;
       
   235 }
       
   236 
       
   237 QGLShader *QGLEngineSharedShaders::compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type)
       
   238 {
       
   239     QByteArray source = stage->source();
       
   240     source += qglslCustomSrcFragmentShader;
       
   241 
       
   242     QGLShader *newShader = customShaderCache.object(source);
       
   243     if (newShader)
       
   244         return newShader;
       
   245 
       
   246     newShader = new QGLShader(type, ctxGuard.context(), this);
       
   247     newShader->compile(source);
       
   248     customShaderCache.insert(source, newShader);
       
   249 
       
   250     connect(newShader, SIGNAL(destroyed(QObject *)),
       
   251             this, SLOT(shaderDestroyed(QObject *)));
       
   252 
       
   253 #if defined(QT_DEBUG)
       
   254     // Name the shader for easier debugging
       
   255     QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName"));
       
   256     newShader->setObjectName(QLatin1String(m.valueToKey(CustomImageSrcFragmentShader)));
       
   257 #endif
       
   258 
       
   259     return newShader;
       
   260 }
       
   261 
       
   262 // The address returned here will only be valid until next time this function is called.
       
   263 QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
       
   264 {
       
   265     for (int i = 0; i < cachedPrograms.size(); ++i) {
       
   266         if (cachedPrograms[i] == prog)
       
   267             return &cachedPrograms[i];
       
   268     }
       
   269 
       
   270     cachedPrograms.append(prog);
       
   271     QGLEngineShaderProg &cached = cachedPrograms.last();
       
   272 
       
   273     // If the shader program's not found in the cache, create it now.
       
   274     cached.program = new QGLShaderProgram(ctxGuard.context(), this);
       
   275     cached.program->addShader(cached.mainVertexShader);
       
   276     cached.program->addShader(cached.positionVertexShader);
       
   277     cached.program->addShader(cached.mainFragShader);
       
   278     cached.program->addShader(cached.srcPixelFragShader);
       
   279     cached.program->addShader(cached.maskFragShader);
       
   280     cached.program->addShader(cached.compositionFragShader);
       
   281 
       
   282     // We have to bind the vertex attribute names before the program is linked:
       
   283     cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   284     if (cached.useTextureCoords)
       
   285         cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
       
   286     if (cached.useOpacityAttribute)
       
   287         cached.program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
       
   288 
       
   289     cached.program->link();
       
   290     if (!cached.program->isLinked()) {
       
   291         QLatin1String none("none");
       
   292         QLatin1String br("\n");
       
   293         QString error;
       
   294         error = QLatin1String("Shader program failed to link,")
       
   295 #if defined(QT_DEBUG)
       
   296             + br
       
   297             + QLatin1String("  Shaders Used:\n")
       
   298             + QLatin1String("    mainVertexShader = ")
       
   299             + (cached.mainVertexShader ?
       
   300                 cached.mainVertexShader->objectName() : none) + br
       
   301             + QLatin1String("    positionVertexShader = ")
       
   302             + (cached.positionVertexShader ?
       
   303                 cached.positionVertexShader->objectName() : none) + br
       
   304             + QLatin1String("    mainFragShader = ")
       
   305             + (cached.mainFragShader ?
       
   306                 cached.mainFragShader->objectName() : none) + br
       
   307             + QLatin1String("    srcPixelFragShader = ")
       
   308             + (cached.srcPixelFragShader ?
       
   309                 cached.srcPixelFragShader->objectName() : none) + br
       
   310             + QLatin1String("    maskFragShader = ")
       
   311             + (cached.maskFragShader ?
       
   312                 cached.maskFragShader->objectName() : none) + br
       
   313             + QLatin1String("    compositionFragShader = ")
       
   314             + (cached.compositionFragShader ?
       
   315                 cached.compositionFragShader->objectName() : none) + br
       
   316 #endif
       
   317             + QLatin1String("  Error Log:\n")
       
   318             + QLatin1String("    ") + cached.program->log();
       
   319         qWarning() << error;
       
   320         delete cached.program;
       
   321         cachedPrograms.removeLast();
       
   322         return 0;
       
   323     } else {
       
   324         // taking the address here is safe since
       
   325         // cachePrograms isn't resized anywhere else
       
   326         return &cached;
       
   327     }
       
   328 }
       
   329 
       
   330 QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
       
   331     : ctx(context),
       
   332       shaderProgNeedsChanging(true),
       
   333       srcPixelType(Qt::NoBrush),
       
   334       opacityMode(NoOpacity),
       
   335       maskType(NoMask),
       
   336       compositionMode(QPainter::CompositionMode_SourceOver),
       
   337       customSrcStage(0),
       
   338       currentShaderProg(0),
       
   339       customShader(0)
       
   340 {
       
   341     sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
       
   342     connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
       
   343 }
       
   344 
       
   345 QGLEngineShaderManager::~QGLEngineShaderManager()
       
   346 {
       
   347     //###
       
   348 }
       
   349 
       
   350 uint QGLEngineShaderManager::getUniformLocation(Uniform id)
       
   351 {
       
   352     QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
       
   353     if (uniformLocations.isEmpty())
       
   354         uniformLocations.fill(GLuint(-1), NumUniforms);
       
   355 
       
   356     static const char *uniformNames[] = {
       
   357         "imageTexture",
       
   358         "patternColor",
       
   359         "globalOpacity",
       
   360         "depth",
       
   361         "pmvMatrix",
       
   362         "maskTexture",
       
   363         "fragmentColor",
       
   364         "linearData",
       
   365         "angle",
       
   366         "halfViewportSize",
       
   367         "fmp",
       
   368         "fmp2_m_radius2",
       
   369         "inverse_2_fmp2_m_radius2",
       
   370         "invertedTextureSize",
       
   371         "brushTransform",
       
   372         "brushTexture"
       
   373     };
       
   374 
       
   375     if (uniformLocations.at(id) == GLuint(-1))
       
   376         uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
       
   377 
       
   378     return uniformLocations.at(id);
       
   379 }
       
   380 
       
   381 
       
   382 void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform)
       
   383 {
       
   384     Q_UNUSED(transform); // Currently ignored
       
   385 }
       
   386 
       
   387 void QGLEngineShaderManager::setDirty()
       
   388 {
       
   389     shaderProgNeedsChanging = true;
       
   390 }
       
   391 
       
   392 void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
       
   393 {
       
   394     if (srcPixelType == PixelSrcType(style))
       
   395         return;
       
   396 
       
   397     srcPixelType = style;
       
   398     shaderProgNeedsChanging = true; //###
       
   399 }
       
   400 
       
   401 void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
       
   402 {
       
   403     if (srcPixelType == type)
       
   404         return;
       
   405 
       
   406     srcPixelType = type;
       
   407     shaderProgNeedsChanging = true; //###
       
   408 }
       
   409 
       
   410 void QGLEngineShaderManager::setOpacityMode(OpacityMode mode)
       
   411 {
       
   412     if (opacityMode == mode)
       
   413         return;
       
   414 
       
   415     opacityMode = mode;
       
   416     shaderProgNeedsChanging = true; //###
       
   417 }
       
   418 
       
   419 void QGLEngineShaderManager::setMaskType(MaskType type)
       
   420 {
       
   421     if (maskType == type)
       
   422         return;
       
   423 
       
   424     maskType = type;
       
   425     shaderProgNeedsChanging = true; //###
       
   426 }
       
   427 
       
   428 void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
       
   429 {
       
   430     if (compositionMode == mode)
       
   431         return;
       
   432 
       
   433     compositionMode = mode;
       
   434     shaderProgNeedsChanging = true; //###
       
   435 }
       
   436 
       
   437 void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
       
   438 {
       
   439     customSrcStage = stage;
       
   440     customShader = 0; // Will be compiled from 'customSrcStage' later.
       
   441     shaderProgNeedsChanging = true;
       
   442 }
       
   443 
       
   444 void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
       
   445 {
       
   446     Q_UNUSED(stage); // Currently we only support one at a time...
       
   447 
       
   448     customSrcStage = 0;
       
   449     customShader = 0;
       
   450     shaderProgNeedsChanging = true;
       
   451 }
       
   452 
       
   453 
       
   454 QGLShaderProgram* QGLEngineShaderManager::currentProgram()
       
   455 {
       
   456     return currentShaderProg->program;
       
   457 }
       
   458 
       
   459 QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
       
   460 {
       
   461     return sharedShaders->simpleProgram();
       
   462 }
       
   463 
       
   464 QGLShaderProgram* QGLEngineShaderManager::blitProgram()
       
   465 {
       
   466     return sharedShaders->blitProgram();
       
   467 }
       
   468 
       
   469 
       
   470 
       
   471 // Select & use the correct shader program using the current state.
       
   472 // Returns true if program needed changing.
       
   473 bool QGLEngineShaderManager::useCorrectShaderProg()
       
   474 {
       
   475     if (!shaderProgNeedsChanging)
       
   476         return false;
       
   477 
       
   478     bool useCustomSrc = customSrcStage != 0;
       
   479     if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc) {
       
   480         useCustomSrc = false;
       
   481         qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
       
   482     }
       
   483 
       
   484     QGLEngineShaderProg requiredProgram;
       
   485     requiredProgram.program = 0;
       
   486 
       
   487     bool texCoords = false;
       
   488 
       
   489     // Choose vertex shader shader position function (which typically also sets
       
   490     // varyings) and the source pixel (srcPixel) fragment shader function:
       
   491     QGLEngineSharedShaders::ShaderName positionVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
       
   492     QGLEngineSharedShaders::ShaderName srcPixelFragShaderName = QGLEngineSharedShaders::InvalidShaderName;
       
   493     bool isAffine = brushTransform.isAffine();
       
   494     if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
       
   495         if (isAffine)
       
   496             positionVertexShaderName = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
       
   497         else
       
   498             positionVertexShaderName = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
       
   499 
       
   500         srcPixelFragShaderName = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
       
   501     }
       
   502     else switch (srcPixelType) {
       
   503         default:
       
   504         case Qt::NoBrush:
       
   505             qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
       
   506             break;
       
   507         case QGLEngineShaderManager::ImageSrc:
       
   508             srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcFragmentShader;
       
   509             positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
       
   510             texCoords = true;
       
   511             break;
       
   512         case QGLEngineShaderManager::NonPremultipliedImageSrc:
       
   513             srcPixelFragShaderName = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
       
   514             positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
       
   515             texCoords = true;
       
   516             break;
       
   517         case QGLEngineShaderManager::PatternSrc:
       
   518             srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
       
   519             positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
       
   520             texCoords = true;
       
   521             break;
       
   522         case QGLEngineShaderManager::TextureSrcWithPattern:
       
   523             srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
       
   524             positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
       
   525                                                 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
       
   526             break;
       
   527         case Qt::SolidPattern:
       
   528             srcPixelFragShaderName = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
       
   529             positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
       
   530             break;
       
   531         case Qt::LinearGradientPattern:
       
   532             srcPixelFragShaderName = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
       
   533             positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
       
   534                                                 : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
       
   535             break;
       
   536         case Qt::ConicalGradientPattern:
       
   537             srcPixelFragShaderName = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
       
   538             positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
       
   539                                                 : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
       
   540             break;
       
   541         case Qt::RadialGradientPattern:
       
   542             srcPixelFragShaderName = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
       
   543             positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
       
   544                                                 : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
       
   545             break;
       
   546         case Qt::TexturePattern:
       
   547             srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
       
   548             positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
       
   549                                                 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
       
   550             break;
       
   551     };
       
   552     requiredProgram.positionVertexShader = sharedShaders->compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader);
       
   553     if (useCustomSrc) {
       
   554         if (!customShader)
       
   555             customShader = sharedShaders->compileCustomShader(customSrcStage, QGLShader::PartialFragmentShader);
       
   556         requiredProgram.srcPixelFragShader = customShader;
       
   557     } else {
       
   558         requiredProgram.srcPixelFragShader = sharedShaders->compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader);
       
   559     }
       
   560 
       
   561     const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
       
   562     const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
       
   563 
       
   564     // Choose fragment shader main function:
       
   565     QGLEngineSharedShaders::ShaderName mainFragShaderName;
       
   566 
       
   567     if (opacityMode == AttributeOpacity) {
       
   568         Q_ASSERT(!hasCompose && !hasMask);
       
   569         mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
       
   570     } else {
       
   571         bool useGlobalOpacity = (opacityMode == UniformOpacity);
       
   572         if (hasCompose && hasMask && useGlobalOpacity)
       
   573             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO;
       
   574         if (hasCompose && hasMask && !useGlobalOpacity)
       
   575             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM;
       
   576         if (!hasCompose && hasMask && useGlobalOpacity)
       
   577             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO;
       
   578         if (!hasCompose && hasMask && !useGlobalOpacity)
       
   579             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M;
       
   580         if (hasCompose && !hasMask && useGlobalOpacity)
       
   581             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO;
       
   582         if (hasCompose && !hasMask && !useGlobalOpacity)
       
   583             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C;
       
   584         if (!hasCompose && !hasMask && useGlobalOpacity)
       
   585             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O;
       
   586         if (!hasCompose && !hasMask && !useGlobalOpacity)
       
   587             mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader;
       
   588     }
       
   589 
       
   590     requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader);
       
   591 
       
   592     if (hasMask) {
       
   593         QGLEngineSharedShaders::ShaderName maskShaderName = QGLEngineSharedShaders::InvalidShaderName;
       
   594         if (maskType == PixelMask) {
       
   595             maskShaderName = QGLEngineSharedShaders::MaskFragmentShader;
       
   596             texCoords = true;
       
   597         } else if (maskType == SubPixelMaskPass1) {
       
   598             maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
       
   599             texCoords = true;
       
   600         } else if (maskType == SubPixelMaskPass2) {
       
   601             maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
       
   602             texCoords = true;
       
   603         } else if (maskType == SubPixelWithGammaMask) {
       
   604             maskShaderName = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
       
   605             texCoords = true;
       
   606         } else {
       
   607             qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
       
   608         }
       
   609 
       
   610         requiredProgram.maskFragShader = sharedShaders->compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader);
       
   611     } else {
       
   612         requiredProgram.maskFragShader = 0;
       
   613     }
       
   614 
       
   615     if (hasCompose) {
       
   616         QGLEngineSharedShaders::ShaderName compositionShaderName = QGLEngineSharedShaders::InvalidShaderName;
       
   617         switch (compositionMode) {
       
   618             case QPainter::CompositionMode_Multiply:
       
   619                 compositionShaderName = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
       
   620                 break;
       
   621             case QPainter::CompositionMode_Screen:
       
   622                 compositionShaderName = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
       
   623                 break;
       
   624             case QPainter::CompositionMode_Overlay:
       
   625                 compositionShaderName = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
       
   626                 break;
       
   627             case QPainter::CompositionMode_Darken:
       
   628                 compositionShaderName = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
       
   629                 break;
       
   630             case QPainter::CompositionMode_Lighten:
       
   631                 compositionShaderName = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
       
   632                 break;
       
   633             case QPainter::CompositionMode_ColorDodge:
       
   634                 compositionShaderName = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
       
   635                 break;
       
   636             case QPainter::CompositionMode_ColorBurn:
       
   637                 compositionShaderName = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
       
   638                 break;
       
   639             case QPainter::CompositionMode_HardLight:
       
   640                 compositionShaderName = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
       
   641                 break;
       
   642             case QPainter::CompositionMode_SoftLight:
       
   643                 compositionShaderName = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
       
   644                 break;
       
   645             case QPainter::CompositionMode_Difference:
       
   646                 compositionShaderName = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
       
   647                 break;
       
   648             case QPainter::CompositionMode_Exclusion:
       
   649                 compositionShaderName = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
       
   650                 break;
       
   651             default:
       
   652                 qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
       
   653         }
       
   654         requiredProgram.compositionFragShader = sharedShaders->compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader);
       
   655     } else {
       
   656         requiredProgram.compositionFragShader = 0;
       
   657     }
       
   658 
       
   659         // Choose vertex shader main function
       
   660     QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
       
   661     if (opacityMode == AttributeOpacity) {
       
   662         Q_ASSERT(texCoords);
       
   663         mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
       
   664     } else if (texCoords) {
       
   665         mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
       
   666     } else {
       
   667         mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader;
       
   668     }
       
   669     requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader);
       
   670     requiredProgram.useTextureCoords = texCoords;
       
   671     requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
       
   672 
       
   673 
       
   674     // At this point, requiredProgram is fully populated so try to find the program in the cache
       
   675     currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
       
   676 
       
   677     if (currentShaderProg) {
       
   678         currentShaderProg->program->enable();
       
   679         if (useCustomSrc)
       
   680             customSrcStage->setUniforms(currentShaderProg->program);
       
   681     }
       
   682 
       
   683     shaderProgNeedsChanging = false;
       
   684     return true;
       
   685 }
       
   686 
       
   687 QT_END_NAMESPACE