summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-09-02 12:18:10 (GMT)
committerKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-09-02 12:52:16 (GMT)
commitabef77a3fa1e4d2f6a44b323672db8ccbbd2b03f (patch)
tree6302736dbdbdad0c32c2e9f813a0fb5d9b13c606
parentdbc2bc6deb8a0d44cafe8c8d6c6905c689aa018f (diff)
downloadQt-abef77a3fa1e4d2f6a44b323672db8ccbbd2b03f.zip
Qt-abef77a3fa1e4d2f6a44b323672db8ccbbd2b03f.tar.gz
Qt-abef77a3fa1e4d2f6a44b323672db8ccbbd2b03f.tar.bz2
Split QGLEngineShaderManager into a shared and a per engine part.
Both the shaders and the engine states were shared between OpenGL contexts, but the states should be only apply to one context, not a group of contexts. This commit separates the shaders and the states. Task-number: 257254 Reviewed-by: Samuel
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp10
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp447
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h159
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp8
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h2
-rw-r--r--src/opengl/qgl.cpp8
-rw-r--r--src/opengl/qgl_p.h4
7 files changed, 337 insertions, 301 deletions
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
index e025736..0b93320 100644
--- a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
@@ -86,9 +86,8 @@ bool QGLCustomShaderStage::setOnPainter(QPainter* p)
return false;
}
- // Might as well go through the paint engine to get to the context
- const QGLContext* ctx = static_cast<QGL2PaintEngineEx*>(p->paintEngine())->context();
- d->m_manager = QGLEngineShaderManager::managerForContext(ctx);
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
Q_ASSERT(d->m_manager);
d->m_manager->setCustomStage(this);
@@ -101,9 +100,8 @@ void QGLCustomShaderStage::removeFromPainter(QPainter* p)
if (p->paintEngine()->type() != QPaintEngine::OpenGL2)
return;
- // Might as well go through the paint engine to get to the context
- const QGLContext* ctx = static_cast<QGL2PaintEngineEx*>(p->paintEngine())->context();
- d->m_manager = QGLEngineShaderManager::managerForContext(ctx);
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
Q_ASSERT(d->m_manager);
// Just set the stage to null, don't call removeCustomStage().
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index d48a7b6..e7c11fd 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -49,47 +49,38 @@
QT_BEGIN_NAMESPACE
-static void QGLEngineShaderManager_free(void *ptr)
+static void qt_shared_shaders_free(void *data)
{
- delete reinterpret_cast<QGLEngineShaderManager *>(ptr);
+ delete reinterpret_cast<QGLEngineSharedShaders *>(data);
}
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shader_managers, (QGLEngineShaderManager_free))
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
-QGLEngineShaderManager *QGLEngineShaderManager::managerForContext(const QGLContext *context)
+QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
{
- QGLEngineShaderManager *p = reinterpret_cast<QGLEngineShaderManager *>(qt_shader_managers()->value(context));
+ QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
if (!p) {
QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
if (oldContext != context)
const_cast<QGLContext *>(context)->makeCurrent();
- p = new QGLEngineShaderManager(const_cast<QGLContext *>(context));
- qt_shader_managers()->insert(context, p);
+ qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
if (oldContext && oldContext != context)
oldContext->makeCurrent();
}
return p;
}
-const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = {
+const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = {
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,
0,0,0,0,0
};
-QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
- : ctx(context),
- shaderProgNeedsChanging(true),
- srcPixelType(Qt::NoBrush),
- useGlobalOpacity(false),
- maskType(NoMask),
- useTextureCoords(false),
- compositionMode(QPainter::CompositionMode_SourceOver),
- customSrcStage(0),
- blitShaderProg(0),
- simpleShaderProg(0),
- currentShaderProg(0)
+QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
+ : ctx(QGLContextPrivate::contextGroup(context))
+ , blitShaderProg(0)
+ , simpleShaderProg(0)
{
memset(compiledShaders, 0, sizeof(compiledShaders));
@@ -174,7 +165,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
}
// Compile up the simple shader:
- simpleShaderProg = new QGLShaderProgram(ctx, this);
+ simpleShaderProg = new QGLShaderProgram(context, this);
compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader);
compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader);
compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
@@ -191,7 +182,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
}
// Compile the blit shader:
- blitShaderProg = new QGLShaderProgram(ctx, this);
+ blitShaderProg = new QGLShaderProgram(context, this);
compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader);
compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader);
compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
@@ -209,6 +200,145 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
}
}
+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--);
+ }
+ }
+
+ emit shaderProgNeedsChanging();
+}
+
+QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader::ShaderType type)
+{
+ Q_ASSERT(name != CustomImageSrcFragmentShader);
+ if (compiledShaders[name])
+ return compiledShaders[name];
+
+ QByteArray source = qglEngineShaderSourceCode[name];
+ QGLShader *newShader = new QGLShader(type, ctx->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;
+}
+
+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, ctx->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];
+ }
+
+ cachedPrograms.append(prog);
+ QGLEngineShaderProg &cached = cachedPrograms.last();
+
+ // If the shader program's not found in the cache, create it now.
+ cached.program = new QGLShaderProgram(ctx->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);
+
+ // We have to bind the vertex attribute names before the program is linked:
+ cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ cached.program->link();
+ if (!cached.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
+#endif
+ + QLatin1String(" Error Log:\n")
+ + QLatin1String(" ") + cached.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;
+ }
+}
+
+QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
+ : ctx(context),
+ shaderProgNeedsChanging(true),
+ srcPixelType(Qt::NoBrush),
+ useGlobalOpacity(false),
+ maskType(NoMask),
+ useTextureCoords(false),
+ compositionMode(QPainter::CompositionMode_SourceOver),
+ customSrcStage(0),
+ currentShaderProg(0),
+ customShader(0)
+{
+ sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
+ connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
+}
+
QGLEngineShaderManager::~QGLEngineShaderManager()
{
//###
@@ -312,24 +442,8 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
{
- // If the custom shader has changed, then destroy the previous compilation.
- if (customSrcStage && stage && customSrcStage != stage)
- removeCustomStage(customSrcStage);
-
customSrcStage = stage;
- shaderProgNeedsChanging = true;
-}
-
-void QGLEngineShaderManager::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--);
- }
- }
-
+ customShader = 0; // Will be compiled from 'customSrcStage' later.
shaderProgNeedsChanging = true;
}
@@ -337,13 +451,8 @@ void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
{
Q_UNUSED(stage); // Currently we only support one at a time...
- QGLShader *compiledShader = compiledShaders[CustomImageSrcFragmentShader];
-
- if (!compiledShader)
- return;
-
- compiledShaders[CustomImageSrcFragmentShader] = 0;
customSrcStage = 0;
+ customShader = 0;
shaderProgNeedsChanging = true;
}
@@ -355,12 +464,12 @@ QGLShaderProgram* QGLEngineShaderManager::currentProgram()
QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
{
- return simpleShaderProg;
+ return sharedShaders->simpleProgram();
}
QGLShaderProgram* QGLEngineShaderManager::blitProgram()
{
- return blitShaderProg;
+ return sharedShaders->blitProgram();
}
@@ -382,26 +491,25 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
requiredProgram.program = 0;
// Choose vertex shader main function
- QGLEngineShaderManager::ShaderName mainVertexShaderName = InvalidShaderName;
+ QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
if (useTextureCoords)
- mainVertexShaderName = MainWithTexCoordsVertexShader;
+ mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
else
- mainVertexShaderName = MainVertexShader;
- compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader);
- requiredProgram.mainVertexShader = compiledShaders[mainVertexShaderName];
+ mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader;
+ requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader);
// Choose vertex shader shader position function (which typically also sets
// varyings) and the source pixel (srcPixel) fragment shader function:
- QGLEngineShaderManager::ShaderName positionVertexShaderName = InvalidShaderName;
- QGLEngineShaderManager::ShaderName srcPixelFragShaderName = InvalidShaderName;
+ QGLEngineSharedShaders::ShaderName positionVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
+ QGLEngineSharedShaders::ShaderName srcPixelFragShaderName = QGLEngineSharedShaders::InvalidShaderName;
bool isAffine = brushTransform.isAffine();
if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
if (isAffine)
- positionVertexShaderName = AffinePositionWithPatternBrushVertexShader;
+ positionVertexShaderName = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
else
- positionVertexShaderName = PositionWithPatternBrushVertexShader;
+ positionVertexShaderName = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
- srcPixelFragShaderName = PatternBrushSrcFragmentShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
}
else switch (srcPixelType) {
default:
@@ -409,204 +517,143 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set");
break;
case QGLEngineShaderManager::ImageSrc:
- srcPixelFragShaderName = useCustomSrc ? CustomImageSrcFragmentShader : ImageSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcFragmentShader;
+ positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case QGLEngineShaderManager::NonPremultipliedImageSrc:
- srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
+ positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case QGLEngineShaderManager::PatternSrc:
- srcPixelFragShaderName = ImageSrcWithPatternFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
+ positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case QGLEngineShaderManager::TextureSrcWithPattern:
- srcPixelFragShaderName = TextureBrushSrcWithPatternFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader
- : PositionWithTextureBrushVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
+ positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
case Qt::SolidPattern:
- srcPixelFragShaderName = SolidBrushSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
+ positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case Qt::LinearGradientPattern:
- srcPixelFragShaderName = LinearGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithLinearGradientBrushVertexShader
- : PositionWithLinearGradientBrushVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
+ positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
break;
case Qt::ConicalGradientPattern:
- srcPixelFragShaderName = ConicalGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithConicalGradientBrushVertexShader
- : PositionWithConicalGradientBrushVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
+ positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
break;
case Qt::RadialGradientPattern:
- srcPixelFragShaderName = RadialGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithRadialGradientBrushVertexShader
- : PositionWithRadialGradientBrushVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
+ positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
break;
case Qt::TexturePattern:
- srcPixelFragShaderName = TextureBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader
- : PositionWithTextureBrushVertexShader;
+ srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
+ positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
};
- compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader);
- compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName];
- requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName];
+ 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);
+ }
const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
// Choose fragment shader main function:
- QGLEngineShaderManager::ShaderName mainFragShaderName;
+ QGLEngineSharedShaders::ShaderName mainFragShaderName;
if (hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CMO;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO;
if (hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CM;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM;
if (!hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_MO;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO;
if (!hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_M;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M;
if (hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CO;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO;
if (hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_C;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C;
if (!hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_O;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O;
if (!hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader;
+ mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader;
- compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.mainFragShader = compiledShaders[mainFragShaderName];
+ requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader);
if (hasMask) {
- QGLEngineShaderManager::ShaderName maskShaderName = QGLEngineShaderManager::InvalidShaderName;
+ QGLEngineSharedShaders::ShaderName maskShaderName = QGLEngineSharedShaders::InvalidShaderName;
if (maskType == PixelMask)
- maskShaderName = MaskFragmentShader;
+ maskShaderName = QGLEngineSharedShaders::MaskFragmentShader;
else if (maskType == SubPixelMask)
- maskShaderName = RgbMaskFragmentShader;
+ maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShader;
else if (maskType == SubPixelWithGammaMask)
- maskShaderName = RgbMaskWithGammaFragmentShader;
+ maskShaderName = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
else
qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
- compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.maskFragShader = compiledShaders[maskShaderName];
- }
- else
+ requiredProgram.maskFragShader = sharedShaders->compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader);
+ } else {
requiredProgram.maskFragShader = 0;
+ }
if (hasCompose) {
- QGLEngineShaderManager::ShaderName compositionShaderName = QGLEngineShaderManager::InvalidShaderName;
+ QGLEngineSharedShaders::ShaderName compositionShaderName = QGLEngineSharedShaders::InvalidShaderName;
switch (compositionMode) {
case QPainter::CompositionMode_Multiply:
- compositionShaderName = MultiplyCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Screen:
- compositionShaderName = ScreenCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Overlay:
- compositionShaderName = OverlayCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Darken:
- compositionShaderName = DarkenCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Lighten:
- compositionShaderName = LightenCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorDodge:
- compositionShaderName = ColorDodgeCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorBurn:
- compositionShaderName = ColorBurnCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_HardLight:
- compositionShaderName = HardLightCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_SoftLight:
- compositionShaderName = SoftLightCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Difference:
- compositionShaderName = DifferenceCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Exclusion:
- compositionShaderName = ExclusionCompositionModeFragmentShader;
+ compositionShaderName = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
break;
default:
qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
}
- compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.compositionFragShader = compiledShaders[compositionShaderName];
- }
- else
+ requiredProgram.compositionFragShader = sharedShaders->compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader);
+ } else {
requiredProgram.compositionFragShader = 0;
-
- // At this point, requiredProgram is fully populated so try to find the program in the cache
- bool foundProgramInCache = false;
- for (int i = 0; i < cachedPrograms.size(); ++i) {
- if (cachedPrograms[i] == requiredProgram) {
- currentShaderProg = &cachedPrograms[i];
- foundProgramInCache = true;
- break;
- }
}
- // If the shader program's not found in the cache, create it now.
- if (!foundProgramInCache) {
- requiredProgram.program = new QGLShaderProgram(ctx, this);
- requiredProgram.program->addShader(requiredProgram.mainVertexShader);
- requiredProgram.program->addShader(requiredProgram.positionVertexShader);
- requiredProgram.program->addShader(requiredProgram.mainFragShader);
- requiredProgram.program->addShader(requiredProgram.srcPixelFragShader);
- requiredProgram.program->addShader(requiredProgram.maskFragShader);
- requiredProgram.program->addShader(requiredProgram.compositionFragShader);
-
- // We have to bind the vertex attribute names before the program is linked:
- requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- if (useTextureCoords)
- requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
-
- requiredProgram.program->link();
- if (!requiredProgram.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 = ")
- + (requiredProgram.mainVertexShader ?
- requiredProgram.mainVertexShader->objectName() : none) + br
- + QLatin1String(" positionVertexShader = ")
- + (requiredProgram.positionVertexShader ?
- requiredProgram.positionVertexShader->objectName() : none) + br
- + QLatin1String(" mainFragShader = ")
- + (requiredProgram.mainFragShader ?
- requiredProgram.mainFragShader->objectName() : none) + br
- + QLatin1String(" srcPixelFragShader = ")
- + (requiredProgram.srcPixelFragShader ?
- requiredProgram.srcPixelFragShader->objectName() : none) + br
- + QLatin1String(" maskFragShader = ")
- + (requiredProgram.maskFragShader ?
- requiredProgram.maskFragShader->objectName() : none) + br
- + QLatin1String(" compositionFragShader = ")
- + (requiredProgram.compositionFragShader ?
- requiredProgram.compositionFragShader->objectName() : none) + br
-#endif
- + QLatin1String(" Error Log:\n")
- + QLatin1String(" ") + requiredProgram.program->log();
- qWarning() << error;
- delete requiredProgram.program;
- } else {
- cachedPrograms.append(requiredProgram);
- // taking the address here is safe since
- // cachePrograms isn't resized anywhere else
- currentShaderProg = &cachedPrograms.last();
- }
- }
+ // At this point, requiredProgram is fully populated so try to find the program in the cache
+ currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
if (currentShaderProg) {
currentShaderProg->program->enable();
@@ -618,40 +665,4 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
return true;
}
-void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type)
-{
- if (compiledShaders[name])
- return;
-
- QGLShader *newShader;
-
- QByteArray source;
- if (name == CustomImageSrcFragmentShader) {
- source = customSrcStage->source();
- source += qglslCustomSrcFragmentShader;
-
- newShader = customShaderCache.object(source);
- if (!newShader) {
- newShader = new QGLShader(type, ctx, this);
- newShader->compile(source);
- customShaderCache.insert(source, newShader);
-
- connect(newShader, SIGNAL(destroyed(QObject *)),
- this, SLOT(shaderDestroyed(QObject *)));
- }
- } else {
- source = qglEngineShaderSourceCode[name];
- newShader = new QGLShader(type, ctx, 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;
-}
-
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 99cd82e..0cfdcf1 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -275,65 +275,10 @@ struct QGLEngineCachedShaderProg
static const GLuint QT_VERTEX_COORDS_ATTR = 0;
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
-class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
+class QGLEngineSharedShaders : public QObject
{
Q_OBJECT
public:
- QGLEngineShaderManager(QGLContext* context);
- ~QGLEngineShaderManager();
-
- enum MaskType {NoMask, PixelMask, SubPixelMask, SubPixelWithGammaMask};
- enum PixelSrcType {
- ImageSrc = Qt::TexturePattern+1,
- NonPremultipliedImageSrc = Qt::TexturePattern+2,
- PatternSrc = Qt::TexturePattern+3,
- TextureSrcWithPattern = Qt::TexturePattern+4
- };
-
- enum Uniform {
- ImageTexture,
- PatternColor,
- GlobalOpacity,
- Depth,
- PmvMatrix,
- MaskTexture,
- FragmentColor,
- LinearData,
- Angle,
- HalfViewportSize,
- Fmp,
- Fmp2MRadius2,
- Inverse2Fmp2MRadius2,
- InvertedTextureSize,
- BrushTransform,
- BrushTexture,
- NumUniforms
- };
-
- // There are optimisations we can do, depending on the brush transform:
- // 1) May not have to apply perspective-correction
- // 2) Can use lower precision for matrix
- void optimiseForBrushTransform(const QTransform &transform);
- void setSrcPixelType(Qt::BrushStyle);
- void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
- void setTextureCoordsEnabled(bool); // For images & text glyphs
- void setUseGlobalOpacity(bool);
- void setMaskType(MaskType);
- void setCompositionMode(QPainter::CompositionMode);
- void setCustomStage(QGLCustomShaderStage* stage);
- void removeCustomStage(QGLCustomShaderStage* stage);
-
- uint getUniformLocation(Uniform id);
-
- void setDirty(); // someone has manually changed the current shader program
- bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
-
- QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
- QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
- QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
-
- static QGLEngineShaderManager *managerForContext(const QGLContext *context);
-
enum ShaderName {
MainVertexShader,
MainWithTexCoordsVertexShader,
@@ -392,6 +337,92 @@ public:
TotalShaderCount, InvalidShaderName
};
+ QGLEngineSharedShaders(const QGLContext *context);
+
+ QGLShader *compileNamedShader(ShaderName name, QGLShader::ShaderType type);
+
+ 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);
+
+signals:
+ void shaderProgNeedsChanging();
+
+private slots:
+ void shaderDestroyed(QObject *shader);
+
+private:
+ QGLContextGroup *ctx;
+ QGLShaderProgram *blitShaderProg;
+ QGLShaderProgram *simpleShaderProg;
+ QList<QGLEngineShaderProg> cachedPrograms;
+ QCache<QByteArray, QGLShader> customShaderCache;
+ QGLShader* compiledShaders[TotalShaderCount];
+
+ static const char* qglEngineShaderSourceCode[TotalShaderCount];
+};
+
+class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGLEngineShaderManager(QGLContext* context);
+ ~QGLEngineShaderManager();
+
+ enum MaskType {NoMask, PixelMask, SubPixelMask, SubPixelWithGammaMask};
+ enum PixelSrcType {
+ ImageSrc = Qt::TexturePattern+1,
+ NonPremultipliedImageSrc = Qt::TexturePattern+2,
+ PatternSrc = Qt::TexturePattern+3,
+ TextureSrcWithPattern = Qt::TexturePattern+4
+ };
+
+ enum Uniform {
+ ImageTexture,
+ PatternColor,
+ GlobalOpacity,
+ Depth,
+ PmvMatrix,
+ MaskTexture,
+ FragmentColor,
+ LinearData,
+ Angle,
+ HalfViewportSize,
+ Fmp,
+ Fmp2MRadius2,
+ Inverse2Fmp2MRadius2,
+ InvertedTextureSize,
+ BrushTransform,
+ BrushTexture,
+ NumUniforms
+ };
+
+ // There are optimisations we can do, depending on the brush transform:
+ // 1) May not have to apply perspective-correction
+ // 2) Can use lower precision for matrix
+ void optimiseForBrushTransform(const QTransform &transform);
+ void setSrcPixelType(Qt::BrushStyle);
+ void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
+ void setTextureCoordsEnabled(bool); // For images & text glyphs
+ void setUseGlobalOpacity(bool);
+ void setMaskType(MaskType);
+ void setCompositionMode(QPainter::CompositionMode);
+ void setCustomStage(QGLCustomShaderStage* stage);
+ void removeCustomStage(QGLCustomShaderStage* stage);
+
+ uint getUniformLocation(Uniform id);
+
+ void setDirty(); // someone has manually changed the current shader program
+ bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
+
+ QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
+ 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
@@ -408,7 +439,7 @@ public:
#endif
private slots:
- void shaderDestroyed(QObject *shader);
+ void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
private:
QGLContext* ctx;
@@ -423,19 +454,9 @@ private:
QPainter::CompositionMode compositionMode;
QGLCustomShaderStage* customSrcStage;
- QGLShaderProgram* blitShaderProg;
- QGLShaderProgram* simpleShaderProg;
QGLEngineShaderProg* currentShaderProg;
-
- // TODO: Possibly convert to a LUT
- QList<QGLEngineShaderProg> cachedPrograms;
- QCache<QByteArray, QGLShader> customShaderCache;
-
- QGLShader* compiledShaders[TotalShaderCount];
-
- void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type);
-
- static const char* qglEngineShaderSourceCode[TotalShaderCount];
+ QGLEngineSharedShaders *sharedShaders;
+ QGLShader *customShader;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 0c01263..7271740 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -316,6 +316,7 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert);
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
{
+ delete shaderManager;
}
void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
@@ -1330,7 +1331,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
qt_resolve_version_2_0_functions(d->ctx);
#endif
- d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
+ if (!d->shaderManager)
+ d->shaderManager = new QGLEngineShaderManager(d->ctx);
d->shaderManager->setDirty();
glViewport(0, 0, d->width, d->height);
@@ -1430,11 +1432,13 @@ void QGL2PaintEngineEx::ensureActive()
p->transferMode(BrushDrawingMode);
p->drawable.doneCurrent();
}
+ d->drawable.context()->makeCurrent();
d->drawable.makeCurrent();
ctx->d_ptr->active_engine = this;
-
d->needsSync = true;
+ } else {
+ d->drawable.context()->makeCurrent();
}
if (d->needsSync) {
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 552e390..cb23b11 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -196,6 +196,8 @@ public:
float zValueForRenderText() const;
+ static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
+
QGL2PaintEngineEx* q;
QGLDrawable drawable;
int width, height;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 8b7674e..1d765f8 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -4922,13 +4922,13 @@ void QGLShareRegister::removeShare(const QGLContext *context) {
QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent)
: QObject(parent), free(f)
{
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *)));
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(removeOne(const QGLContext *)));
}
QGLContextResource::~QGLContextResource()
{
while (!m_resources.empty())
- remove(m_resources.begin().key());
+ removeGroup(m_resources.begin().key());
}
void QGLContextResource::insert(const QGLContext *key, void *value)
@@ -4976,7 +4976,7 @@ void *QGLContextResource::value(const QGLContext *key)
return it.value();
}
-void QGLContextResource::remove(const QGLContext *key)
+void QGLContextResource::removeGroup(const QGLContext *key)
{
QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
if (shares.size() == 0)
@@ -5000,7 +5000,7 @@ void QGLContextResource::remove(const QGLContext *key)
}
}
-void QGLContextResource::aboutToDestroyContext(const QGLContext *key)
+void QGLContextResource::removeOne(const QGLContext *key)
{
ResourceHash::iterator it = m_resources.find(key);
if (it == m_resources.end())
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index a39c52c..72ec35e 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -540,10 +540,10 @@ public:
// Return resource for 'key' or a shared context.
void *value(const QGLContext *key);
// Free resource for 'key' and all its shared contexts.
- void remove(const QGLContext *key);
+ void removeGroup(const QGLContext *key);
private slots:
// Remove entry 'key' from cache and delete resource if there are no shared contexts.
- void aboutToDestroyContext(const QGLContext *key);
+ void removeOne(const QGLContext *key);
private:
typedef QHash<const QGLContext *, void *> ResourceHash;
ResourceHash m_resources;