src/opengl/gl2paintengineex/qglengineshadermanager.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 25 e24348a560a6
equal deleted inserted replaced
3:41300fa6a67c 18:2f34d5167611
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     8 **
     8 **
   168     // Compile up the simple shader:
   168     // Compile up the simple shader:
   169     source.clear();
   169     source.clear();
   170     source.append(qShaderSnippets[MainVertexShader]);
   170     source.append(qShaderSnippets[MainVertexShader]);
   171     source.append(qShaderSnippets[PositionOnlyVertexShader]);
   171     source.append(qShaderSnippets[PositionOnlyVertexShader]);
   172     vertexShader = new QGLShader(QGLShader::Vertex, context, this);
   172     vertexShader = new QGLShader(QGLShader::Vertex, context, this);
   173     vertexShader->compileSourceCode(source);
   173     if (!vertexShader->compileSourceCode(source))
       
   174         qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
   174 
   175 
   175     source.clear();
   176     source.clear();
   176     source.append(qShaderSnippets[MainFragmentShader]);
   177     source.append(qShaderSnippets[MainFragmentShader]);
   177     source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
   178     source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
   178     fragShader = new QGLShader(QGLShader::Fragment, context, this);
   179     fragShader = new QGLShader(QGLShader::Fragment, context, this);
   179     fragShader->compileSourceCode(source);
   180     if (!fragShader->compileSourceCode(source))
       
   181         qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
   180 
   182 
   181     simpleShaderProg = new QGLShaderProgram(context, this);
   183     simpleShaderProg = new QGLShaderProgram(context, this);
   182     simpleShaderProg->addShader(vertexShader);
   184     simpleShaderProg->addShader(vertexShader);
   183     simpleShaderProg->addShader(fragShader);
   185     simpleShaderProg->addShader(fragShader);
   184     simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
   186     simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   187     simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
       
   188     simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
       
   189     simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
   185     simpleShaderProg->link();
   190     simpleShaderProg->link();
   186     if (!simpleShaderProg->isLinked()) {
   191     if (!simpleShaderProg->isLinked()) {
   187         qCritical() << "Errors linking simple shader:"
   192         qCritical() << "Errors linking simple shader:"
   188                     << simpleShaderProg->log();
   193                     << simpleShaderProg->log();
   189     }
   194     }
   191     // Compile the blit shader:
   196     // Compile the blit shader:
   192     source.clear();
   197     source.clear();
   193     source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
   198     source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
   194     source.append(qShaderSnippets[UntransformedPositionVertexShader]);
   199     source.append(qShaderSnippets[UntransformedPositionVertexShader]);
   195     vertexShader = new QGLShader(QGLShader::Vertex, context, this);
   200     vertexShader = new QGLShader(QGLShader::Vertex, context, this);
   196     vertexShader->compileSourceCode(source);
   201     if (!vertexShader->compileSourceCode(source))
       
   202         qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
   197 
   203 
   198     source.clear();
   204     source.clear();
   199     source.append(qShaderSnippets[MainFragmentShader]);
   205     source.append(qShaderSnippets[MainFragmentShader]);
   200     source.append(qShaderSnippets[ImageSrcFragmentShader]);
   206     source.append(qShaderSnippets[ImageSrcFragmentShader]);
   201     fragShader = new QGLShader(QGLShader::Fragment, context, this);
   207     fragShader = new QGLShader(QGLShader::Fragment, context, this);
   202     fragShader->compileSourceCode(source);
   208     if (!fragShader->compileSourceCode(source))
       
   209         qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
   203 
   210 
   204     blitShaderProg = new QGLShaderProgram(context, this);
   211     blitShaderProg = new QGLShaderProgram(context, this);
   205     blitShaderProg->addShader(vertexShader);
   212     blitShaderProg->addShader(vertexShader);
   206     blitShaderProg->addShader(fragShader);
   213     blitShaderProg->addShader(fragShader);
   207     blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
   214     blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
   212                     << simpleShaderProg->log();
   219                     << simpleShaderProg->log();
   213     }
   220     }
   214 
   221 
   215 }
   222 }
   216 
   223 
       
   224 QGLEngineSharedShaders::~QGLEngineSharedShaders()
       
   225 {
       
   226     QList<QGLEngineShaderProg*>::iterator itr;
       
   227     for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr)
       
   228         delete *itr;
       
   229 
       
   230     if (blitShaderProg) {
       
   231         delete blitShaderProg;
       
   232         blitShaderProg = 0;
       
   233     }
       
   234 
       
   235     if (simpleShaderProg) {
       
   236         delete simpleShaderProg;
       
   237         simpleShaderProg = 0;
       
   238     }
       
   239 }
       
   240 
   217 #if defined (QT_DEBUG)
   241 #if defined (QT_DEBUG)
   218 QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
   242 QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
   219 {
   243 {
   220     QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
   244     QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
   221     return QByteArray(m.valueToKey(name));
   245     return QByteArray(m.valueToKey(name));
   232             cachedPrograms.move(i, 0);
   256             cachedPrograms.move(i, 0);
   233             return cachedProg;
   257             return cachedProg;
   234         }
   258         }
   235     }
   259     }
   236 
   260 
   237     QByteArray source;
   261     QGLShader *vertexShader = 0;
   238     source.append(qShaderSnippets[prog.mainFragShader]);
   262     QGLShader *fragShader = 0;
   239     source.append(qShaderSnippets[prog.srcPixelFragShader]);
   263     QGLEngineShaderProg *newProg = 0;
   240     if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
   264     bool success = false;
   241         source.append(prog.customStageSource);
   265 
   242     if (prog.compositionFragShader)
   266     do {
   243         source.append(qShaderSnippets[prog.compositionFragShader]);
   267         QByteArray source;
   244     if (prog.maskFragShader)
   268         source.append(qShaderSnippets[prog.mainFragShader]);
   245         source.append(qShaderSnippets[prog.maskFragShader]);
   269         source.append(qShaderSnippets[prog.srcPixelFragShader]);
   246     QGLShader* fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
   270         if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
   247     fragShader->compileSourceCode(source);
   271             source.append(prog.customStageSource);
   248 
   272         if (prog.compositionFragShader)
   249     source.clear();
   273             source.append(qShaderSnippets[prog.compositionFragShader]);
   250     source.append(qShaderSnippets[prog.mainVertexShader]);
   274         if (prog.maskFragShader)
   251     source.append(qShaderSnippets[prog.positionVertexShader]);
   275             source.append(qShaderSnippets[prog.maskFragShader]);
   252     QGLShader* vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
   276         fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
   253     vertexShader->compileSourceCode(source);
   277         QByteArray description;
   254 
       
   255 #if defined(QT_DEBUG)
   278 #if defined(QT_DEBUG)
   256     // Name the shaders for easier debugging
   279         // Name the shader for easier debugging
   257     QByteArray description;
   280         description.append("Fragment shader: main=");
   258     description.append("Fragment shader: main=");
   281         description.append(snippetNameStr(prog.mainFragShader));
   259     description.append(snippetNameStr(prog.mainFragShader));
   282         description.append(", srcPixel=");
   260     description.append(", srcPixel=");
   283         description.append(snippetNameStr(prog.srcPixelFragShader));
   261     description.append(snippetNameStr(prog.srcPixelFragShader));
   284         if (prog.compositionFragShader) {
   262     if (prog.compositionFragShader) {
   285             description.append(", composition=");
   263         description.append(", composition=");
   286             description.append(snippetNameStr(prog.compositionFragShader));
   264         description.append(snippetNameStr(prog.compositionFragShader));
   287         }
   265     }
   288         if (prog.maskFragShader) {
   266     if (prog.maskFragShader) {
   289             description.append(", mask=");
   267         description.append(", mask=");
   290             description.append(snippetNameStr(prog.maskFragShader));
   268         description.append(snippetNameStr(prog.maskFragShader));
   291         }
   269     }
   292         fragShader->setObjectName(QString::fromLatin1(description));
   270     fragShader->setObjectName(QString::fromLatin1(description));
       
   271 
       
   272     description.clear();
       
   273     description.append("Vertex shader: main=");
       
   274     description.append(snippetNameStr(prog.mainVertexShader));
       
   275     description.append(", position=");
       
   276     description.append(snippetNameStr(prog.positionVertexShader));
       
   277     vertexShader->setObjectName(QString::fromLatin1(description));
       
   278 #endif
   293 #endif
   279 
   294         if (!fragShader->compileSourceCode(source)) {
   280     QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog);
   295             qWarning() << "Warning:" << description << "failed to compile!";
   281 
   296             break;
   282     // If the shader program's not found in the cache, create it now.
   297         }
   283     newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
   298 
   284     newProg->program->addShader(vertexShader);
   299         source.clear();
   285     newProg->program->addShader(fragShader);
   300         source.append(qShaderSnippets[prog.mainVertexShader]);
   286 
   301         source.append(qShaderSnippets[prog.positionVertexShader]);
   287     // We have to bind the vertex attribute names before the program is linked:
   302         vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
   288     newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   289     if (newProg->useTextureCoords)
       
   290         newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
       
   291     if (newProg->useOpacityAttribute)
       
   292         newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
       
   293 
       
   294     newProg->program->link();
       
   295     if (!newProg->program->isLinked()) {
       
   296         QLatin1String none("none");
       
   297         QLatin1String br("\n");
       
   298         QString error;
       
   299         error = QLatin1String("Shader program failed to link,")
       
   300 #if defined(QT_DEBUG)
   303 #if defined(QT_DEBUG)
   301             + br
   304         // Name the shader for easier debugging
   302             + QLatin1String("  Shaders Used:") + br
   305         description.clear();
   303             + QLatin1String("    ") + vertexShader->objectName() + QLatin1String(": ") + br
   306         description.append("Vertex shader: main=");
   304             + QLatin1String(vertexShader->sourceCode()) + br
   307         description.append(snippetNameStr(prog.mainVertexShader));
   305             + QLatin1String("    ") + fragShader->objectName() + QLatin1String(": ") + br
   308         description.append(", position=");
   306             + QLatin1String(fragShader->sourceCode()) + br
   309         description.append(snippetNameStr(prog.positionVertexShader));
       
   310         vertexShader->setObjectName(QString::fromLatin1(description));
   307 #endif
   311 #endif
   308             + QLatin1String("  Error Log:\n")
   312         if (!vertexShader->compileSourceCode(source)) {
   309             + QLatin1String("    ") + newProg->program->log();
   313             qWarning() << "Warning:" << description << "failed to compile!";
   310         qWarning() << error;
   314             break;
   311         delete newProg; // Deletes the QGLShaderProgram in it's destructor
   315         }
   312         newProg = 0;
   316 
   313     }
   317         newProg = new QGLEngineShaderProg(prog);
   314     else {
   318 
       
   319         // If the shader program's not found in the cache, create it now.
       
   320         newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
       
   321         newProg->program->addShader(vertexShader);
       
   322         newProg->program->addShader(fragShader);
       
   323 
       
   324         // We have to bind the vertex attribute names before the program is linked:
       
   325         newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
       
   326         if (newProg->useTextureCoords)
       
   327             newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
       
   328         if (newProg->useOpacityAttribute)
       
   329             newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
       
   330         if (newProg->usePmvMatrix) {
       
   331             newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
       
   332             newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
       
   333             newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
       
   334         }
       
   335 
       
   336         newProg->program->link();
       
   337         if (!newProg->program->isLinked()) {
       
   338             QLatin1String none("none");
       
   339             QLatin1String br("\n");
       
   340             QString error;
       
   341             error = QLatin1String("Shader program failed to link,")
       
   342 #if defined(QT_DEBUG)
       
   343                 + br
       
   344                 + QLatin1String("  Shaders Used:") + br
       
   345                 + QLatin1String("    ") + vertexShader->objectName() + QLatin1String(": ") + br
       
   346                 + QLatin1String(vertexShader->sourceCode()) + br
       
   347                 + QLatin1String("    ") + fragShader->objectName() + QLatin1String(": ") + br
       
   348                 + QLatin1String(fragShader->sourceCode()) + br
       
   349 #endif
       
   350                 + QLatin1String("  Error Log:\n")
       
   351                 + QLatin1String("    ") + newProg->program->log();
       
   352             qWarning() << error;
       
   353             break;
       
   354         }
   315         if (cachedPrograms.count() > 30) {
   355         if (cachedPrograms.count() > 30) {
   316             // The cache is full, so delete the last 5 programs in the list.
   356             // The cache is full, so delete the last 5 programs in the list.
   317             // These programs will be least used, as a program us bumped to
   357             // These programs will be least used, as a program us bumped to
   318             // the top of the list when it's used.
   358             // the top of the list when it's used.
   319             for (int i = 0; i < 5; ++i) {
   359             for (int i = 0; i < 5; ++i) {
   321                 cachedPrograms.removeLast();
   361                 cachedPrograms.removeLast();
   322             }
   362             }
   323         }
   363         }
   324 
   364 
   325         cachedPrograms.insert(0, newProg);
   365         cachedPrograms.insert(0, newProg);
       
   366 
       
   367         success = true;
       
   368     } while (false);
       
   369 
       
   370     // Clean up everything if we weren't successful
       
   371     if (!success) {
       
   372         if (newProg) {
       
   373             delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
       
   374             newProg = 0;
       
   375         }
       
   376         else {
       
   377             if (vertexShader)
       
   378                 delete vertexShader;
       
   379             if (fragShader)
       
   380                 delete fragShader;
       
   381         }
   326     }
   382     }
   327 
   383 
   328     return newProg;
   384     return newProg;
   329 }
   385 }
   330 
   386 
   360 {
   416 {
   361     //###
   417     //###
   362     removeCustomStage();
   418     removeCustomStage();
   363 }
   419 }
   364 
   420 
   365 uint QGLEngineShaderManager::getUniformLocation(Uniform id)
   421 GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
   366 {
   422 {
       
   423     if (!currentShaderProg)
       
   424         return 0;
       
   425 
   367     QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
   426     QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
   368     if (uniformLocations.isEmpty())
   427     if (uniformLocations.isEmpty())
   369         uniformLocations.fill(GLuint(-1), NumUniforms);
   428         uniformLocations.fill(GLuint(-1), NumUniforms);
   370 
   429 
   371     static const char *uniformNames[] = {
   430     static const char *uniformNames[] = {
   372         "imageTexture",
   431         "imageTexture",
   373         "patternColor",
   432         "patternColor",
   374         "globalOpacity",
   433         "globalOpacity",
   375         "depth",
   434         "depth",
   376         "pmvMatrix",
       
   377         "maskTexture",
   435         "maskTexture",
   378         "fragmentColor",
   436         "fragmentColor",
   379         "linearData",
   437         "linearData",
   380         "angle",
   438         "angle",
   381         "halfViewportSize",
   439         "halfViewportSize",
   392 
   450 
   393     return uniformLocations.at(id);
   451     return uniformLocations.at(id);
   394 }
   452 }
   395 
   453 
   396 
   454 
   397 void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform)
   455 void QGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType)
   398 {
   456 {
   399     Q_UNUSED(transform); // Currently ignored
   457     Q_UNUSED(transformType); // Currently ignored
   400 }
   458 }
   401 
   459 
   402 void QGLEngineShaderManager::setDirty()
   460 void QGLEngineShaderManager::setDirty()
   403 {
   461 {
   404     shaderProgNeedsChanging = true;
   462     shaderProgNeedsChanging = true;
   466     shaderProgNeedsChanging = true;
   524     shaderProgNeedsChanging = true;
   467 }
   525 }
   468 
   526 
   469 QGLShaderProgram* QGLEngineShaderManager::currentProgram()
   527 QGLShaderProgram* QGLEngineShaderManager::currentProgram()
   470 {
   528 {
   471     return currentShaderProg->program;
   529     if (currentShaderProg)
       
   530         return currentShaderProg->program;
       
   531     else
       
   532         return sharedShaders->simpleProgram();
       
   533 }
       
   534 
       
   535 void QGLEngineShaderManager::useSimpleProgram()
       
   536 {
       
   537     sharedShaders->simpleProgram()->bind();
       
   538     QGLContextPrivate* ctx_d = ctx->d_func();
       
   539     ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
       
   540     ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
       
   541     ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
       
   542     shaderProgNeedsChanging = true;
       
   543 }
       
   544 
       
   545 void QGLEngineShaderManager::useBlitProgram()
       
   546 {
       
   547     sharedShaders->blitProgram()->bind();
       
   548     QGLContextPrivate* ctx_d = ctx->d_func();
       
   549     ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
       
   550     ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
       
   551     ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
       
   552     shaderProgNeedsChanging = true;
   472 }
   553 }
   473 
   554 
   474 QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
   555 QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
   475 {
   556 {
   476     return sharedShaders->simpleProgram();
   557     return sharedShaders->simpleProgram();
   667     } else {
   748     } else {
   668         requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
   749         requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
   669     }
   750     }
   670     requiredProgram.useTextureCoords = texCoords;
   751     requiredProgram.useTextureCoords = texCoords;
   671     requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
   752     requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
       
   753     requiredProgram.usePmvMatrix = true;
   672 
   754 
   673     // At this point, requiredProgram is fully populated so try to find the program in the cache
   755     // At this point, requiredProgram is fully populated so try to find the program in the cache
   674     currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
   756     currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
   675 
   757 
   676     if (currentShaderProg) {
   758     if (currentShaderProg) {
   677         currentShaderProg->program->bind();
   759         currentShaderProg->program->bind();
   678         if (useCustomSrc)
   760         if (useCustomSrc)
   679             customSrcStage->setUniforms(currentShaderProg->program);
   761             customSrcStage->setUniforms(currentShaderProg->program);
   680     }
   762     }
   681 
   763 
       
   764     // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it
       
   765     // doesn't use are disabled)
       
   766     QGLContextPrivate* ctx_d = ctx->d_func();
       
   767     ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
       
   768     ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg->useTextureCoords);
       
   769     ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg->useOpacityAttribute);
       
   770 
   682     shaderProgNeedsChanging = false;
   771     shaderProgNeedsChanging = false;
   683     return true;
   772     return true;
   684 }
   773 }
   685 
   774 
   686 QT_END_NAMESPACE
   775 QT_END_NAMESPACE