summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authorTom Cooksey <thomas.cooksey@nokia.com>2009-10-30 12:38:00 +0100
committerTom Cooksey <thomas.cooksey@nokia.com>2009-10-30 14:03:25 +0100
commit90567274b900b22ab6b1c016ee66b7915aa994c8 (patch)
tree1c8df6469520c99f054e4b6b2c8ec4e1fea847d4 /src/opengl
parenta8d1c0a7137b2d1f7ca74a24321cea41428ce0bd (diff)
Implement a simple caching algorithm for shader programs.
When the number of programs held in the cache exceeds a threshold, the least frequantly used programs get deleted. This also covers programs with custom snippets of code. As a conequence, when a QGLCustomShaderStage gets deleted, any programs using that code will (eventually) be freed. Reviewed-By: Samuel Rødal
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp71
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h13
2 files changed, 53 insertions, 31 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index be0e98a170..34c448f4e4 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -231,12 +231,14 @@ QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
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]);
@@ -280,20 +282,22 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
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(vertexShader);
- cached.program->addShader(fragShader);
+ 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;
@@ -307,32 +311,42 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
+ 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) {
- if (cachedPrograms.at(i).customStageSource == stage->source()) {
- delete cachedPrograms.at(i).program;
- cachedPrograms.removeAt(i--);
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (cachedProg->customStageSource == stage->source()) {
+ delete cachedProg;
+ cachedPrograms.removeAt(i);
+ i--;
}
}
}
-
QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
: ctx(context),
shaderProgNeedsChanging(true),
@@ -487,7 +501,6 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
}
QGLEngineShaderProg requiredProgram;
- requiredProgram.program = 0;
bool texCoords = false;
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index fd73b44292..59e50d0bf4 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -366,13 +366,22 @@ private:
QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
QGLShaderProgram *simpleShaderProg;
- QList<QGLEngineShaderProg> cachedPrograms;
+ QList<QGLEngineShaderProg*> cachedPrograms;
static const char* qShaderSnippets[TotalSnippetCount];
};
-struct QGLEngineShaderProg
+
+class QGLEngineShaderProg
{
+public:
+ QGLEngineShaderProg() : program(0) {}
+
+ ~QGLEngineShaderProg() {
+ if (program)
+ delete program;
+ }
+
QGLEngineSharedShaders::SnippetName mainVertexShader;
QGLEngineSharedShaders::SnippetName positionVertexShader;
QGLEngineSharedShaders::SnippetName mainFragShader;