summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp10
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp433
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h159
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp74
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h21
-rw-r--r--src/opengl/qgl.cpp52
-rw-r--r--src/opengl/qgl_p.h4
-rw-r--r--src/opengl/qglextensions_p.h4
-rw-r--r--src/opengl/qglframebufferobject.cpp89
-rw-r--r--src/opengl/qglframebufferobject.h18
-rw-r--r--src/opengl/qglpixelbuffer.cpp4
-rw-r--r--src/opengl/qglpixmapfilter.cpp2
-rw-r--r--src/opengl/qglshaderprogram.cpp21
-rw-r--r--src/opengl/qpixmapdata_gl.cpp2
-rw-r--r--src/opengl/qwindowsurface_gl.cpp2
-rwxr-xr-xsrc/opengl/util/glsl_to_include.sh40
16 files changed, 555 insertions, 380 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 891c027..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,190 +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()) {
- QString error;
- qWarning() << "Shader program failed to link,"
-#if defined(QT_DEBUG)
- << '\n'
- << " Shaders Used:" << '\n'
- << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n'
- << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n'
- << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n'
- << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n'
- << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n'
- << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n'
-#endif
- << " Error Log:" << '\n'
- << " " << 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();
@@ -604,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 a976a02..e24539b 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)
@@ -380,7 +381,7 @@ void QGL2PaintEngineExPrivate::useSimpleShader()
}
if (simpleShaderDepthUniformDirty) {
- shaderManager->simpleProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth);
+ shaderManager->simpleProgram()->setUniformValue("depth", normalizedDeviceDepth(q->state()->currentDepth));
simpleShaderDepthUniformDirty = false;
}
}
@@ -731,7 +732,6 @@ void QGL2PaintEngineExPrivate::resetGLState()
glActiveTexture(GL_TEXTURE0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
- glDepthFunc(GL_LESS);
glDepthMask(true);
glClearDepth(1);
}
@@ -959,7 +959,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
}
if (depthUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), (GLfloat)q->state()->currentDepth);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), normalizedDeviceDepth(q->state()->currentDepth));
depthUniformDirty = false;
}
@@ -1331,8 +1331,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
qt_resolve_version_2_0_functions(d->ctx);
#endif
- d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
- d->shaderManager->setDirty();
+ d->shaderManager = new QGLEngineShaderManager(d->ctx);
glViewport(0, 0, d->width, d->height);
@@ -1351,7 +1350,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
if (!d->inRenderText) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
- glDepthFunc(GL_LEQUAL);
+ glDepthFunc(GL_LESS);
glDepthMask(false);
}
@@ -1416,6 +1415,9 @@ bool QGL2PaintEngineEx::end()
d->resetGLState();
+ delete d->shaderManager;
+ d->shaderManager = 0;
+
return false;
}
@@ -1431,17 +1433,19 @@ 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) {
glViewport(0, 0, d->width, d->height);
glDepthMask(false);
- glDepthFunc(GL_LEQUAL);
+ glDepthFunc(GL_LESS);
setState(state());
d->needsSync = false;
}
@@ -1492,7 +1496,7 @@ void QGL2PaintEngineEx::clipEnabledChanged()
d->regenerateDepthClip();
} else {
if (d->use_system_clip) {
- state()->currentDepth = -0.5f;
+ state()->currentDepth = 0;
} else {
state()->depthTestEnabled = false;
}
@@ -1501,7 +1505,7 @@ void QGL2PaintEngineEx::clipEnabledChanged()
}
}
-void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth)
+void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint depth)
{
transferMode(BrushDrawingMode);
@@ -1510,7 +1514,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth)
if (q->state()->needsDepthBufferClear) {
glDepthMask(true);
- glClearDepth(0.5);
+ glClearDepth(rawDepth(2));
glClear(GL_DEPTH_BUFFER_BIT);
q->state()->needsDepthBufferClear = false;
glDepthMask(false);
@@ -1532,7 +1536,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth)
glColorMask(false, false, false, false);
glDepthMask(true);
- shaderManager->simpleProgram()->setUniformValue("depth", depth);
+ shaderManager->simpleProgram()->setUniformValue("depth", normalizedDeviceDepth(depth));
simpleShaderDepthUniformDirty = true;
glEnable(GL_DEPTH_TEST);
@@ -1596,12 +1600,12 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
glDepthFunc(GL_ALWAYS);
- state()->maxDepth = 0.5f;
+ state()->maxDepth = 4;
d->writeClip(qtVectorPathForPath(path), state()->maxDepth);
- state()->currentDepth = 0.25f;
+ state()->currentDepth = 3;
state()->depthTestEnabled = true;
- glDepthFunc(GL_LEQUAL);
+ glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}
@@ -1610,7 +1614,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
if (d->use_system_clip) {
glEnable(GL_DEPTH_TEST);
state()->depthTestEnabled = true;
- state()->currentDepth = -0.5;
+ state()->currentDepth = 0;
} else {
glDisable(GL_DEPTH_TEST);
state()->depthTestEnabled = false;
@@ -1618,18 +1622,18 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
state()->canRestoreClip = false;
break;
case Qt::IntersectClip:
- state()->maxDepth = (1.0f + state()->maxDepth) * 0.5;
+ ++state()->maxDepth;
d->writeClip(path, state()->maxDepth);
- state()->currentDepth = 1.5 * state()->maxDepth - 0.5f;
+ state()->currentDepth = state()->maxDepth - 1;
state()->depthTestEnabled = true;
break;
case Qt::ReplaceClip:
d->systemStateChanged();
state()->rectangleClip = QRect();
- state()->maxDepth = 0.5f;
+ state()->maxDepth = 4;
glDepthFunc(GL_ALWAYS);
d->writeClip(path, state()->maxDepth);
- state()->currentDepth = 0.25f;
+ state()->currentDepth = 3;
state()->canRestoreClip = false;
state()->depthTestEnabled = true;
break;
@@ -1641,7 +1645,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
break;
}
- glDepthFunc(GL_LEQUAL);
+ glDepthFunc(GL_LESS);
if (state()->depthTestEnabled) {
glEnable(GL_DEPTH_TEST);
d->simpleShaderDepthUniformDirty = true;
@@ -1659,10 +1663,16 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
{
Q_Q(QGL2PaintEngineEx);
- if (q->paintDevice()->devType() == QInternal::Widget)
+ if (systemClip.isEmpty()) {
use_system_clip = false;
- else
- use_system_clip = !systemClip.isEmpty();
+ } else {
+ if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
+ QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
+ use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
+ } else {
+ use_system_clip = true;
+ }
+ }
glDisable(GL_DEPTH_TEST);
q->state()->depthTestEnabled = false;
@@ -1672,8 +1682,8 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
glDisable(GL_SCISSOR_TEST);
- q->state()->currentDepth = -0.5f;
- q->state()->maxDepth = 0.5f;
+ q->state()->currentDepth = 1;
+ q->state()->maxDepth = 4;
q->state()->rectangleClip = QRect(0, 0, width, height);
@@ -1708,8 +1718,8 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
path.addRegion(systemClip);
glDepthFunc(GL_ALWAYS);
- writeClip(qtVectorPathForPath(path), 0.0f);
- glDepthFunc(GL_LEQUAL);
+ writeClip(qtVectorPathForPath(path), 2);
+ glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
q->state()->depthTestEnabled = true;
@@ -1718,7 +1728,7 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
q->transformChanged();
}
- q->state()->currentDepth = -0.5f;
+ q->state()->currentDepth = 1;
simpleShaderDepthUniformDirty = true;
depthUniformDirty = true;
}
@@ -1757,7 +1767,7 @@ void QGL2PaintEngineEx::setState(QPainterState *new_state)
if (old_state && old_state != s && old_state->canRestoreClip) {
d->updateDepthScissorTest();
glDepthMask(false);
- glDepthFunc(GL_LEQUAL);
+ glDepthFunc(GL_LESS);
s->maxDepth = old_state->maxDepth;
} else {
d->regenerateDepthClip();
@@ -1802,8 +1812,8 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
needsDepthBufferClear = true;
depthTestEnabled = false;
scissorTestEnabled = false;
- currentDepth = -0.5f;
- maxDepth = 0.5f;
+ currentDepth = 1;
+ maxDepth = 4;
canRestoreClip = true;
hasRectangleClip = false;
}
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 58fcde1..cb23b11 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -82,8 +82,8 @@ public:
bool depthTestEnabled;
bool scissorTestEnabled;
- qreal currentDepth;
- qreal maxDepth;
+ uint maxDepth;
+ uint currentDepth;
bool canRestoreClip;
QRect rectangleClip;
@@ -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;
@@ -230,13 +232,26 @@ public:
QGLEngineShaderManager* shaderManager;
- void writeClip(const QVectorPath &path, float depth);
+ void writeClip(const QVectorPath &path, uint depth);
void updateDepthScissorTest();
void setScissor(const QRect &rect);
void regenerateDepthClip();
void systemStateChanged();
uint use_system_clip : 1;
+ static inline GLfloat rawDepth(uint depth)
+ {
+ // assume at least 16 bits in the depth buffer, and
+ // use 2^15 depth levels to be safe with regard to
+ // rounding issues etc
+ return depth * (1.0f / GLfloat((1 << 15) - 1));
+ }
+
+ static inline GLfloat normalizedDeviceDepth(uint depth)
+ {
+ return 2.0f * rawDepth(depth) - 1.0f;
+ }
+
uint location(QGLEngineShaderManager::Uniform uniform)
{
return shaderManager->getUniformLocation(uniform);
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 8b7674e..dde4eba 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -2005,9 +2005,15 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
QImage::Format target_format = img.format();
bool premul = options & QGLContext::PremultipliedAlphaBindOption;
- GLenum texture_format = QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2
- ? GL_BGRA : GL_RGBA;
- GLuint pixel_type = GL_UNSIGNED_BYTE;
+ GLenum texture_format;
+ GLuint pixel_type;
+ if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2) {
+ texture_format = GL_BGRA;
+ pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ } else {
+ texture_format = GL_RGBA;
+ pixel_type = GL_UNSIGNED_BYTE;
+ }
switch (target_format) {
case QImage::Format_ARGB32:
@@ -2034,7 +2040,6 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
if (format == GL_RGBA)
format = GL_RGB;
break;
-
default:
if (img.hasAlphaChannel()) {
img = img.convertToFormat(premul
@@ -2062,6 +2067,30 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
}
}
+ if (texture_format == GL_RGBA) {
+ // The only case where we end up with a depth different from
+ // 32 in the switch above is for the RGB16 case, where we set
+ // the format to GL_RGB
+ Q_ASSERT(img.depth() == 32);
+ const int width = img.width();
+ const int height = img.height();
+
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
+ || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
+ for (int i=0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x=0; x<width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x=0; x<width; ++x)
+ p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
+ }
+ }
+ }
+
const QImage &constRef = img; // to avoid detach in bits()...
glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format,
pixel_type, constRef.bits());
@@ -3533,12 +3562,7 @@ bool QGLWidget::event(QEvent *e)
#elif defined(Q_WS_WIN)
if (e->type() == QEvent::ParentChange) {
QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
- QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx);
- setContext(newContext);
- for (int i = 0; i < shares.size(); ++i) {
- if (newContext != shares.at(i))
- qgl_share_reg()->addShare(newContext, shares.at(i));
- }
+ setContext(newContext, d->glcx);
// the overlay needs to be recreated as well
delete d->olcx;
@@ -4922,13 +4946,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 +5000,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 +5024,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;
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index 8839f60..b1c9503 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -418,6 +418,10 @@ struct QGLExtensionFuncs
#define GL_UNSIGNED_SHORT_5_6_5 33635
#endif
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 9659654..a03e627 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -109,38 +109,28 @@ public:
*/
/*!
- Creates a QGLFramebufferObjectFormat object with properties specifying
+ Creates a QGLFramebufferObjectFormat object for specifying
the format of an OpenGL framebuffer object.
- A multisample framebuffer object is specified by setting \a samples
- to a value different from zero. If the desired amount of samples per pixel is
- not supported by the hardware then the maximum number of samples per pixel
- will be used. Note that multisample framebuffer objects can not be bound as
- textures. Also, the \c{GL_EXT_framebuffer_multisample} extension is required
- to create a framebuffer with more than one sample per pixel.
-
- For multisample framebuffer objects a color render buffer is created,
- otherwise a texture with the texture target \a target is created.
- The color render buffer or texture will have the internal format
- \a internalFormat, and will be bound to the \c GL_COLOR_ATTACHMENT0
- attachment in the framebuffer object.
-
- The \a attachment parameter describes the depth/stencil buffer
- configuration.
+ By default the format specifies a non-multisample framebuffer object with no
+ attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
\sa samples(), attachment(), target(), internalFormat()
*/
-QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples,
- QGLFramebufferObject::Attachment attachment,
- GLenum target,
- GLenum internalFormat)
+#ifndef QT_OPENGL_ES
+#define DEFAULT_FORMAT GL_RGBA8
+#else
+#define DEFAULT_FORMAT GL_RGBA
+#endif
+
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
{
d = new QGLFramebufferObjectFormatPrivate;
- d->samples = samples;
- d->attachment = attachment;
- d->target = target;
- d->internal_format = internalFormat;
+ d->samples = 0;
+ d->attachment = QGLFramebufferObject::NoAttachment;
+ d->target = GL_TEXTURE_2D;
+ d->internal_format = DEFAULT_FORMAT;
}
/*!
@@ -176,6 +166,12 @@ QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
to \a samples.
A sample count of 0 represents a regular non-multisample framebuffer object.
+ If the desired amount of samples per pixel is not supported by the hardware
+ then the maximum number of samples per pixel will be used. Note that
+ multisample framebuffer objects can not be bound as textures. Also, the
+ \c{GL_EXT_framebuffer_multisample} extension is required to create a
+ framebuffer with more than one sample per pixel.
+
\sa samples()
*/
void QGLFramebufferObjectFormat::setSamples(int samples)
@@ -195,7 +191,7 @@ int QGLFramebufferObjectFormat::samples() const
}
/*!
- Sets the attachments a framebuffer object should have to \a attachment.
+ Sets the attachment configuration of a framebuffer object to \a attachment.
\sa attachment()
*/
@@ -259,6 +255,20 @@ GLenum QGLFramebufferObjectFormat::internalFormat() const
return d->internal_format;
}
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
+{
+ d->target = target;
+}
+
+/*! \internal */
+void QGLFramebufferObjectFormat::setInternalFormat(QMacCompatGLenum internalFormat)
+{
+ d->internal_format = internalFormat;
+}
+#endif
+
class QGLFramebufferObjectPrivate
{
public:
@@ -526,6 +536,12 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
the constructors that take a QGLFramebufferObject parameter, and set the
QGLFramebufferObject::samples() property to a non-zero value.
+ For multisample framebuffer objects a color render buffer is created,
+ otherwise a texture with the specified texture target is created.
+ The color render buffer or texture will have the specified internal
+ format, and will be bound to the \c GL_COLOR_ATTACHMENT0
+ attachment in the framebuffer object.
+
If you want to use a framebuffer object with multisampling enabled
as a texture, you first need to copy from it to a regular framebuffer
object using QGLContext::blitFramebuffer().
@@ -579,12 +595,6 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
\sa size(), texture(), attachment()
*/
-#ifndef QT_OPENGL_ES
-#define DEFAULT_FORMAT GL_RGBA8
-#else
-#define DEFAULT_FORMAT GL_RGBA
-#endif
-
QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
@@ -875,9 +885,22 @@ QImage QGLFramebufferObject::toImage() const
if (!d->valid)
return QImage();
- const_cast<QGLFramebufferObject *>(this)->bind();
+ // qt_gl_read_framebuffer doesn't work on a multisample FBO
+ if (format().samples() != 0) {
+ QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
+
+ QRect rect(QPoint(0, 0), size());
+ blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
+
+ return temp.toImage();
+ }
+
+ bool wasBound = isBound();
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->bind();
QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true);
- const_cast<QGLFramebufferObject *>(this)->release();
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->release();
return image;
}
diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h
index cfc824b..ad14e50 100644
--- a/src/opengl/qglframebufferobject.h
+++ b/src/opengl/qglframebufferobject.h
@@ -137,18 +137,7 @@ class QGLFramebufferObjectFormatPrivate;
class Q_OPENGL_EXPORT QGLFramebufferObjectFormat
{
public:
-#if !defined(QT_OPENGL_ES) || defined(Q_QDOC)
- QGLFramebufferObjectFormat(int samples = 0,
- QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
- GLenum target = GL_TEXTURE_2D,
- GLenum internalFormat = GL_RGBA8);
-#else
- QGLFramebufferObjectFormat(int samples = 0,
- QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
- GLenum target = GL_TEXTURE_2D,
- GLenum internalFormat = GL_RGBA);
-#endif
-
+ QGLFramebufferObjectFormat();
QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other);
QGLFramebufferObjectFormat &operator=(const QGLFramebufferObjectFormat &other);
~QGLFramebufferObjectFormat();
@@ -165,6 +154,11 @@ public:
void setInternalFormat(GLenum internalFormat);
GLenum internalFormat() const;
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+ void setTextureTarget(QMacCompatGLenum target);
+ void setInternalFormat(QMacCompatGLenum internalFormat);
+#endif
+
private:
QGLFramebufferObjectFormatPrivate *d;
};
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 54d54e9..f082ff0 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -110,8 +110,10 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
invalid = false;
qctx = new QGLContext(format);
qctx->d_func()->sharing = (shareWidget != 0);
- if (shareWidget != 0 && shareWidget->d_func()->glcx)
+ if (shareWidget != 0 && shareWidget->d_func()->glcx) {
qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
+ shareWidget->d_func()->glcx->d_func()->sharing = true;
+ }
qctx->d_func()->paintDevice = q;
qctx->d_func()->valid = true;
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index c51ccc7..56e5baa 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -324,7 +324,7 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const
filter->setSource(generateBlurShader(radius(), quality() == Qt::SmoothTransformation));
QGLFramebufferObjectFormat format;
- format.setInternalFormat(src.hasAlphaChannel() ? GL_RGBA : GL_RGB);
+ format.setInternalFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB));
QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(src.size(), format);
if (!fbo)
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
index c4d9322..56b55d0 100644
--- a/src/opengl/qglshaderprogram.cpp
+++ b/src/opengl/qglshaderprogram.cpp
@@ -501,6 +501,25 @@ bool QGLShader::compile(const char *source)
return d->compile(this);
} else if (d->shader) {
QVarLengthArray<const char *> src;
+ int headerLen = 0;
+ while (source && source[headerLen] == '#') {
+ // Skip #version and #extension directives at the start of
+ // the shader code. We need to insert the qualifierDefines
+ // and redefineHighp just after them.
+ if (qstrncmp(source + headerLen, "#version", 8) != 0 &&
+ qstrncmp(source + headerLen, "#extension", 10) != 0) {
+ break;
+ }
+ while (source[headerLen] != '\0' && source[headerLen] != '\n')
+ ++headerLen;
+ if (source[headerLen] == '\n')
+ ++headerLen;
+ }
+ QByteArray header;
+ if (headerLen > 0) {
+ header = QByteArray(source, headerLen);
+ src.append(header.constData());
+ }
#ifdef QGL_DEFINE_QUALIFIERS
src.append(qualifierDefines);
#endif
@@ -509,7 +528,7 @@ bool QGLShader::compile(const char *source)
d->shaderType == PartialFragmentShader)
src.append(redefineHighp);
#endif
- src.append(source);
+ src.append(source + headerLen);
QGLContextGroup *ctx = d->ctx;
glShaderSource(d->shader, src.size(), src.data(), 0);
return d->compile(this);
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index 5e87e96..b6f5012 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -467,7 +467,7 @@ QPaintEngine* QGLPixmapData::paintEngine() const
QGLFramebufferObjectFormat format;
format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
format.setSamples(4);
- format.setInternalFormat(m_hasAlpha ? GL_RGBA : GL_RGB);
+ format.setInternalFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index a59501c..f974938 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -569,7 +569,7 @@ void QGLWindowSurface::updateGeometry()
QGLFramebufferObjectFormat format;
format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- format.setInternalFormat(GL_RGBA);
+ format.setInternalFormat(GLenum(GL_RGBA));
format.setTextureTarget(target);
if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
diff --git a/src/opengl/util/glsl_to_include.sh b/src/opengl/util/glsl_to_include.sh
index 59d4693..083ad1e 100755
--- a/src/opengl/util/glsl_to_include.sh
+++ b/src/opengl/util/glsl_to_include.sh
@@ -1,4 +1,44 @@
#! /bin/sh
+#############################################################################
+##
+## Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+## Contact: Nokia Corporation (qt-info@nokia.com)
+##
+## This file is the build configuration utility of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, Nokia gives you certain
+## additional rights. These rights are described in the Nokia Qt LGPL
+## Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+## package.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
# Compile a .glsl file to a file that can be included in a C++ program
USAGE="Usage: $0 <file.glsl>"