diff options
Diffstat (limited to 'src/opengl/gl2paintengineex')
6 files changed, 307 insertions, 273 deletions
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp index ab2026c..b71a7b7 100644 --- a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp +++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp @@ -67,8 +67,10 @@ QGLCustomShaderStage::QGLCustomShaderStage() QGLCustomShaderStage::~QGLCustomShaderStage() { Q_D(QGLCustomShaderStage); - if (d->m_manager) - d->m_manager->removeCustomStage(this); + if (d->m_manager) { + d->m_manager->removeCustomStage(); + d->m_manager->sharedShaders->cleanupCustomStage(this); + } } void QGLCustomShaderStage::setUniformsDirty() @@ -85,6 +87,8 @@ bool QGLCustomShaderStage::setOnPainter(QPainter* p) qWarning("QGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2"); return false; } + if (d->m_manager) + qWarning("Custom shader is already set on a painter"); QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine()); d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine); @@ -108,12 +112,21 @@ void QGLCustomShaderStage::removeFromPainter(QPainter* p) // This should leave the program in a compiled/linked state // if the next custom shader stage is this one again. d->m_manager->setCustomStage(0); + d->m_manager = 0; } -const char* QGLCustomShaderStage::source() const +QByteArray QGLCustomShaderStage::source() const { Q_D(const QGLCustomShaderStage); - return d->m_source.constData(); + return d->m_source; +} + +// Called by the shader manager if another custom shader is attached or +// the manager is deleted +void QGLCustomShaderStage::setInactive() +{ + Q_D(QGLCustomShaderStage); + d->m_manager = 0; } void QGLCustomShaderStage::setSource(const QByteArray& s) diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h index f8c13c5..e319389 100644 --- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h +++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h @@ -74,8 +74,9 @@ public: bool setOnPainter(QPainter*); void removeFromPainter(QPainter*); - const char* source() const; + QByteArray source() const; + void setInactive(); protected: void setSource(const QByteArray&); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index af9306f..40a6241 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -66,7 +66,7 @@ QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLConte return p; } -const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = { +const char* QGLEngineSharedShaders::qShaderSnippets[] = { 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, @@ -78,7 +78,6 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) , blitShaderProg(0) , simpleShaderProg(0) { - memset(compiledShaders, 0, sizeof(compiledShaders)); /* Rather than having the shader source array statically initialised, it is initialised @@ -86,10 +85,10 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) around without having to change the order of the glsl strings. It is hoped this will make future hard-to-find runtime bugs more obvious and generally give more solid code. */ - static bool qglEngineShaderSourceCodePopulated = false; - if (!qglEngineShaderSourceCodePopulated) { + static bool snippetsPopulated = false; + if (!snippetsPopulated) { - const char** code = qglEngineShaderSourceCode; // shortcut + const char** code = qShaderSnippets; // shortcut code[MainVertexShader] = qglslMainVertexShader; code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader; @@ -121,7 +120,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader; code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader; code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader; - code[CustomImageSrcFragmentShader] = ""; // Supplied by app. + code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader; code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader; code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader; @@ -131,11 +130,13 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader; code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader; + code[NoMaskFragmentShader] = ""; code[MaskFragmentShader] = qglslMaskFragmentShader; code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1; code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2; code[RgbMaskWithGammaFragmentShader] = ""; //### + code[NoCompositionModeFragmentShader] = ""; code[MultiplyCompositionModeFragmentShader] = ""; //### code[ScreenCompositionModeFragmentShader] = ""; //### code[OverlayCompositionModeFragmentShader] = ""; //### @@ -150,29 +151,36 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) #if defined(QT_DEBUG) // Check that all the elements have been filled: - for (int i = 0; i < TotalShaderCount; ++i) { - if (qglEngineShaderSourceCode[i] == 0) { - int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName"); - QMetaEnum m = staticMetaObject.enumerator(enumIndex); - - qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i) - << "(shader" << i << ") missing!"; + for (int i = 0; i < TotalSnippetCount; ++i) { + if (qShaderSnippets[i] == 0) { + qFatal("Shader snippet for %s (#%d) is missing!", + snippetNameStr(SnippetName(i)).constData(), i); } } #endif - qglEngineShaderSourceCodePopulated = true; + snippetsPopulated = true; } + QGLShader* fragShader; + QGLShader* vertexShader; + QByteArray source; + // Compile up the simple shader: + source.clear(); + source.append(qShaderSnippets[MainVertexShader]); + source.append(qShaderSnippets[PositionOnlyVertexShader]); + vertexShader = new QGLShader(QGLShader::VertexShader, context, this); + vertexShader->compile(source); + + source.clear(); + source.append(qShaderSnippets[MainFragmentShader]); + source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); + fragShader = new QGLShader(QGLShader::FragmentShader, context, this); + fragShader->compile(source); + simpleShaderProg = new QGLShaderProgram(context, this); - compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader); - compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader); - compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); - compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader); - simpleShaderProg->addShader(compiledShaders[MainVertexShader]); - simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]); - simpleShaderProg->addShader(compiledShaders[MainFragmentShader]); - simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]); + simpleShaderProg->addShader(vertexShader); + simpleShaderProg->addShader(fragShader); simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); simpleShaderProg->link(); if (!simpleShaderProg->isLinked()) { @@ -181,152 +189,159 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) } // Compile the blit shader: + source.clear(); + source.append(qShaderSnippets[MainWithTexCoordsVertexShader]); + source.append(qShaderSnippets[UntransformedPositionVertexShader]); + vertexShader = new QGLShader(QGLShader::VertexShader, context, this); + vertexShader->compile(source); + + source.clear(); + source.append(qShaderSnippets[MainFragmentShader]); + source.append(qShaderSnippets[ImageSrcFragmentShader]); + fragShader = new QGLShader(QGLShader::FragmentShader, context, this); + fragShader->compile(source); + blitShaderProg = new QGLShaderProgram(context, this); - compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader); - compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader); - compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); - compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader); - blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]); - blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]); - blitShaderProg->addShader(compiledShaders[MainFragmentShader]); - blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]); + blitShaderProg->addShader(vertexShader); + blitShaderProg->addShader(fragShader); blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); blitShaderProg->link(); if (!blitShaderProg->isLinked()) { qCritical() << "Errors linking blit shader:" - << blitShaderProg->log(); - } -} - -void QGLEngineSharedShaders::shaderDestroyed(QObject *shader) -{ - // Remove any shader programs which has this as the srcPixel shader: - for (int i = 0; i < cachedPrograms.size(); ++i) { - if (cachedPrograms.at(i).srcPixelFragShader == shader) { - delete cachedPrograms.at(i).program; - cachedPrograms.removeAt(i--); - } + << simpleShaderProg->log(); } - emit shaderProgNeedsChanging(); } -QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader::ShaderType type) +#if defined (QT_DEBUG) +QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name) { - Q_ASSERT(name != CustomImageSrcFragmentShader); - Q_ASSERT(name < InvalidShaderName); - - if (compiledShaders[name]) - return compiledShaders[name]; - - QByteArray source = qglEngineShaderSourceCode[name]; - QGLShader *newShader = new QGLShader(type, ctxGuard.context(), this); - newShader->compile(source); - -#if defined(QT_DEBUG) - // Name the shader for easier debugging - QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); - newShader->setObjectName(QLatin1String(m.valueToKey(name))); -#endif - - compiledShaders[name] = newShader; - return newShader; + QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName")); + return QByteArray(m.valueToKey(name)); } - -QGLShader *QGLEngineSharedShaders::compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type) -{ - QByteArray source = stage->source(); - source += qglslCustomSrcFragmentShader; - - QGLShader *newShader = customShaderCache.object(source); - if (newShader) - return newShader; - - newShader = new QGLShader(type, ctxGuard.context(), this); - newShader->compile(source); - customShaderCache.insert(source, newShader); - - connect(newShader, SIGNAL(destroyed(QObject *)), - this, SLOT(shaderDestroyed(QObject *))); - -#if defined(QT_DEBUG) - // Name the shader for easier debugging - QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); - newShader->setObjectName(QLatin1String(m.valueToKey(CustomImageSrcFragmentShader))); #endif - return newShader; -} - // The address returned here will only be valid until next time this function is called. QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog) { for (int i = 0; i < cachedPrograms.size(); ++i) { - if (cachedPrograms[i] == prog) - return &cachedPrograms[i]; + QGLEngineShaderProg *cachedProg = cachedPrograms[i]; + if (*cachedProg == prog) { + // Move the program to the top of the list as a poor-man's cache algo + cachedPrograms.move(i, 0); + return cachedProg; + } } - cachedPrograms.append(prog); - QGLEngineShaderProg &cached = cachedPrograms.last(); + QByteArray source; + source.append(qShaderSnippets[prog.mainFragShader]); + source.append(qShaderSnippets[prog.srcPixelFragShader]); + if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) + source.append(prog.customStageSource); + if (prog.compositionFragShader) + source.append(qShaderSnippets[prog.compositionFragShader]); + if (prog.maskFragShader) + source.append(qShaderSnippets[prog.maskFragShader]); + QGLShader* fragShader = new QGLShader(QGLShader::FragmentShader, ctxGuard.context(), this); + fragShader->compile(source); + + source.clear(); + source.append(qShaderSnippets[prog.mainVertexShader]); + source.append(qShaderSnippets[prog.positionVertexShader]); + QGLShader* vertexShader = new QGLShader(QGLShader::VertexShader, ctxGuard.context(), this); + vertexShader->compile(source); + +#if defined(QT_DEBUG) + // Name the shaders for easier debugging + QByteArray description; + description.append("Fragment shader: main="); + description.append(snippetNameStr(prog.mainFragShader)); + description.append(", srcPixel="); + description.append(snippetNameStr(prog.srcPixelFragShader)); + if (prog.compositionFragShader) { + description.append(", composition="); + description.append(snippetNameStr(prog.compositionFragShader)); + } + if (prog.maskFragShader) { + description.append(", mask="); + description.append(snippetNameStr(prog.maskFragShader)); + } + fragShader->setObjectName(QString::fromLatin1(description)); + + description.clear(); + description.append("Vertex shader: main="); + description.append(snippetNameStr(prog.mainVertexShader)); + description.append(", position="); + description.append(snippetNameStr(prog.positionVertexShader)); + vertexShader->setObjectName(QString::fromLatin1(description)); +#endif + + QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog); // If the shader program's not found in the cache, create it now. - cached.program = new QGLShaderProgram(ctxGuard.context(), this); - cached.program->addShader(cached.mainVertexShader); - cached.program->addShader(cached.positionVertexShader); - cached.program->addShader(cached.mainFragShader); - cached.program->addShader(cached.srcPixelFragShader); - cached.program->addShader(cached.maskFragShader); - cached.program->addShader(cached.compositionFragShader); + newProg->program = new QGLShaderProgram(ctxGuard.context(), this); + newProg->program->addShader(vertexShader); + newProg->program->addShader(fragShader); // We have to bind the vertex attribute names before the program is linked: - cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - if (cached.useTextureCoords) - cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - if (cached.useOpacityAttribute) - cached.program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); - - cached.program->link(); - if (!cached.program->isLinked()) { + newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + if (newProg->useTextureCoords) + newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + if (newProg->useOpacityAttribute) + newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); + + newProg->program->link(); + if (!newProg->program->isLinked()) { QLatin1String none("none"); QLatin1String br("\n"); QString error; error = QLatin1String("Shader program failed to link,") #if defined(QT_DEBUG) + br - + QLatin1String(" Shaders Used:\n") - + QLatin1String(" mainVertexShader = ") - + (cached.mainVertexShader ? - cached.mainVertexShader->objectName() : none) + br - + QLatin1String(" positionVertexShader = ") - + (cached.positionVertexShader ? - cached.positionVertexShader->objectName() : none) + br - + QLatin1String(" mainFragShader = ") - + (cached.mainFragShader ? - cached.mainFragShader->objectName() : none) + br - + QLatin1String(" srcPixelFragShader = ") - + (cached.srcPixelFragShader ? - cached.srcPixelFragShader->objectName() : none) + br - + QLatin1String(" maskFragShader = ") - + (cached.maskFragShader ? - cached.maskFragShader->objectName() : none) + br - + QLatin1String(" compositionFragShader = ") - + (cached.compositionFragShader ? - cached.compositionFragShader->objectName() : none) + br + + QLatin1String(" Shaders Used:") + br + + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br + + QLatin1String(vertexShader->sourceCode()) + br + + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br + + QLatin1String(fragShader->sourceCode()) + br #endif + QLatin1String(" Error Log:\n") - + QLatin1String(" ") + cached.program->log(); + + QLatin1String(" ") + newProg->program->log(); qWarning() << error; - delete cached.program; - cachedPrograms.removeLast(); - return 0; - } else { - // taking the address here is safe since - // cachePrograms isn't resized anywhere else - return &cached; + delete newProg; // Deletes the QGLShaderProgram in it's destructor + newProg = 0; } + else { + if (cachedPrograms.count() > 30) { + // The cache is full, so delete the last 5 programs in the list. + // These programs will be least used, as a program us bumped to + // the top of the list when it's used. + for (int i = 0; i < 5; ++i) { + delete cachedPrograms.last(); + cachedPrograms.removeLast(); + } + } + + cachedPrograms.insert(0, newProg); + } + + return newProg; } +void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage) +{ + // Remove any shader programs which has this as the custom shader src: + for (int i = 0; i < cachedPrograms.size(); ++i) { + QGLEngineShaderProg *cachedProg = cachedPrograms[i]; + if (cachedProg->customStageSource == stage->source()) { + delete cachedProg; + cachedPrograms.removeAt(i); + i--; + } + } +} + + QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) : ctx(context), shaderProgNeedsChanging(true), @@ -335,8 +350,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) maskType(NoMask), compositionMode(QPainter::CompositionMode_SourceOver), customSrcStage(0), - currentShaderProg(0), - customShader(0) + currentShaderProg(0) { sharedShaders = QGLEngineSharedShaders::shadersForContext(context); connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot())); @@ -345,6 +359,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) QGLEngineShaderManager::~QGLEngineShaderManager() { //### + removeCustomStage(); } uint QGLEngineShaderManager::getUniformLocation(Uniform id) @@ -436,21 +451,20 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage) { + if (customSrcStage) + removeCustomStage(); customSrcStage = stage; - customShader = 0; // Will be compiled from 'customSrcStage' later. shaderProgNeedsChanging = true; } -void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage) +void QGLEngineShaderManager::removeCustomStage() { - Q_UNUSED(stage); // Currently we only support one at a time... - + if (customSrcStage) + customSrcStage->setInactive(); customSrcStage = 0; - customShader = 0; shaderProgNeedsChanging = true; } - QGLShaderProgram* QGLEngineShaderManager::currentProgram() { return currentShaderProg->program; @@ -482,22 +496,21 @@ bool QGLEngineShaderManager::useCorrectShaderProg() } QGLEngineShaderProg requiredProgram; - requiredProgram.program = 0; bool texCoords = false; // Choose vertex shader shader position function (which typically also sets // varyings) and the source pixel (srcPixel) fragment shader function: - QGLEngineSharedShaders::ShaderName positionVertexShaderName = QGLEngineSharedShaders::InvalidShaderName; - QGLEngineSharedShaders::ShaderName srcPixelFragShaderName = QGLEngineSharedShaders::InvalidShaderName; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName; bool isAffine = brushTransform.isAffine(); if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { if (isAffine) - positionVertexShaderName = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader; else - positionVertexShaderName = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader; - srcPixelFragShaderName = QGLEngineSharedShaders::PatternBrushSrcFragmentShader; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader; } else switch (srcPixelType) { default: @@ -505,172 +518,157 @@ bool QGLEngineShaderManager::useCorrectShaderProg() qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set"); break; case QGLEngineShaderManager::ImageSrc: - srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcFragmentShader; - positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader; texCoords = true; break; case QGLEngineShaderManager::NonPremultipliedImageSrc: - srcPixelFragShaderName = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; - positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader; texCoords = true; break; case QGLEngineShaderManager::PatternSrc: - srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; - positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader; texCoords = true; break; case QGLEngineShaderManager::TextureSrcWithPattern: - srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; - positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader; break; case Qt::SolidPattern: - srcPixelFragShaderName = QGLEngineSharedShaders::SolidBrushSrcFragmentShader; - positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader; + requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader; break; case Qt::LinearGradientPattern: - srcPixelFragShaderName = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; - positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader; break; case Qt::ConicalGradientPattern: - srcPixelFragShaderName = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; - positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader; break; case Qt::RadialGradientPattern: - srcPixelFragShaderName = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; - positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader; break; case Qt::TexturePattern: - srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcFragmentShader; - positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader; break; }; - requiredProgram.positionVertexShader = sharedShaders->compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader); + if (useCustomSrc) { - if (!customShader) - customShader = sharedShaders->compileCustomShader(customSrcStage, QGLShader::PartialFragmentShader); - requiredProgram.srcPixelFragShader = customShader; - } else { - requiredProgram.srcPixelFragShader = sharedShaders->compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader; + requiredProgram.customStageSource = customSrcStage->source(); } const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; const bool hasMask = maskType != QGLEngineShaderManager::NoMask; // Choose fragment shader main function: - QGLEngineSharedShaders::ShaderName mainFragShaderName; - if (opacityMode == AttributeOpacity) { Q_ASSERT(!hasCompose && !hasMask); - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_ImageArrays; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays; } else { bool useGlobalOpacity = (opacityMode == UniformOpacity); if (hasCompose && hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO; if (hasCompose && hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM; if (!hasCompose && hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO; if (!hasCompose && hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M; if (hasCompose && !hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO; if (hasCompose && !hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C; if (!hasCompose && !hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O; if (!hasCompose && !hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader; + requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader; } - requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); - if (hasMask) { - QGLEngineSharedShaders::ShaderName maskShaderName = QGLEngineSharedShaders::InvalidShaderName; if (maskType == PixelMask) { - maskShaderName = QGLEngineSharedShaders::MaskFragmentShader; + requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader; texCoords = true; } else if (maskType == SubPixelMaskPass1) { - maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1; + requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1; texCoords = true; } else if (maskType == SubPixelMaskPass2) { - maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2; + requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2; texCoords = true; } else if (maskType == SubPixelWithGammaMask) { - maskShaderName = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; + requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; texCoords = true; } else { qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); } - - requiredProgram.maskFragShader = sharedShaders->compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader); } else { - requiredProgram.maskFragShader = 0; + requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader; } if (hasCompose) { - QGLEngineSharedShaders::ShaderName compositionShaderName = QGLEngineSharedShaders::InvalidShaderName; switch (compositionMode) { case QPainter::CompositionMode_Multiply: - compositionShaderName = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader; break; case QPainter::CompositionMode_Screen: - compositionShaderName = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader; break; case QPainter::CompositionMode_Overlay: - compositionShaderName = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader; break; case QPainter::CompositionMode_Darken: - compositionShaderName = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader; break; case QPainter::CompositionMode_Lighten: - compositionShaderName = QGLEngineSharedShaders::LightenCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader; break; case QPainter::CompositionMode_ColorDodge: - compositionShaderName = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader; break; case QPainter::CompositionMode_ColorBurn: - compositionShaderName = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader; break; case QPainter::CompositionMode_HardLight: - compositionShaderName = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader; break; case QPainter::CompositionMode_SoftLight: - compositionShaderName = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader; break; case QPainter::CompositionMode_Difference: - compositionShaderName = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader; break; case QPainter::CompositionMode_Exclusion: - compositionShaderName = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader; break; default: qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); } - requiredProgram.compositionFragShader = sharedShaders->compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader); } else { - requiredProgram.compositionFragShader = 0; + requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader; } - // Choose vertex shader main function - QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName; + // Choose vertex shader main function if (opacityMode == AttributeOpacity) { Q_ASSERT(texCoords); - mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; + requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; } else if (texCoords) { - mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader; + requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader; } else { - mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader; + requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader; } - requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); requiredProgram.useTextureCoords = texCoords; requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity); - // At this point, requiredProgram is fully populated so try to find the program in the cache currentShaderProg = sharedShaders->findProgramInCache(requiredProgram); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 291d24c..50c1432 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -234,32 +234,6 @@ QT_BEGIN_NAMESPACE QT_MODULE(OpenGL) -struct QGLEngineShaderProg -{ - QGLShader* mainVertexShader; - QGLShader* positionVertexShader; - QGLShader* mainFragShader; - QGLShader* srcPixelFragShader; - QGLShader* maskFragShader; // Can be null for no mask - QGLShader* compositionFragShader; // Can be null for GL-handled mode - QGLShaderProgram* program; - - QVector<uint> uniformLocations; - - bool useTextureCoords; - bool useOpacityAttribute; - - bool operator==(const QGLEngineShaderProg& other) { - // We don't care about the program - return ( mainVertexShader == other.mainVertexShader && - positionVertexShader == other.positionVertexShader && - mainFragShader == other.mainFragShader && - srcPixelFragShader == other.srcPixelFragShader && - maskFragShader == other.maskFragShader && - compositionFragShader == other.compositionFragShader - ); - } -}; /* struct QGLEngineCachedShaderProg @@ -280,15 +254,19 @@ static const GLuint QT_VERTEX_COORDS_ATTR = 0; static const GLuint QT_TEXTURE_COORDS_ATTR = 1; static const GLuint QT_OPACITY_ATTR = 2; +class QGLEngineShaderProg; + class QGLEngineSharedShaders : public QObject { Q_OBJECT public: - enum ShaderName { + + enum SnippetName { MainVertexShader, MainWithTexCoordsVertexShader, MainWithTexCoordsAndOpacityVertexShader, + // UntransformedPositionVertexShader must be first in the list: UntransformedPositionVertexShader, PositionOnlyVertexShader, PositionWithPatternBrushVertexShader, @@ -302,6 +280,7 @@ public: AffinePositionWithRadialGradientBrushVertexShader, AffinePositionWithTextureBrushVertexShader, + // MainFragmentShader_CMO must be first in the list: MainFragmentShader_CMO, MainFragmentShader_CM, MainFragmentShader_MO, @@ -312,6 +291,7 @@ public: MainFragmentShader, MainFragmentShader_ImageArrays, + // ImageSrcFragmentShader must be first in the list:: ImageSrcFragmentShader, ImageSrcWithPatternFragmentShader, NonPremultipliedImageSrcFragmentShader, @@ -325,11 +305,15 @@ public: ConicalGradientBrushSrcFragmentShader, ShockingPinkSrcFragmentShader, + // NoMaskFragmentShader must be first in the list: + NoMaskFragmentShader, MaskFragmentShader, RgbMaskFragmentShaderPass1, RgbMaskFragmentShaderPass2, RgbMaskWithGammaFragmentShader, + // NoCompositionModeFragmentShader must be first in the list: + NoCompositionModeFragmentShader, MultiplyCompositionModeFragmentShader, ScreenCompositionModeFragmentShader, OverlayCompositionModeFragmentShader, @@ -342,37 +326,88 @@ public: DifferenceCompositionModeFragmentShader, ExclusionCompositionModeFragmentShader, - TotalShaderCount, InvalidShaderName + TotalSnippetCount, InvalidSnippetName }; +#if defined (QT_DEBUG) + Q_ENUMS(SnippetName) + static QByteArray snippetNameStr(SnippetName snippetName); +#endif - QGLEngineSharedShaders(const QGLContext *context); +/* + // These allow the ShaderName enum to be used as a cache key + const int mainVertexOffset = 0; + const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; + const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; + const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; + const int maskOffset = (1<<14) - NoMaskShader; + const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; +*/ - QGLShader *compileNamedShader(ShaderName name, QGLShader::ShaderType type); + QGLEngineSharedShaders(const QGLContext *context); QGLShaderProgram *simpleProgram() { return simpleShaderProg; } QGLShaderProgram *blitProgram() { return blitShaderProg; } // Compile the program if it's not already in the cache, return the item in the cache. QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog); // Compile the custom shader if it's not already in the cache, return the item in the cache. - QGLShader *compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type); static QGLEngineSharedShaders *shadersForContext(const QGLContext *context); + // Ideally, this would be static and cleanup all programs in all contexts which + // contain the custom code. Currently it is just a hint and we rely on deleted + // custom shaders being cleaned up by being kicked out of the cache when it's + // full. + void cleanupCustomStage(QGLCustomShaderStage* stage); + signals: void shaderProgNeedsChanging(); -private slots: - void shaderDestroyed(QObject *shader); - private: QGLSharedResourceGuard ctxGuard; QGLShaderProgram *blitShaderProg; QGLShaderProgram *simpleShaderProg; - QList<QGLEngineShaderProg> cachedPrograms; - QCache<QByteArray, QGLShader> customShaderCache; - QGLShader* compiledShaders[TotalShaderCount]; + QList<QGLEngineShaderProg*> cachedPrograms; - static const char* qglEngineShaderSourceCode[TotalShaderCount]; + static const char* qShaderSnippets[TotalSnippetCount]; +}; + + +class QGLEngineShaderProg +{ +public: + QGLEngineShaderProg() : program(0) {} + + ~QGLEngineShaderProg() { + if (program) + delete program; + } + + QGLEngineSharedShaders::SnippetName mainVertexShader; + QGLEngineSharedShaders::SnippetName positionVertexShader; + QGLEngineSharedShaders::SnippetName mainFragShader; + QGLEngineSharedShaders::SnippetName srcPixelFragShader; + QGLEngineSharedShaders::SnippetName maskFragShader; + QGLEngineSharedShaders::SnippetName compositionFragShader; + + QByteArray customStageSource; //TODO: Decent cache key for custom stages + QGLShaderProgram* program; + + QVector<uint> uniformLocations; + + bool useTextureCoords; + bool useOpacityAttribute; + + bool operator==(const QGLEngineShaderProg& other) { + // We don't care about the program + return ( mainVertexShader == other.mainVertexShader && + positionVertexShader == other.positionVertexShader && + mainFragShader == other.mainFragShader && + srcPixelFragShader == other.srcPixelFragShader && + maskFragShader == other.maskFragShader && + compositionFragShader == other.compositionFragShader && + customStageSource == other.customStageSource + ); + } }; class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject @@ -426,7 +461,7 @@ public: void setMaskType(MaskType); void setCompositionMode(QPainter::CompositionMode); void setCustomStage(QGLCustomShaderStage* stage); - void removeCustomStage(QGLCustomShaderStage* stage); + void removeCustomStage(); uint getUniformLocation(Uniform id); @@ -437,19 +472,7 @@ public: QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer -/* - // These allow the ShaderName enum to be used as a cache key - const int mainVertexOffset = 0; - const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; - const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; - const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; - const int maskOffset = (1<<14) - NoMaskShader; - const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; -*/ - -#if defined (QT_DEBUG) - Q_ENUMS(ShaderName) -#endif + QGLEngineSharedShaders* sharedShaders; private slots: void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; } @@ -466,9 +489,7 @@ private: QPainter::CompositionMode compositionMode; QGLCustomShaderStage* customSrcStage; - QGLEngineShaderProg* currentShaderProg; - QGLEngineSharedShaders *sharedShaders; - QGLShader *customShader; + QGLEngineShaderProg* currentShaderProg; }; QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 209cd36..4cf2a83 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -289,6 +289,7 @@ public: QScopedPointer<QPixmapFilter> convolutionFilter; QScopedPointer<QPixmapFilter> colorizeFilter; QScopedPointer<QPixmapFilter> blurFilter; + QScopedPointer<QPixmapFilter> animationBlurFilter; QScopedPointer<QPixmapFilter> fastBlurFilter; QScopedPointer<QPixmapFilter> dropShadowFilter; QScopedPointer<QPixmapFilter> fastDropShadowFilter; diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp index ad18a51..1163eba 100644 --- a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp +++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp @@ -114,7 +114,7 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen) if (m_join_style == Qt::RoundJoin) m_join_style = Qt::MiterJoin; m_curvyness_add = 0.5; - m_curvyness_mul = CURVE_FLATNESS; + m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; m_roundness = 1; } else if (cosmetic) { m_curvyness_add = realWidth / 2; |