summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authoraxis <qt-info@nokia.com>2009-11-04 14:07:39 (GMT)
committeraxis <qt-info@nokia.com>2009-11-04 14:07:39 (GMT)
commit9cda9fb4bb496a7c589767bdcead131dbcdeeb79 (patch)
tree2302096f06d4629ea62a85317429daa74ce6f02d /src/opengl
parentbe6357bfa96cdaffa5797fef99e95cac7121e5b3 (diff)
parent7905101fb5ef18c776be515b9287356b1efc5ceb (diff)
downloadQt-9cda9fb4bb496a7c589767bdcead131dbcdeeb79.zip
Qt-9cda9fb4bb496a7c589767bdcead131dbcdeeb79.tar.gz
Qt-9cda9fb4bb496a7c589767bdcead131dbcdeeb79.tar.bz2
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6-s60
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp21
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage_p.h3
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp422
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h131
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h1
-rw-r--r--src/opengl/gl2paintengineex/qtriangulatingstroker.cpp2
-rw-r--r--src/opengl/qgl.cpp49
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_x11.cpp3
-rw-r--r--src/opengl/qgl_x11egl.cpp3
-rw-r--r--src/opengl/qglpixmapfilter.cpp423
-rw-r--r--src/opengl/qglshaderprogram.cpp182
-rw-r--r--src/opengl/qglshaderprogram.h9
-rw-r--r--src/opengl/qpixmapdata_gl.cpp19
-rw-r--r--src/opengl/qpixmapdata_gl_p.h2
15 files changed, 758 insertions, 513 deletions
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
index ab2026c..b71a7b7 100644
--- a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
@@ -67,8 +67,10 @@ QGLCustomShaderStage::QGLCustomShaderStage()
QGLCustomShaderStage::~QGLCustomShaderStage()
{
Q_D(QGLCustomShaderStage);
- if (d->m_manager)
- d->m_manager->removeCustomStage(this);
+ if (d->m_manager) {
+ d->m_manager->removeCustomStage();
+ d->m_manager->sharedShaders->cleanupCustomStage(this);
+ }
}
void QGLCustomShaderStage::setUniformsDirty()
@@ -85,6 +87,8 @@ bool QGLCustomShaderStage::setOnPainter(QPainter* p)
qWarning("QGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2");
return false;
}
+ if (d->m_manager)
+ qWarning("Custom shader is already set on a painter");
QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
@@ -108,12 +112,21 @@ void QGLCustomShaderStage::removeFromPainter(QPainter* p)
// This should leave the program in a compiled/linked state
// if the next custom shader stage is this one again.
d->m_manager->setCustomStage(0);
+ d->m_manager = 0;
}
-const char* QGLCustomShaderStage::source() const
+QByteArray QGLCustomShaderStage::source() const
{
Q_D(const QGLCustomShaderStage);
- return d->m_source.constData();
+ return d->m_source;
+}
+
+// Called by the shader manager if another custom shader is attached or
+// the manager is deleted
+void QGLCustomShaderStage::setInactive()
+{
+ Q_D(QGLCustomShaderStage);
+ d->m_manager = 0;
}
void QGLCustomShaderStage::setSource(const QByteArray& s)
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
index f8c13c5..e319389 100644
--- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
@@ -74,8 +74,9 @@ public:
bool setOnPainter(QPainter*);
void removeFromPainter(QPainter*);
- const char* source() const;
+ QByteArray source() const;
+ void setInactive();
protected:
void setSource(const QByteArray&);
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index af9306f..40a6241 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -66,7 +66,7 @@ QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLConte
return p;
}
-const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = {
+const char* QGLEngineSharedShaders::qShaderSnippets[] = {
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
@@ -78,7 +78,6 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
, blitShaderProg(0)
, simpleShaderProg(0)
{
- memset(compiledShaders, 0, sizeof(compiledShaders));
/*
Rather than having the shader source array statically initialised, it is initialised
@@ -86,10 +85,10 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
around without having to change the order of the glsl strings. It is hoped this will
make future hard-to-find runtime bugs more obvious and generally give more solid code.
*/
- static bool qglEngineShaderSourceCodePopulated = false;
- if (!qglEngineShaderSourceCodePopulated) {
+ static bool snippetsPopulated = false;
+ if (!snippetsPopulated) {
- const char** code = qglEngineShaderSourceCode; // shortcut
+ const char** code = qShaderSnippets; // shortcut
code[MainVertexShader] = qglslMainVertexShader;
code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
@@ -121,7 +120,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
- code[CustomImageSrcFragmentShader] = ""; // Supplied by app.
+ code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
@@ -131,11 +130,13 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;
+ code[NoMaskFragmentShader] = "";
code[MaskFragmentShader] = qglslMaskFragmentShader;
code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
code[RgbMaskWithGammaFragmentShader] = ""; //###
+ code[NoCompositionModeFragmentShader] = "";
code[MultiplyCompositionModeFragmentShader] = ""; //###
code[ScreenCompositionModeFragmentShader] = ""; //###
code[OverlayCompositionModeFragmentShader] = ""; //###
@@ -150,29 +151,36 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
- for (int i = 0; i < TotalShaderCount; ++i) {
- if (qglEngineShaderSourceCode[i] == 0) {
- int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName");
- QMetaEnum m = staticMetaObject.enumerator(enumIndex);
-
- qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i)
- << "(shader" << i << ") missing!";
+ for (int i = 0; i < TotalSnippetCount; ++i) {
+ if (qShaderSnippets[i] == 0) {
+ qFatal("Shader snippet for %s (#%d) is missing!",
+ snippetNameStr(SnippetName(i)).constData(), i);
}
}
#endif
- qglEngineShaderSourceCodePopulated = true;
+ snippetsPopulated = true;
}
+ QGLShader* fragShader;
+ QGLShader* vertexShader;
+ QByteArray source;
+
// Compile up the simple shader:
+ source.clear();
+ source.append(qShaderSnippets[MainVertexShader]);
+ source.append(qShaderSnippets[PositionOnlyVertexShader]);
+ vertexShader = new QGLShader(QGLShader::VertexShader, context, this);
+ vertexShader->compile(source);
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::FragmentShader, context, this);
+ fragShader->compile(source);
+
simpleShaderProg = new QGLShaderProgram(context, this);
- compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
- compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader);
- simpleShaderProg->addShader(compiledShaders[MainVertexShader]);
- simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]);
- simpleShaderProg->addShader(compiledShaders[MainFragmentShader]);
- simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]);
+ simpleShaderProg->addShader(vertexShader);
+ simpleShaderProg->addShader(fragShader);
simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
simpleShaderProg->link();
if (!simpleShaderProg->isLinked()) {
@@ -181,152 +189,159 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
}
// Compile the blit shader:
+ source.clear();
+ source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
+ source.append(qShaderSnippets[UntransformedPositionVertexShader]);
+ vertexShader = new QGLShader(QGLShader::VertexShader, context, this);
+ vertexShader->compile(source);
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ImageSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::FragmentShader, context, this);
+ fragShader->compile(source);
+
blitShaderProg = new QGLShaderProgram(context, this);
- compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
- compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader);
- blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]);
- blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]);
- blitShaderProg->addShader(compiledShaders[MainFragmentShader]);
- blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]);
+ blitShaderProg->addShader(vertexShader);
+ blitShaderProg->addShader(fragShader);
blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
blitShaderProg->link();
if (!blitShaderProg->isLinked()) {
qCritical() << "Errors linking blit shader:"
- << blitShaderProg->log();
- }
-}
-
-void QGLEngineSharedShaders::shaderDestroyed(QObject *shader)
-{
- // Remove any shader programs which has this as the srcPixel shader:
- for (int i = 0; i < cachedPrograms.size(); ++i) {
- if (cachedPrograms.at(i).srcPixelFragShader == shader) {
- delete cachedPrograms.at(i).program;
- cachedPrograms.removeAt(i--);
- }
+ << simpleShaderProg->log();
}
- emit shaderProgNeedsChanging();
}
-QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader::ShaderType type)
+#if defined (QT_DEBUG)
+QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
{
- Q_ASSERT(name != CustomImageSrcFragmentShader);
- Q_ASSERT(name < InvalidShaderName);
-
- if (compiledShaders[name])
- return compiledShaders[name];
-
- QByteArray source = qglEngineShaderSourceCode[name];
- QGLShader *newShader = new QGLShader(type, ctxGuard.context(), this);
- newShader->compile(source);
-
-#if defined(QT_DEBUG)
- // Name the shader for easier debugging
- QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName"));
- newShader->setObjectName(QLatin1String(m.valueToKey(name)));
-#endif
-
- compiledShaders[name] = newShader;
- return newShader;
+ QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
+ return QByteArray(m.valueToKey(name));
}
-
-QGLShader *QGLEngineSharedShaders::compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type)
-{
- QByteArray source = stage->source();
- source += qglslCustomSrcFragmentShader;
-
- QGLShader *newShader = customShaderCache.object(source);
- if (newShader)
- return newShader;
-
- newShader = new QGLShader(type, ctxGuard.context(), this);
- newShader->compile(source);
- customShaderCache.insert(source, newShader);
-
- connect(newShader, SIGNAL(destroyed(QObject *)),
- this, SLOT(shaderDestroyed(QObject *)));
-
-#if defined(QT_DEBUG)
- // Name the shader for easier debugging
- QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName"));
- newShader->setObjectName(QLatin1String(m.valueToKey(CustomImageSrcFragmentShader)));
#endif
- return newShader;
-}
-
// The address returned here will only be valid until next time this function is called.
QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
{
for (int i = 0; i < cachedPrograms.size(); ++i) {
- if (cachedPrograms[i] == prog)
- return &cachedPrograms[i];
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (*cachedProg == prog) {
+ // Move the program to the top of the list as a poor-man's cache algo
+ cachedPrograms.move(i, 0);
+ return cachedProg;
+ }
}
- cachedPrograms.append(prog);
- QGLEngineShaderProg &cached = cachedPrograms.last();
+ QByteArray source;
+ source.append(qShaderSnippets[prog.mainFragShader]);
+ source.append(qShaderSnippets[prog.srcPixelFragShader]);
+ if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
+ source.append(prog.customStageSource);
+ if (prog.compositionFragShader)
+ source.append(qShaderSnippets[prog.compositionFragShader]);
+ if (prog.maskFragShader)
+ source.append(qShaderSnippets[prog.maskFragShader]);
+ QGLShader* fragShader = new QGLShader(QGLShader::FragmentShader, ctxGuard.context(), this);
+ fragShader->compile(source);
+
+ source.clear();
+ source.append(qShaderSnippets[prog.mainVertexShader]);
+ source.append(qShaderSnippets[prog.positionVertexShader]);
+ QGLShader* vertexShader = new QGLShader(QGLShader::VertexShader, ctxGuard.context(), this);
+ vertexShader->compile(source);
+
+#if defined(QT_DEBUG)
+ // Name the shaders for easier debugging
+ QByteArray description;
+ description.append("Fragment shader: main=");
+ description.append(snippetNameStr(prog.mainFragShader));
+ description.append(", srcPixel=");
+ description.append(snippetNameStr(prog.srcPixelFragShader));
+ if (prog.compositionFragShader) {
+ description.append(", composition=");
+ description.append(snippetNameStr(prog.compositionFragShader));
+ }
+ if (prog.maskFragShader) {
+ description.append(", mask=");
+ description.append(snippetNameStr(prog.maskFragShader));
+ }
+ fragShader->setObjectName(QString::fromLatin1(description));
+
+ description.clear();
+ description.append("Vertex shader: main=");
+ description.append(snippetNameStr(prog.mainVertexShader));
+ description.append(", position=");
+ description.append(snippetNameStr(prog.positionVertexShader));
+ vertexShader->setObjectName(QString::fromLatin1(description));
+#endif
+
+ QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog);
// If the shader program's not found in the cache, create it now.
- cached.program = new QGLShaderProgram(ctxGuard.context(), this);
- cached.program->addShader(cached.mainVertexShader);
- cached.program->addShader(cached.positionVertexShader);
- cached.program->addShader(cached.mainFragShader);
- cached.program->addShader(cached.srcPixelFragShader);
- cached.program->addShader(cached.maskFragShader);
- cached.program->addShader(cached.compositionFragShader);
+ newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
+ newProg->program->addShader(vertexShader);
+ newProg->program->addShader(fragShader);
// We have to bind the vertex attribute names before the program is linked:
- cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- if (cached.useTextureCoords)
- cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
- if (cached.useOpacityAttribute)
- cached.program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
-
- cached.program->link();
- if (!cached.program->isLinked()) {
+ newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ if (newProg->useTextureCoords)
+ newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ if (newProg->useOpacityAttribute)
+ newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
+
+ newProg->program->link();
+ if (!newProg->program->isLinked()) {
QLatin1String none("none");
QLatin1String br("\n");
QString error;
error = QLatin1String("Shader program failed to link,")
#if defined(QT_DEBUG)
+ br
- + QLatin1String(" Shaders Used:\n")
- + QLatin1String(" mainVertexShader = ")
- + (cached.mainVertexShader ?
- cached.mainVertexShader->objectName() : none) + br
- + QLatin1String(" positionVertexShader = ")
- + (cached.positionVertexShader ?
- cached.positionVertexShader->objectName() : none) + br
- + QLatin1String(" mainFragShader = ")
- + (cached.mainFragShader ?
- cached.mainFragShader->objectName() : none) + br
- + QLatin1String(" srcPixelFragShader = ")
- + (cached.srcPixelFragShader ?
- cached.srcPixelFragShader->objectName() : none) + br
- + QLatin1String(" maskFragShader = ")
- + (cached.maskFragShader ?
- cached.maskFragShader->objectName() : none) + br
- + QLatin1String(" compositionFragShader = ")
- + (cached.compositionFragShader ?
- cached.compositionFragShader->objectName() : none) + br
+ + QLatin1String(" Shaders Used:") + br
+ + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(vertexShader->sourceCode()) + br
+ + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(fragShader->sourceCode()) + br
#endif
+ QLatin1String(" Error Log:\n")
- + QLatin1String(" ") + cached.program->log();
+ + QLatin1String(" ") + newProg->program->log();
qWarning() << error;
- delete cached.program;
- cachedPrograms.removeLast();
- return 0;
- } else {
- // taking the address here is safe since
- // cachePrograms isn't resized anywhere else
- return &cached;
+ delete newProg; // Deletes the QGLShaderProgram in it's destructor
+ newProg = 0;
}
+ else {
+ if (cachedPrograms.count() > 30) {
+ // The cache is full, so delete the last 5 programs in the list.
+ // These programs will be least used, as a program us bumped to
+ // the top of the list when it's used.
+ for (int i = 0; i < 5; ++i) {
+ delete cachedPrograms.last();
+ cachedPrograms.removeLast();
+ }
+ }
+
+ cachedPrograms.insert(0, newProg);
+ }
+
+ return newProg;
}
+void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
+{
+ // Remove any shader programs which has this as the custom shader src:
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (cachedProg->customStageSource == stage->source()) {
+ delete cachedProg;
+ cachedPrograms.removeAt(i);
+ i--;
+ }
+ }
+}
+
+
QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
: ctx(context),
shaderProgNeedsChanging(true),
@@ -335,8 +350,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
maskType(NoMask),
compositionMode(QPainter::CompositionMode_SourceOver),
customSrcStage(0),
- currentShaderProg(0),
- customShader(0)
+ currentShaderProg(0)
{
sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
@@ -345,6 +359,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
QGLEngineShaderManager::~QGLEngineShaderManager()
{
//###
+ removeCustomStage();
}
uint QGLEngineShaderManager::getUniformLocation(Uniform id)
@@ -436,21 +451,20 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
{
+ if (customSrcStage)
+ removeCustomStage();
customSrcStage = stage;
- customShader = 0; // Will be compiled from 'customSrcStage' later.
shaderProgNeedsChanging = true;
}
-void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
+void QGLEngineShaderManager::removeCustomStage()
{
- Q_UNUSED(stage); // Currently we only support one at a time...
-
+ if (customSrcStage)
+ customSrcStage->setInactive();
customSrcStage = 0;
- customShader = 0;
shaderProgNeedsChanging = true;
}
-
QGLShaderProgram* QGLEngineShaderManager::currentProgram()
{
return currentShaderProg->program;
@@ -482,22 +496,21 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
}
QGLEngineShaderProg requiredProgram;
- requiredProgram.program = 0;
bool texCoords = false;
// Choose vertex shader shader position function (which typically also sets
// varyings) and the source pixel (srcPixel) fragment shader function:
- QGLEngineSharedShaders::ShaderName positionVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
- QGLEngineSharedShaders::ShaderName srcPixelFragShaderName = QGLEngineSharedShaders::InvalidShaderName;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName;
bool isAffine = brushTransform.isAffine();
if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
if (isAffine)
- positionVertexShaderName = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
else
- positionVertexShaderName = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
- srcPixelFragShaderName = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
}
else switch (srcPixelType) {
default:
@@ -505,172 +518,157 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
break;
case QGLEngineShaderManager::ImageSrc:
- srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcFragmentShader;
- positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QGLEngineShaderManager::NonPremultipliedImageSrc:
- srcPixelFragShaderName = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
- positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QGLEngineShaderManager::PatternSrc:
- srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
- positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
case QGLEngineShaderManager::TextureSrcWithPattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
- positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
: QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
case Qt::SolidPattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
- positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case Qt::LinearGradientPattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
: QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
break;
case Qt::ConicalGradientPattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
: QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
break;
case Qt::RadialGradientPattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
: QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
break;
case Qt::TexturePattern:
- srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
: QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
};
- requiredProgram.positionVertexShader = sharedShaders->compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader);
+
if (useCustomSrc) {
- if (!customShader)
- customShader = sharedShaders->compileCustomShader(customSrcStage, QGLShader::PartialFragmentShader);
- requiredProgram.srcPixelFragShader = customShader;
- } else {
- requiredProgram.srcPixelFragShader = sharedShaders->compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader);
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader;
+ requiredProgram.customStageSource = customSrcStage->source();
}
const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
// Choose fragment shader main function:
- QGLEngineSharedShaders::ShaderName mainFragShaderName;
-
if (opacityMode == AttributeOpacity) {
Q_ASSERT(!hasCompose && !hasMask);
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
} else {
bool useGlobalOpacity = (opacityMode == UniformOpacity);
if (hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO;
if (hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM;
if (!hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO;
if (!hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M;
if (hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO;
if (hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C;
if (!hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O;
if (!hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader;
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader;
}
- requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader);
-
if (hasMask) {
- QGLEngineSharedShaders::ShaderName maskShaderName = QGLEngineSharedShaders::InvalidShaderName;
if (maskType == PixelMask) {
- maskShaderName = QGLEngineSharedShaders::MaskFragmentShader;
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader;
texCoords = true;
} else if (maskType == SubPixelMaskPass1) {
- maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
texCoords = true;
} else if (maskType == SubPixelMaskPass2) {
- maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
texCoords = true;
} else if (maskType == SubPixelWithGammaMask) {
- maskShaderName = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
texCoords = true;
} else {
qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
}
-
- requiredProgram.maskFragShader = sharedShaders->compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader);
} else {
- requiredProgram.maskFragShader = 0;
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader;
}
if (hasCompose) {
- QGLEngineSharedShaders::ShaderName compositionShaderName = QGLEngineSharedShaders::InvalidShaderName;
switch (compositionMode) {
case QPainter::CompositionMode_Multiply:
- compositionShaderName = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Screen:
- compositionShaderName = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Overlay:
- compositionShaderName = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Darken:
- compositionShaderName = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Lighten:
- compositionShaderName = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorDodge:
- compositionShaderName = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorBurn:
- compositionShaderName = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_HardLight:
- compositionShaderName = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_SoftLight:
- compositionShaderName = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Difference:
- compositionShaderName = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Exclusion:
- compositionShaderName = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
break;
default:
qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
}
- requiredProgram.compositionFragShader = sharedShaders->compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader);
} else {
- requiredProgram.compositionFragShader = 0;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader;
}
- // Choose vertex shader main function
- QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName;
+ // Choose vertex shader main function
if (opacityMode == AttributeOpacity) {
Q_ASSERT(texCoords);
- mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
} else if (texCoords) {
- mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
} else {
- mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader;
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
}
- requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader);
requiredProgram.useTextureCoords = texCoords;
requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
-
// At this point, requiredProgram is fully populated so try to find the program in the cache
currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 291d24c..50c1432 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -234,32 +234,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(OpenGL)
-struct QGLEngineShaderProg
-{
- QGLShader* mainVertexShader;
- QGLShader* positionVertexShader;
- QGLShader* mainFragShader;
- QGLShader* srcPixelFragShader;
- QGLShader* maskFragShader; // Can be null for no mask
- QGLShader* compositionFragShader; // Can be null for GL-handled mode
- QGLShaderProgram* program;
-
- QVector<uint> uniformLocations;
-
- bool useTextureCoords;
- bool useOpacityAttribute;
-
- bool operator==(const QGLEngineShaderProg& other) {
- // We don't care about the program
- return ( mainVertexShader == other.mainVertexShader &&
- positionVertexShader == other.positionVertexShader &&
- mainFragShader == other.mainFragShader &&
- srcPixelFragShader == other.srcPixelFragShader &&
- maskFragShader == other.maskFragShader &&
- compositionFragShader == other.compositionFragShader
- );
- }
-};
/*
struct QGLEngineCachedShaderProg
@@ -280,15 +254,19 @@ static const GLuint QT_VERTEX_COORDS_ATTR = 0;
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
static const GLuint QT_OPACITY_ATTR = 2;
+class QGLEngineShaderProg;
+
class QGLEngineSharedShaders : public QObject
{
Q_OBJECT
public:
- enum ShaderName {
+
+ enum SnippetName {
MainVertexShader,
MainWithTexCoordsVertexShader,
MainWithTexCoordsAndOpacityVertexShader,
+ // UntransformedPositionVertexShader must be first in the list:
UntransformedPositionVertexShader,
PositionOnlyVertexShader,
PositionWithPatternBrushVertexShader,
@@ -302,6 +280,7 @@ public:
AffinePositionWithRadialGradientBrushVertexShader,
AffinePositionWithTextureBrushVertexShader,
+ // MainFragmentShader_CMO must be first in the list:
MainFragmentShader_CMO,
MainFragmentShader_CM,
MainFragmentShader_MO,
@@ -312,6 +291,7 @@ public:
MainFragmentShader,
MainFragmentShader_ImageArrays,
+ // ImageSrcFragmentShader must be first in the list::
ImageSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
@@ -325,11 +305,15 @@ public:
ConicalGradientBrushSrcFragmentShader,
ShockingPinkSrcFragmentShader,
+ // NoMaskFragmentShader must be first in the list:
+ NoMaskFragmentShader,
MaskFragmentShader,
RgbMaskFragmentShaderPass1,
RgbMaskFragmentShaderPass2,
RgbMaskWithGammaFragmentShader,
+ // NoCompositionModeFragmentShader must be first in the list:
+ NoCompositionModeFragmentShader,
MultiplyCompositionModeFragmentShader,
ScreenCompositionModeFragmentShader,
OverlayCompositionModeFragmentShader,
@@ -342,37 +326,88 @@ public:
DifferenceCompositionModeFragmentShader,
ExclusionCompositionModeFragmentShader,
- TotalShaderCount, InvalidShaderName
+ TotalSnippetCount, InvalidSnippetName
};
+#if defined (QT_DEBUG)
+ Q_ENUMS(SnippetName)
+ static QByteArray snippetNameStr(SnippetName snippetName);
+#endif
- QGLEngineSharedShaders(const QGLContext *context);
+/*
+ // These allow the ShaderName enum to be used as a cache key
+ const int mainVertexOffset = 0;
+ const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
+ const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
+ const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
+ const int maskOffset = (1<<14) - NoMaskShader;
+ const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
+*/
- QGLShader *compileNamedShader(ShaderName name, QGLShader::ShaderType type);
+ QGLEngineSharedShaders(const QGLContext *context);
QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
QGLShaderProgram *blitProgram() { return blitShaderProg; }
// Compile the program if it's not already in the cache, return the item in the cache.
QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
// Compile the custom shader if it's not already in the cache, return the item in the cache.
- QGLShader *compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type);
static QGLEngineSharedShaders *shadersForContext(const QGLContext *context);
+ // Ideally, this would be static and cleanup all programs in all contexts which
+ // contain the custom code. Currently it is just a hint and we rely on deleted
+ // custom shaders being cleaned up by being kicked out of the cache when it's
+ // full.
+ void cleanupCustomStage(QGLCustomShaderStage* stage);
+
signals:
void shaderProgNeedsChanging();
-private slots:
- void shaderDestroyed(QObject *shader);
-
private:
QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
QGLShaderProgram *simpleShaderProg;
- QList<QGLEngineShaderProg> cachedPrograms;
- QCache<QByteArray, QGLShader> customShaderCache;
- QGLShader* compiledShaders[TotalShaderCount];
+ QList<QGLEngineShaderProg*> cachedPrograms;
- static const char* qglEngineShaderSourceCode[TotalShaderCount];
+ static const char* qShaderSnippets[TotalSnippetCount];
+};
+
+
+class QGLEngineShaderProg
+{
+public:
+ QGLEngineShaderProg() : program(0) {}
+
+ ~QGLEngineShaderProg() {
+ if (program)
+ delete program;
+ }
+
+ QGLEngineSharedShaders::SnippetName mainVertexShader;
+ QGLEngineSharedShaders::SnippetName positionVertexShader;
+ QGLEngineSharedShaders::SnippetName mainFragShader;
+ QGLEngineSharedShaders::SnippetName srcPixelFragShader;
+ QGLEngineSharedShaders::SnippetName maskFragShader;
+ QGLEngineSharedShaders::SnippetName compositionFragShader;
+
+ QByteArray customStageSource; //TODO: Decent cache key for custom stages
+ QGLShaderProgram* program;
+
+ QVector<uint> uniformLocations;
+
+ bool useTextureCoords;
+ bool useOpacityAttribute;
+
+ bool operator==(const QGLEngineShaderProg& other) {
+ // We don't care about the program
+ return ( mainVertexShader == other.mainVertexShader &&
+ positionVertexShader == other.positionVertexShader &&
+ mainFragShader == other.mainFragShader &&
+ srcPixelFragShader == other.srcPixelFragShader &&
+ maskFragShader == other.maskFragShader &&
+ compositionFragShader == other.compositionFragShader &&
+ customStageSource == other.customStageSource
+ );
+ }
};
class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
@@ -426,7 +461,7 @@ public:
void setMaskType(MaskType);
void setCompositionMode(QPainter::CompositionMode);
void setCustomStage(QGLCustomShaderStage* stage);
- void removeCustomStage(QGLCustomShaderStage* stage);
+ void removeCustomStage();
uint getUniformLocation(Uniform id);
@@ -437,19 +472,7 @@ public:
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
-/*
- // These allow the ShaderName enum to be used as a cache key
- const int mainVertexOffset = 0;
- const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
- const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
- const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
- const int maskOffset = (1<<14) - NoMaskShader;
- const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
-*/
-
-#if defined (QT_DEBUG)
- Q_ENUMS(ShaderName)
-#endif
+ QGLEngineSharedShaders* sharedShaders;
private slots:
void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
@@ -466,9 +489,7 @@ private:
QPainter::CompositionMode compositionMode;
QGLCustomShaderStage* customSrcStage;
- QGLEngineShaderProg* currentShaderProg;
- QGLEngineSharedShaders *sharedShaders;
- QGLShader *customShader;
+ QGLEngineShaderProg* currentShaderProg;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 209cd36..4cf2a83 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -289,6 +289,7 @@ public:
QScopedPointer<QPixmapFilter> convolutionFilter;
QScopedPointer<QPixmapFilter> colorizeFilter;
QScopedPointer<QPixmapFilter> blurFilter;
+ QScopedPointer<QPixmapFilter> animationBlurFilter;
QScopedPointer<QPixmapFilter> fastBlurFilter;
QScopedPointer<QPixmapFilter> dropShadowFilter;
QScopedPointer<QPixmapFilter> fastDropShadowFilter;
diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
index ad18a51..1163eba 100644
--- a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
+++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
@@ -114,7 +114,7 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen)
if (m_join_style == Qt::RoundJoin)
m_join_style = Qt::MiterJoin;
m_curvyness_add = 0.5;
- m_curvyness_mul = CURVE_FLATNESS;
+ m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
m_roundness = 1;
} else if (cosmetic) {
m_curvyness_add = realWidth / 2;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index e80521b..ad177dc 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1773,10 +1773,12 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
/*!
\enum QGLContext::BindOption
+ \since 4.6
+
A set of options to decide how to bind a texture using bindTexture().
\value NoBindOption Don't do anything, pass the texture straight
- thru.
+ through.
\value InvertedYBindOption Specifies that the texture should be flipped
over the X axis so that the texture coordinate 0,0 corresponds to
@@ -2137,7 +2139,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
Q_ASSERT(texture);
if (texture->id > 0)
- const_cast<QImage &>(image).data_ptr()->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(image);
return texture;
}
@@ -2158,7 +2160,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
#ifndef QT_NO_DEBUG
// Reset the gl error stack...git
- while (glGetError() != GL_NO_ERROR);
+ while (glGetError() != GL_NO_ERROR) ;
#endif
// Scale the pixmap if needed. GL textures needs to have the
@@ -2396,7 +2398,7 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
Q_ASSERT(texture);
if (texture->id > 0)
- const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
return texture;
}
@@ -2445,6 +2447,9 @@ int QGLContextPrivate::maxTextureSize()
*/
GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption);
return texture->id;
@@ -2477,6 +2482,9 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
*/
GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(image, target, format, false, options);
return texture->id;
@@ -2486,6 +2494,9 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format,
/*! \internal */
GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption);
return texture->id;
@@ -2495,6 +2506,9 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa
GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options);
return texture->id;
@@ -2507,6 +2521,9 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa
*/
GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption);
return texture->id;
@@ -2521,6 +2538,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma
*/
GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(pixmap, target, format, options);
return texture->id;
@@ -2530,6 +2550,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma
/*! \internal */
GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption);
return texture->id;
@@ -2538,6 +2561,9 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q
GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
BindOptions options)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options);
return texture->id;
@@ -4595,6 +4621,9 @@ bool QGLWidget::autoBufferSwap() const
*/
GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption);
}
@@ -4608,6 +4637,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
*/
GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
return d->glcx->bindTexture(image, target, format, options);
}
@@ -4617,6 +4649,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format,
/*! \internal */
GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption);
}
@@ -4624,6 +4659,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac
GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
QGLContext::BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
return d->glcx->bindTexture(image, GLenum(target), GLint(format), options);
}
@@ -4637,6 +4675,9 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac
*/
GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLWidget);
return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
}
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index e14e7fb..079953f 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -399,6 +399,7 @@ private:
friend class QGLTextureGlyphCache;
friend class QGLShareRegister;
friend class QGLSharedResourceGuard;
+ friend class QGLPixmapBlurFilter;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 86e593d..899047a 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -53,6 +53,7 @@
#include <private/qfontengine_ft_p.h>
#include <private/qt_x11_p.h>
#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#ifdef Q_OS_HPUX
// for GLXPBuffer
#include <private/qglpixelbuffer_p.h>
@@ -1704,7 +1705,7 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con
pixmapData->gl_surface = (Qt::HANDLE)glxPixmap;
// Make sure the cleanup hook gets called so we can delete the glx pixmap
- pixmapData->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData);
}
GLuint textureId;
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 7180682..9b20297 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -42,6 +42,7 @@
#include "qgl.h"
#include <private/qt_x11_p.h>
#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#include <private/qgl_p.h>
#include <private/qpaintengine_opengl_p.h>
#include "qgl_egl_p.h"
@@ -531,7 +532,7 @@ bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnl
Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
- pixmapData->is_cached = true; // Make sure the cleanup hook gets called
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called
return true;
}
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 2af69e0..8768fbc 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -43,6 +43,8 @@
#include "private/qpixmapdata_gl_p.h"
#include "private/qpaintengineex_opengl2_p.h"
#include "private/qglengineshadermanager_p.h"
+#include "private/qpixmapdata_p.h"
+#include "private/qimagepixmapcleanuphooks_p.h"
#include "qglpixmapfilter_p.h"
#include "qgraphicssystem_gl_p.h"
#include "qpaintengine_opengl_p.h"
@@ -54,7 +56,7 @@
#include "private/qapplication_p.h"
#include "private/qmath_p.h"
-
+#include "qmath.h"
QT_BEGIN_NAMESPACE
@@ -100,7 +102,7 @@ private:
class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter>
{
public:
- QGLPixmapBlurFilter(Qt::RenderHint hint);
+ QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint);
void setUniforms(QGLShaderProgram *program);
@@ -114,16 +116,20 @@ private:
mutable QSize m_textureSize;
mutable bool m_horizontalBlur;
mutable bool m_singlePass;
+ mutable bool m_animatedBlur;
+
+ mutable qreal m_t;
+ mutable QSize m_targetSize;
mutable bool m_haveCached;
mutable int m_cachedRadius;
- mutable Qt::RenderHint m_hint;
+ mutable QGraphicsBlurEffect::BlurHint m_hint;
};
class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter>
{
public:
- QGLPixmapDropShadowFilter(Qt::RenderHint hint);
+ QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint);
void setUniforms(QGLShaderProgram *program);
@@ -137,7 +143,7 @@ private:
mutable bool m_haveCached;
mutable int m_cachedRadius;
- mutable Qt::RenderHint m_hint;
+ mutable QGraphicsBlurEffect::BlurHint m_hint;
};
extern QGLWidget *qt_gl_share_widget();
@@ -153,13 +159,18 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr
case QPixmapFilter::BlurFilter: {
const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype);
- if (proto->blurHint() == Qt::PerformanceHint || proto->radius() <= 5) {
+ if (proto->blurHint() == QGraphicsBlurEffect::AnimationHint) {
+ if (!d->animationBlurFilter)
+ d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHint()));
+ return d->animationBlurFilter.data();
+ }
+ if (proto->blurHint() == QGraphicsBlurEffect::PerformanceHint || proto->radius() <= 5) {
if (!d->fastBlurFilter)
- d->fastBlurFilter.reset(new QGLPixmapBlurFilter(Qt::PerformanceHint));
+ d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint));
return d->fastBlurFilter.data();
}
if (!d->blurFilter)
- d->blurFilter.reset(new QGLPixmapBlurFilter(Qt::QualityHint));
+ d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint));
return d->blurFilter.data();
}
@@ -167,11 +178,11 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr
const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype);
if (proto->blurRadius() <= 5) {
if (!d->fastDropShadowFilter)
- d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::PerformanceHint));
+ d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint));
return d->fastDropShadowFilter.data();
}
if (!d->dropShadowFilter)
- d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::QualityHint));
+ d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint));
return d->dropShadowFilter.data();
}
@@ -305,43 +316,344 @@ static const char *qt_gl_texture_sampling_helper =
" return texture2D(src, srcCoords).a;\n"
"}\n";
-static const char *qt_gl_clamped_texture_sampling_helper =
- "highp vec4 texture_dimensions;\n" // x = width, y = height, z = 0.5/width, w = 0.5/height
- "lowp float clampedTexture2DAlpha(lowp sampler2D src, highp vec2 srcCoords) {\n"
- " highp vec2 clampedCoords = clamp(srcCoords, texture_dimensions.zw, vec2(1.0) - texture_dimensions.zw);\n"
- " highp vec2 t = clamp(min(srcCoords, vec2(1.0) - srcCoords) * srcDim + 0.5, 0.0, 1.0);\n"
- " return texture2D(src, clampedCoords).a * t.x * t.y;\n"
- "}\n"
- "lowp vec4 clampedTexture2D(lowp sampler2D src, highp vec2 srcCoords) {\n"
- " highp vec2 clampedCoords = clamp(srcCoords, texture_dimensions.zw, vec2(1.0) - texture_dimensions.zw);\n"
- " highp vec2 t = clamp(min(srcCoords, vec2(1.0) - srcCoords) * srcDim + 0.5, 0.0, 1.0);\n"
- " return texture2D(src, clampedCoords) * t.x * t.y;\n"
- "}\n";
+QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint)
+ : m_animatedBlur(false)
+ , m_haveCached(false)
+ , m_cachedRadius(0)
+ , m_hint(hint)
+{
+}
-static QByteArray qt_gl_convertToClamped(const QByteArray &source)
+// should be even numbers as they will be divided by two
+static const int qCachedBlurLevels[] = { 6, 14, 30 };
+static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels);
+static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1];
+
+static qreal qLogBlurLevel(int level)
{
- QByteArray result;
- result.append(qt_gl_clamped_texture_sampling_helper);
- result.append(QByteArray(source).replace("texture2DAlpha", "clampedTexture2DAlpha")
- .replace("texture2D", "clampedTexture2D"));
- return result;
+ static bool initialized = false;
+ static qreal logBlurLevelCache[qNumCachedBlurTextures];
+ if (!initialized) {
+ for (int i = 0; i < qNumCachedBlurTextures; ++i)
+ logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]);
+ initialized = true;
+ }
+ return logBlurLevelCache[level];
}
-QGLPixmapBlurFilter::QGLPixmapBlurFilter(Qt::RenderHint hint)
- : m_haveCached(false)
- , m_cachedRadius(0)
- , m_hint(hint)
+class QGLBlurTextureInfo
+{
+public:
+ QGLBlurTextureInfo(QSize size, GLuint textureIds[])
+ : m_size(size)
+ {
+ for (int i = 0; i < qNumCachedBlurTextures; ++i)
+ m_textureIds[i] = textureIds[i];
+ }
+
+ ~QGLBlurTextureInfo()
+ {
+ glDeleteTextures(qNumCachedBlurTextures, m_textureIds);
+ }
+
+ QSize size() const { return m_size; }
+ GLuint textureId(int i) const { return m_textureIds[i]; }
+
+private:
+ GLuint m_textureIds[qNumCachedBlurTextures];
+ QSize m_size;
+};
+
+class QGLBlurTextureCache : public QObject
+{
+public:
+ static QGLBlurTextureCache *cacheForContext(const QGLContext *context);
+
+ QGLBlurTextureCache();
+ ~QGLBlurTextureCache();
+
+ QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap);
+ bool fitsInCache(const QPixmap &pixmap) const;
+ bool hasBlurTextureInfo(const QPixmap &pixmap) const;
+ void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info);
+ void clearBlurTextureInfo(const QPixmap &pixmap);
+
+ void timerEvent(QTimerEvent *event);
+
+private:
+ static void pixmapDestroyed(QPixmap *pixmap);
+
+ QCache<quint64, QGLBlurTextureInfo > cache;
+
+ static QList<QGLBlurTextureCache *> blurTextureCaches;
+
+ int timerId;
+};
+
+QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches;
+
+static void QGLBlurTextureCache_free(void *ptr)
+{
+ delete reinterpret_cast<QGLBlurTextureCache *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free))
+
+QGLBlurTextureCache::QGLBlurTextureCache()
+ : timerId(0)
+{
+ cache.setMaxCost(4 * 1024 * 1024);
+ blurTextureCaches.append(this);
+}
+
+QGLBlurTextureCache::~QGLBlurTextureCache()
+{
+ blurTextureCaches.removeAt(blurTextureCaches.indexOf(this));
+}
+
+void QGLBlurTextureCache::timerEvent(QTimerEvent *)
+{
+ killTimer(timerId);
+ timerId = 0;
+
+ cache.clear();
+}
+
+QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context)
+{
+ QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context));
+ if (!p) {
+ p = new QGLBlurTextureCache;
+ qt_blur_texture_caches()->insert(context, p);
+ }
+ return p;
+}
+
+QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap)
+{
+ return cache.take(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap)
+{
+ cache.remove(pixmap.cacheKey());
+}
+
+bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const
+{
+ return cache.contains(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info)
+{
+ static bool hookAdded = false;
+ if (!hookAdded) {
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed);
+ hookAdded = true;
+ }
+
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
+ cache.insert(pixmap.cacheKey(), info, pixmap.width() * pixmap.height());
+
+ if (timerId)
+ killTimer(timerId);
+
+ timerId = startTimer(1000);
+}
+
+bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const
+{
+ return pixmap.width() * pixmap.height() <= cache.maxCost();
+}
+
+void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap)
+{
+ foreach (QGLBlurTextureCache *cache, blurTextureCaches) {
+ if (cache->hasBlurTextureInfo(*pixmap))
+ cache->clearBlurTextureInfo(*pixmap);
+ }
+}
+
+static const char *qt_gl_interpolate_filter =
+ "uniform lowp float interpolationValue;"
+ "uniform lowp sampler2D interpolateTarget;"
+ "uniform highp vec4 interpolateMapping;"
+ "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)"
+ "{"
+ " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords),"
+ " texture2D(src, srcCoords), interpolationValue);"
+ "}";
+
+static void initializeTexture(GLuint id, int width, int height)
{
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
}
bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
{
QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this);
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx);
+
+ if (m_hint == QGraphicsBlurEffect::AnimationHint && blurTextureCache->fitsInCache(src)) {
+ QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel);
+ // ensure even dimensions (going to divide by two)
+ targetRect.setWidth((targetRect.width() + 1) & ~1);
+ targetRect.setHeight((targetRect.height() + 1) & ~1);
+
+ QGLBlurTextureInfo *info = 0;
+ if (blurTextureCache->hasBlurTextureInfo(src)) {
+ info = blurTextureCache->takeBlurTextureInfo(src);
+ } else {
+ m_animatedBlur = false;
+ m_hint = QGraphicsBlurEffect::QualityHint;
+ m_singlePass = false;
+
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(GL_RGBA);
+ QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true);
+
+ if (!fbo)
+ return false;
+
+ QPainter fboPainter(fbo);
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(fboPainter.paintEngine());
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // ensure GL_LINEAR filtering is used for scaling down to half the size
+ fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2,
+ targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src);
+
+ GLuint textures[qNumCachedBlurTextures]; // blur textures
+ glGenTextures(qNumCachedBlurTextures, textures);
+ GLuint temp; // temp texture
+ glGenTextures(1, &temp);
+
+ initializeTexture(temp, fbo->width(), fbo->height());
+ m_textureSize = fbo->size();
+
+ int currentBlur = 0;
+
+ QRect fboRect(0, 0, fbo->width(), fbo->height());
+ GLuint sourceTexture = fbo->texture();
+ for (int i = 0; i < qNumCachedBlurTextures; ++i) {
+ int targetBlur = qCachedBlurLevels[i] / 2;
+
+ int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur));
+ QByteArray source = generateGaussianShader(blurDelta);
+ filter->setSource(source);
+
+ currentBlur = targetBlur;
+
+ // now we're going to be nasty and keep using the same FBO with different textures
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, temp, 0);
+
+ m_horizontalBlur = true;
+ filter->setOnPainter(&fboPainter);
+ engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect);
+ filter->removeFromPainter(&fboPainter);
+
+ sourceTexture = textures[i];
+ initializeTexture(sourceTexture, fbo->width(), fbo->height());
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, textures[i], 0);
+
+ m_horizontalBlur = false;
+ filter->setOnPainter(&fboPainter);
+ engine->drawTexture(fboRect, temp, fbo->size(), fboRect);
+ filter->removeFromPainter(&fboPainter);
+ }
+
+ glDeleteTextures(1, &temp);
+
+ // reattach the original FBO texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, fbo->texture(), 0);
+
+ fboPainter.end();
+
+ qgl_fbo_pool()->release(fbo);
+
+ info = new QGLBlurTextureInfo(fboRect.size(), textures);
+ }
+
+ if (!m_haveCached || !m_animatedBlur) {
+ m_haveCached = true;
+ m_animatedBlur = true;
+ m_hint = QGraphicsBlurEffect::AnimationHint;
+ filter->setSource(qt_gl_interpolate_filter);
+ }
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+
+ qreal logRadius = qLn(radius());
+
+ int t;
+ for (t = -1; t < qNumCachedBlurTextures - 2; ++t) {
+ if (logRadius < qLogBlurLevel(t+1))
+ break;
+ }
+
+ qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0;
+ m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1));
+
+ m_textureSize = info->size();
+
+ glActiveTexture(GL_TEXTURE0 + 3);
+ if (t >= 0) {
+ glBindTexture(GL_TEXTURE_2D, info->textureId(t));
+ m_targetSize = info->size();
+ } else {
+ QGLTexture *texture =
+ ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
+ m_targetSize = src.size();
+ if (!(texture->options & QGLContext::InvertedYBindOption))
+ m_targetSize.setHeight(-m_targetSize.height());
+ }
+
+ // restrict the target rect to the max of the radii we are interpolating between
+ int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1];
+ targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta);
+
+ radiusDelta /= 2;
+ QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta);
+
+ engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect);
+
+ glActiveTexture(GL_TEXTURE0 + 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ filter->removeFromPainter(painter);
+ blurTextureCache->insertBlurTextureInfo(src, info);
+
+ return true;
+ }
+
+ if (blurTextureCache->hasBlurTextureInfo(src))
+ blurTextureCache->clearBlurTextureInfo(src);
+
int actualRadius = qRound(radius());
int filterRadius = actualRadius;
int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 };
- if (m_hint == Qt::PerformanceHint) {
+ if (m_hint != QGraphicsBlurEffect::QualityHint) {
uint i = 0;
for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) {
if (fastRadii[i+1] > filterRadius)
@@ -352,9 +664,10 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const
m_singlePass = filterRadius <= 3;
- if (!m_haveCached || filterRadius != m_cachedRadius) {
+ if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) {
// Only regenerate the shader from source if parameters have changed.
m_haveCached = true;
+ m_animatedBlur = false;
m_cachedRadius = filterRadius;
QByteArray source = generateGaussianShader(filterRadius, m_singlePass);
filter->setSource(source);
@@ -389,13 +702,12 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const
QPainter fboPainter(fbo);
- if (src.hasAlphaChannel()) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
// ensure GL_LINEAR filtering is used
fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
filter->setOnPainter(&fboPainter);
QBrush pixmapBrush = src;
pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius));
@@ -428,7 +740,29 @@ void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- if (m_hint == Qt::QualityHint) {
+ if (m_animatedBlur) {
+ program->setUniformValue("interpolateTarget", 3);
+ program->setUniformValue("interpolationValue", GLfloat(m_t));
+
+ if (m_textureSize == m_targetSize) {
+ program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width());
+ float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height());
+
+ if (m_targetSize.height() < 0)
+ offsetY = 1 + offsetY;
+
+ float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width());
+ float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height());
+
+ program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY);
+ }
+
+ return;
+ }
+
+ if (m_hint == QGraphicsBlurEffect::QualityHint) {
if (m_singlePass)
program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
else if (m_horizontalBlur)
@@ -578,7 +912,7 @@ QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePa
return source;
}
-QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(Qt::RenderHint hint)
+QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint)
: m_haveCached(false)
, m_cachedRadius(0)
, m_hint(hint)
@@ -632,13 +966,12 @@ bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos,
QPainter fboPainter(fbo);
- if (src.hasAlphaChannel()) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
// ensure GL_LINEAR filtering is used
fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
filter->setOnPainter(&fboPainter);
QBrush pixmapBrush = src;
pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius));
@@ -685,7 +1018,7 @@ void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program)
alpha);
}
- if (m_hint == Qt::QualityHint) {
+ if (m_hint == QGraphicsBlurEffect::QualityHint) {
if (m_singlePass)
program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
else if (m_horizontalBlur)
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
index 90b496e..080c3b2 100644
--- a/src/opengl/qglshaderprogram.cpp
+++ b/src/opengl/qglshaderprogram.cpp
@@ -106,30 +106,6 @@ QT_BEGIN_NAMESPACE
\snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 2
- \section1 Partial shaders
-
- Desktop GLSL can attach an arbitrary number of vertex and fragment
- shaders to a shader program. Embedded GLSL/ES on the other hand
- supports only a single shader of each type on a shader program.
-
- Multiple shaders of the same type can be useful when large libraries
- of shaders are needed. Common functions can be factored out into
- library shaders that can be reused in multiple shader programs.
-
- To support this use of shaders, the application programmer can
- create shaders with the QGLShader::PartialVertexShader and
- QGLShader::PartialFragmentShader types. These types direct
- QGLShader and QGLShaderProgram to delay shader compilation until
- link time.
-
- When link() is called, the sources for the partial shaders are
- concatenated, and a single vertex or fragment shader is compiled
- and linked into the shader program.
-
- It is more efficient to use the QGLShader::VertexShader and
- QGLShader::FragmentShader when there is only one shader of that
- type in the program.
-
\sa QGLShader
*/
@@ -154,11 +130,6 @@ QT_BEGIN_NAMESPACE
\value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL).
\value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL).
-
- \value PartialVertexShader Partial vertex shader that will be concatenated with all other partial vertex shaders at link time.
- \value PartialFragmentShader Partial fragment shader that will be concatenated with all other partial fragment shaders at link time.
-
- \omitvalue PartialShader
*/
#ifndef GL_FRAGMENT_SHADER
@@ -209,8 +180,6 @@ public:
: shaderGuard(context)
, shaderType(type)
, compiled(false)
- , isPartial((type & QGLShader::PartialShader) != 0)
- , hasPartialSource(false)
{
}
~QGLShaderPrivate();
@@ -218,10 +187,7 @@ public:
QGLSharedResourceGuard shaderGuard;
QGLShader::ShaderType shaderType;
bool compiled;
- bool isPartial;
- bool hasPartialSource;
QString log;
- QByteArray partialSource;
bool create();
bool compile(QGLShader *q);
@@ -243,8 +209,6 @@ bool QGLShaderPrivate::create()
const QGLContext *context = shaderGuard.context();
if (!context)
return false;
- if (isPartial)
- return true;
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
GLuint shader;
if (shaderType == QGLShader::VertexShader)
@@ -264,11 +228,6 @@ bool QGLShaderPrivate::create()
bool QGLShaderPrivate::compile(QGLShader *q)
{
- // Partial shaders are compiled during QGLShaderProgram::link().
- if (isPartial && hasPartialSource) {
- compiled = true;
- return true;
- }
GLuint shader = shaderGuard.id();
if (!shader)
return false;
@@ -441,21 +400,12 @@ static const char redefineHighp[] =
Sets the \a source code for this shader and compiles it.
Returns true if the source was successfully compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
\sa compileFile()
*/
bool QGLShader::compile(const char *source)
{
Q_D(QGLShader);
- if (d->isPartial) {
- d->partialSource = QByteArray(source);
- d->hasPartialSource = true;
- return d->compile(this);
- } else if (d->shaderGuard.id()) {
+ if (d->shaderGuard.id()) {
QVarLengthArray<const char *, 4> src;
QVarLengthArray<GLint, 4> srclen;
int headerLen = 0;
@@ -481,8 +431,7 @@ bool QGLShader::compile(const char *source)
srclen.append(GLint(sizeof(qualifierDefines) - 1));
#endif
#ifdef QGL_REDEFINE_HIGHP
- if (d->shaderType == FragmentShader ||
- d->shaderType == PartialFragmentShader) {
+ if (d->shaderType == FragmentShader) {
src.append(redefineHighp);
srclen.append(GLint(sizeof(redefineHighp) - 1));
}
@@ -497,71 +446,11 @@ bool QGLShader::compile(const char *source)
}
/*!
- \internal
-*/
-bool QGLShader::compile
- (const QList<QGLShader *>& shaders, QGLShader::ShaderType type)
-{
- Q_D(QGLShader);
- QVarLengthArray<const char *, 16> src;
- QVarLengthArray<GLint, 16> srclen;
- if (!d->shaderGuard.id())
- return false;
- foreach (QGLShader *shader, shaders) {
- if (shader->shaderType() != type)
- continue;
- const char *source = shader->d_func()->partialSource.constData();
- int headerLen = 0;
- if (src.isEmpty()) {
- // First shader: handle the #version and #extension tags
- // plus the precision qualifiers.
- 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;
- }
- if (headerLen > 0) {
- src.append(source);
- srclen.append(GLint(headerLen));
- }
-#ifdef QGL_DEFINE_QUALIFIERS
- src.append(qualifierDefines);
- srclen.append(GLint(sizeof(qualifierDefines) - 1));
-#endif
-#ifdef QGL_REDEFINE_HIGHP
- if (d->shaderType == FragmentShader ||
- d->shaderType == PartialFragmentShader) {
- src.append(redefineHighp);
- srclen.append(GLint(sizeof(redefineHighp) - 1));
- }
-#endif
- }
- src.append(source + headerLen);
- srclen.append(GLint(qstrlen(source + headerLen)));
- }
- glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
- return d->compile(this);
-}
-
-/*!
\overload
Sets the \a source code for this shader and compiles it.
Returns true if the source was successfully compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
\sa compileFile()
*/
bool QGLShader::compile(const QByteArray& source)
@@ -575,11 +464,6 @@ bool QGLShader::compile(const QByteArray& source)
Sets the \a source code for this shader and compiles it.
Returns true if the source was successfully compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
\sa compileFile()
*/
bool QGLShader::compile(const QString& source)
@@ -592,11 +476,6 @@ bool QGLShader::compile(const QString& source)
and compiles it. Returns true if the file could be opened and the
source compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
\sa compile()
*/
bool QGLShader::compileFile(const QString& fileName)
@@ -619,8 +498,6 @@ bool QGLShader::compileFile(const QString& fileName)
QByteArray QGLShader::sourceCode() const
{
Q_D(const QGLShader);
- if (d->isPartial)
- return d->partialSource;
GLuint shader = d->shaderGuard.id();
if (!shader)
return QByteArray();
@@ -661,10 +538,6 @@ QString QGLShader::log() const
/*!
Returns the OpenGL identifier associated with this shader.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- this function will always return zero. Partial shaders are
- created and compiled when QGLShaderProgram::link() is called.
-
\sa QGLShaderProgram::programId()
*/
GLuint QGLShader::shaderId() const
@@ -684,7 +557,6 @@ public:
: programGuard(context)
, linked(false)
, inited(false)
- , hasPartialShaders(false)
, removingShaders(false)
, vertexShader(0)
, fragmentShader(0)
@@ -695,7 +567,6 @@ public:
QGLSharedResourceGuard programGuard;
bool linked;
bool inited;
- bool hasPartialShaders;
bool removingShaders;
QString log;
QList<QGLShader *> shaders;
@@ -812,13 +683,9 @@ bool QGLShaderProgram::addShader(QGLShader *shader)
}
if (!shader->d_func()->compiled)
return false;
- if (!shader->d_func()->isPartial) {
- if (!shader->d_func()->shaderGuard.id())
- return false;
- glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
- } else {
- d->hasPartialShaders = true;
- }
+ if (!shader->d_func()->shaderGuard.id())
+ return false;
+ glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
d->linked = false; // Program needs to be relinked.
d->shaders.append(shader);
connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
@@ -999,45 +866,6 @@ bool QGLShaderProgram::link()
GLuint program = d->programGuard.id();
if (!program)
return false;
- if (d->hasPartialShaders) {
- // Compile the partial vertex and fragment shaders.
- if (d->hasShader(QGLShader::PartialVertexShader)) {
- if (!d->vertexShader) {
- d->vertexShader =
- new QGLShader(QGLShader::VertexShader, this);
- }
- if (!d->vertexShader->compile
- (d->shaders, QGLShader::PartialVertexShader)) {
- d->log = d->vertexShader->log();
- return false;
- }
- glAttachShader(program, d->vertexShader->d_func()->shaderGuard.id());
- } else {
- if (d->vertexShader) {
- glDetachShader(program, d->vertexShader->d_func()->shaderGuard.id());
- delete d->vertexShader;
- d->vertexShader = 0;
- }
- }
- if (d->hasShader(QGLShader::PartialFragmentShader)) {
- if (!d->fragmentShader) {
- d->fragmentShader =
- new QGLShader(QGLShader::FragmentShader, this);
- }
- if (!d->fragmentShader->compile
- (d->shaders, QGLShader::PartialFragmentShader)) {
- d->log = d->fragmentShader->log();
- return false;
- }
- glAttachShader(program, d->fragmentShader->d_func()->shaderGuard.id());
- } else {
- if (d->fragmentShader) {
- glDetachShader(program, d->fragmentShader->d_func()->shaderGuard.id());
- delete d->fragmentShader;
- d->fragmentShader = 0;
- }
- }
- }
glLinkProgram(program);
GLint value = 0;
glGetProgramiv(program, GL_LINK_STATUS, &value);
diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h
index 708cf09..b7bd2d7 100644
--- a/src/opengl/qglshaderprogram.h
+++ b/src/opengl/qglshaderprogram.h
@@ -66,12 +66,7 @@ public:
enum ShaderTypeBits
{
VertexShader = 0x0001,
- FragmentShader = 0x0002,
-
- PartialShader = 0x1000,
-
- PartialVertexShader = PartialShader | VertexShader,
- PartialFragmentShader = PartialShader | FragmentShader
+ FragmentShader = 0x0002
};
Q_DECLARE_FLAGS(ShaderType, ShaderTypeBits)
@@ -100,8 +95,6 @@ private:
Q_DISABLE_COPY(QGLShader)
Q_DECLARE_PRIVATE(QGLShader)
-
- bool compile(const QList<QGLShader *>& shaders, QGLShader::ShaderType type);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QGLShader::ShaderType)
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index c965947..5ca37ef 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -89,13 +89,22 @@ static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
}
-QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat)
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
{
QGLFramebufferObject *chosen = 0;
QGLFramebufferObject *candidate = 0;
for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
QGLFramebufferObject *fbo = m_fbos.at(i);
+ if (strictSize) {
+ if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+ chosen = fbo;
+ break;
+ } else {
+ continue;
+ }
+ }
+
if (fbo->format() == requestFormat) {
// choose the fbo with a matching format and the closest size
if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
@@ -127,7 +136,10 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize
}
if (!chosen) {
- chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
+ if (strictSize)
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ else
+ chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
}
if (!chosen->isValid()) {
@@ -140,7 +152,8 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize
void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
{
- m_fbos << fbo;
+ if (fbo)
+ m_fbos << fbo;
}
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index 6190d38..8a13e03 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -69,7 +69,7 @@ class QGLPixmapData;
class QGLFramebufferObjectPool
{
public:
- QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format);
+ QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false);
void release(QGLFramebufferObject *fbo);
private: