summaryrefslogtreecommitdiffstats
path: root/config.profiles/harmattan/patches/glshadercache.diff
diff options
context:
space:
mode:
Diffstat (limited to 'config.profiles/harmattan/patches/glshadercache.diff')
-rw-r--r--config.profiles/harmattan/patches/glshadercache.diff1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/config.profiles/harmattan/patches/glshadercache.diff b/config.profiles/harmattan/patches/glshadercache.diff
new file mode 100644
index 0000000000..2c6ad9a3b5
--- /dev/null
+++ b/config.profiles/harmattan/patches/glshadercache.diff
@@ -0,0 +1,1003 @@
+Index: qt-maemo-qtp/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+===================================================================
+--- qt-maemo-qtp.orig/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
++++ qt-maemo-qtp/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+@@ -42,12 +42,12 @@
+ #include "qglengineshadermanager_p.h"
+ #include "qglengineshadersource_p.h"
+ #include "qpaintengineex_opengl2_p.h"
++#include "qglshadercache_p.h"
+
+ #if defined(QT_DEBUG)
+ #include <QMetaEnum>
+ #endif
+
+-
+ QT_BEGIN_NAMESPACE
+
+ static void qt_shared_shaders_free(void *data)
+@@ -165,62 +165,89 @@
+
+ QGLShader* fragShader;
+ QGLShader* vertexShader;
+- QByteArray source;
++ QByteArray vertexSource;
++ QByteArray fragSource;
+
+ // Compile up the simple shader:
+- source.clear();
+- source.append(qShaderSnippets[MainVertexShader]);
+- source.append(qShaderSnippets[PositionOnlyVertexShader]);
+- vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+- if (!vertexShader->compileSourceCode(source))
+- qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
+-
+- source.clear();
+- source.append(qShaderSnippets[MainFragmentShader]);
+- source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
+- fragShader = new QGLShader(QGLShader::Fragment, context, this);
+- if (!fragShader->compileSourceCode(source))
+- qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
++ vertexSource.append(qShaderSnippets[MainVertexShader]);
++ vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]);
++
++ fragSource.append(qShaderSnippets[MainFragmentShader]);
++ fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
+
+ simpleShaderProg = new QGLShaderProgram(context, this);
+- simpleShaderProg->addShader(vertexShader);
+- simpleShaderProg->addShader(fragShader);
+- simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+- simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
+- simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
+- simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
++
++ CachedShader simpleShaderCache(fragSource, vertexSource);
++
++ bool inCache = simpleShaderCache.load(simpleShaderProg, context);
++
++ if (!inCache) {
++ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
++ if (!vertexShader->compileSourceCode(vertexSource))
++ qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
++
++ fragShader = new QGLShader(QGLShader::Fragment, context, this);
++ if (!fragShader->compileSourceCode(fragSource))
++ qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
++
++ simpleShaderProg->addShader(vertexShader);
++ simpleShaderProg->addShader(fragShader);
++
++ simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
++ simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
++ simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
++ simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
++ }
++
+ simpleShaderProg->link();
+- if (!simpleShaderProg->isLinked()) {
++
++ if (simpleShaderProg->isLinked()) {
++ if (!inCache)
++ simpleShaderCache.store(simpleShaderProg, context);
++ } else {
+ qCritical() << "Errors linking simple shader:"
+ << simpleShaderProg->log();
+ }
+
+ // Compile the blit shader:
+- source.clear();
+- source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
+- source.append(qShaderSnippets[UntransformedPositionVertexShader]);
+- vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+- if (!vertexShader->compileSourceCode(source))
+- qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
+-
+- source.clear();
+- source.append(qShaderSnippets[MainFragmentShader]);
+- source.append(qShaderSnippets[ImageSrcFragmentShader]);
+- fragShader = new QGLShader(QGLShader::Fragment, context, this);
+- if (!fragShader->compileSourceCode(source))
+- qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
++ vertexSource.clear();
++ vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
++ vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]);
++
++ fragSource.clear();
++ fragSource.append(qShaderSnippets[MainFragmentShader]);
++ fragSource.append(qShaderSnippets[ImageSrcFragmentShader]);
+
+ blitShaderProg = new QGLShaderProgram(context, this);
+- blitShaderProg->addShader(vertexShader);
+- blitShaderProg->addShader(fragShader);
+- blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+- blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
++
++ CachedShader blitShaderCache(fragSource, vertexSource);
++
++ inCache = blitShaderCache.load(blitShaderProg, context);
++
++ if (!inCache) {
++ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
++ if (!vertexShader->compileSourceCode(vertexSource))
++ qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
++
++ fragShader = new QGLShader(QGLShader::Fragment, context, this);
++ if (!fragShader->compileSourceCode(fragSource))
++ qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
++
++ 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()) {
++ if (blitShaderProg->isLinked()) {
++ if (!inCache)
++ blitShaderCache.store(blitShaderProg, context);
++ } else {
+ qCritical() << "Errors linking blit shader:"
+- << simpleShaderProg->log();
++ << blitShaderProg->log();
+ }
+-
+ }
+
+ QGLEngineSharedShaders::~QGLEngineSharedShaders()
+@@ -262,99 +289,108 @@
+ }
+ }
+
+- QGLShader *vertexShader = 0;
+- QGLShader *fragShader = 0;
+- QGLEngineShaderProg *newProg = 0;
+- bool success = false;
++ QScopedPointer<QGLEngineShaderProg> newProg;
+
+ do {
+- QByteArray source;
++ QByteArray fragSource;
+ // Insert the custom stage before the srcPixel shader to work around an ATI driver bug
+ // where you cannot forward declare a function that takes a sampler as argument.
+ if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
+- source.append(prog.customStageSource);
+- source.append(qShaderSnippets[prog.mainFragShader]);
+- source.append(qShaderSnippets[prog.srcPixelFragShader]);
++ fragSource.append(prog.customStageSource);
++ fragSource.append(qShaderSnippets[prog.mainFragShader]);
++ fragSource.append(qShaderSnippets[prog.srcPixelFragShader]);
+ if (prog.compositionFragShader)
+- source.append(qShaderSnippets[prog.compositionFragShader]);
++ fragSource.append(qShaderSnippets[prog.compositionFragShader]);
+ if (prog.maskFragShader)
+- source.append(qShaderSnippets[prog.maskFragShader]);
+- fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
+- QByteArray description;
++ fragSource.append(qShaderSnippets[prog.maskFragShader]);
++
++ QByteArray vertexSource;
++ vertexSource.append(qShaderSnippets[prog.mainVertexShader]);
++ vertexSource.append(qShaderSnippets[prog.positionVertexShader]);
++
++ QScopedPointer<QGLShaderProgram> shaderProgram(new QGLShaderProgram(ctxGuard.context(), this));
++
++ CachedShader shaderCache(fragSource, vertexSource);
++ bool inCache = shaderCache.load(shaderProgram.data(), ctxGuard.context());
++
++ if (!inCache) {
++
++ QScopedPointer<QGLShader> fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), this));
++ QByteArray description;
+ #if defined(QT_DEBUG)
+- // Name the shader for easier debugging
+- 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));
++ // Name the shader for easier debugging
++ 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));
+ #endif
+- if (!fragShader->compileSourceCode(source)) {
+- qWarning() << "Warning:" << description << "failed to compile!";
+- break;
+- }
++ if (!fragShader->compileSourceCode(fragSource)) {
++ qWarning() << "Warning:" << description << "failed to compile!";
++ break;
++ }
+
+- source.clear();
+- source.append(qShaderSnippets[prog.mainVertexShader]);
+- source.append(qShaderSnippets[prog.positionVertexShader]);
+- vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
++ QScopedPointer<QGLShader> vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), this));
+ #if defined(QT_DEBUG)
+- // Name the shader for easier debugging
+- 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));
++ // Name the shader for easier debugging
++ 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
+- if (!vertexShader->compileSourceCode(source)) {
+- qWarning() << "Warning:" << description << "failed to compile!";
+- break;
+- }
++ if (!vertexShader->compileSourceCode(vertexSource)) {
++ qWarning() << "Warning:" << description << "failed to compile!";
++ break;
++ }
+
+- newProg = new QGLEngineShaderProg(prog);
++ shaderProgram->addShader(vertexShader.take());
++ shaderProgram->addShader(fragShader.take());
+
+- // If the shader program's not found in the cache, create it now.
+- 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:
+- 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);
+- if (newProg->usePmvMatrixAttribute) {
+- newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
+- newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
+- newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
++ // We have to bind the vertex attribute names before the program is linked:
++ shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
++ if (prog.useTextureCoords)
++ shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
++ if (prog.useOpacityAttribute)
++ shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
++ if (prog.usePmvMatrixAttribute) {
++ shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
++ shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
++ shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
++ }
+ }
+
++ newProg.reset(new QGLEngineShaderProg(prog));
++ newProg->program = shaderProgram.take();
++
+ newProg->program->link();
+- if (!newProg->program->isLinked()) {
++ if (newProg->program->isLinked()) {
++ if (!inCache)
++ shaderCache.store(newProg->program, ctxGuard.context());
++ } else {
+ QLatin1String none("none");
+ QLatin1String br("\n");
+ QString error;
+- error = QLatin1String("Shader program failed to link,")
++ error = QLatin1String("Shader program failed to link,");
+ #if defined(QT_DEBUG)
+- + br
+- + QLatin1String(" Shaders Used:") + br
+- + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
+- + QLatin1String(vertexShader->sourceCode()) + br
+- + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
+- + QLatin1String(fragShader->sourceCode()) + br
++ error += QLatin1String("\n Shaders Used:\n");
++ for (int i = 0; i < newProg->program->shaders().count(); ++i) {
++ QGLShader *shader = newProg->program->shaders().at(i);
++ error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n")
++ + QLatin1String(shader->sourceCode()) + br;
++ }
+ #endif
+- + QLatin1String(" Error Log:\n")
+- + QLatin1String(" ") + newProg->program->log();
++ error += QLatin1String(" Error Log:\n")
++ + QLatin1String(" ") + newProg->program->log();
+ qWarning() << error;
+ break;
+ }
+@@ -376,26 +412,10 @@
+ }
+ }
+
+- cachedPrograms.insert(0, newProg);
+-
+- success = true;
++ cachedPrograms.insert(0, newProg.data());
+ } while (false);
+
+- // Clean up everything if we weren't successful
+- if (!success) {
+- if (newProg) {
+- delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
+- newProg = 0;
+- }
+- else {
+- if (vertexShader)
+- delete vertexShader;
+- if (fragShader)
+- delete fragShader;
+- }
+- }
+-
+- return newProg;
++ return newProg.take();
+ }
+
+ void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
+Index: qt-maemo-qtp/src/opengl/gl2paintengineex/qglshadercache_meego_p.h
+===================================================================
+--- /dev/null
++++ qt-maemo-qtp/src/opengl/gl2paintengineex/qglshadercache_meego_p.h
+@@ -0,0 +1,457 @@
++/****************************************************************************
++**
++** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
++** All rights reserved.
++** Contact: Nokia Corporation (qt-info@nokia.com)
++**
++** This file is part of the QtOpenGL module 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$
++**
++****************************************************************************/
++
++//
++// W A R N I N G
++// -------------
++//
++// This file is not part of the Qt API. It exists purely as an
++// implementation detail. This header file may change from version to
++// version without notice, or even be removed.
++//
++// We mean it.
++//
++
++#ifndef QGLSHADERCACHE_MEEGO_P_H
++#define QGLSHADERCACHE_MEEGO_P_H
++
++#include <QtCore/qglobal.h>
++
++#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2)
++
++#include <QtCore/qcryptographichash.h>
++#include <QtCore/qsharedmemory.h>
++#include <QtCore/qsystemsemaphore.h>
++
++#ifndef QT_BOOTSTRAPPED
++# include <GLES2/gl2ext.h>
++#endif
++#if defined(QT_DEBUG) || defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE)
++# include <syslog.h>
++#endif
++
++QT_BEGIN_HEADER
++
++/*
++ This cache stores internal Qt shader programs in shared memory.
++
++ This header file is ugly on purpose and can only be included once. It is only to be used
++ for the internal shader cache, not as a generic cache for anyone's shaders.
++
++ The cache stores either ShaderCacheMaxEntries shader programs or ShaderCacheDataSize kilobytes
++ of shader programs, whatever limit is reached first.
++
++ The layout of the cache is as outlined in the CachedShaders struct. After some
++ integers, an array of headers is reserved, then comes the space for the actual binaries.
++
++ Shader Programs are identified by the md5sum of their frag and vertex shader source code.
++
++ Shader Programs are never removed. The cache never shrinks or re-shuffles. This is done
++ on purpose to ensure minimum amount of locking, no alignment problems and very few write
++ operations.
++
++ Note: Locking the shader cache could be expensive, because the entire system might hang.
++ That's why the cache is immutable to minimize the time we need to keep it locked.
++
++ Why is it Meego specific?
++
++ First, the size is chosen so that it fits to generic meego usage. Second, on Meego, there's
++ always at least one Qt application active (the launcher), so the cache will never be destroyed.
++ Only when the last Qt app exits, the cache dies, which should only be when someone kills the
++ X11 server. And last but not least it was only tested with Meego's SGX driver.
++
++ There's a small tool in src/opengl/util/meego that dumps the contents of the cache.
++ */
++
++// anonymous namespace, prevent exporting of the private symbols
++namespace
++{
++
++struct CachedShaderHeader
++{
++ /* the index in the data[] member of CachedShaders */
++ int index;
++ /* the size of the binary shader */
++ GLsizei size;
++ /* the format of the binary shader */
++ GLenum format;
++ /* the md5sum of the frag+vertex shaders */
++ char md5Sum[16];
++};
++
++enum
++{
++ /* The maximum amount of shader programs the cache can hold */
++ ShaderCacheMaxEntries = 20
++};
++
++typedef CachedShaderHeader CachedShaderHeaders[ShaderCacheMaxEntries];
++
++enum
++{
++ // ShaderCacheDataSize is 20k minus the other data members of CachedShaders
++ ShaderCacheDataSize = 1024 * ShaderCacheMaxEntries - sizeof(CachedShaderHeaders) - 2 * sizeof(int)
++};
++
++struct CachedShaders
++{
++ /* How much space is still available in the cache */
++ inline int availableSize() const { return ShaderCacheDataSize - dataSize; }
++
++ /* The current amount of cached shaders */
++ int shaderCount;
++
++ /* The current amount (in bytes) of cached data */
++ int dataSize;
++
++ /* The headers describing the shaders */
++ CachedShaderHeaders headers;
++
++ /* The actual binary data of the shader programs */
++ char data[ShaderCacheDataSize];
++};
++
++//#define QT_DEBUG_SHADER_CACHE
++#ifdef QT_DEBUG_SHADER_CACHE
++static QDebug shaderCacheDebug()
++{
++ return QDebug(QtDebugMsg);
++}
++#else
++static inline QNoDebug shaderCacheDebug() { return QNoDebug(); }
++#endif
++
++class ShaderCacheSharedMemory
++{
++public:
++ ShaderCacheSharedMemory()
++ : shm(QLatin1String("qt_gles2_shadercache_" QT_VERSION_STR))
++ {
++ // we need a system semaphore here, since cache creation and initialization must be atomic
++ QSystemSemaphore attachSemaphore(QLatin1String("qt_gles2_shadercache_mutex_" QT_VERSION_STR), 1);
++
++ if (!attachSemaphore.acquire()) {
++ shaderCacheDebug() << "Unable to require shader cache semaphore:" << attachSemaphore.errorString();
++ return;
++ }
++
++ if (shm.attach()) {
++ // success!
++ shaderCacheDebug() << "Attached to shader cache";
++ } else {
++
++ // no cache exists - create and initialize it
++ if (shm.create(sizeof(CachedShaders))) {
++ shaderCacheDebug() << "Created new shader cache";
++ initializeCache();
++ } else {
++ shaderCacheDebug() << "Unable to create shader cache:" << shm.errorString();
++ }
++ }
++
++ attachSemaphore.release();
++ }
++
++ inline bool isAttached() const { return shm.isAttached(); }
++
++ inline bool lock() { return shm.lock(); }
++ inline bool unlock() { return shm.unlock(); }
++ inline void *data() { return shm.data(); }
++ inline QString errorString() { return shm.errorString(); }
++
++ ~ShaderCacheSharedMemory()
++ {
++ if (!shm.detach())
++ shaderCacheDebug() << "Unable to detach shader cache" << shm.errorString();
++ }
++
++private:
++ void initializeCache()
++ {
++ // no need to lock the shared memory since we're already protected by the
++ // attach system semaphore.
++
++ void *data = shm.data();
++ Q_ASSERT(data);
++
++ memset(data, 0, sizeof(CachedShaders));
++ }
++
++ QSharedMemory shm;
++};
++
++class ShaderCacheLocker
++{
++public:
++ inline ShaderCacheLocker(ShaderCacheSharedMemory *cache)
++ : shm(cache->lock() ? cache : (ShaderCacheSharedMemory *)0)
++ {
++ if (!shm)
++ shaderCacheDebug() << "Unable to lock shader cache" << cache->errorString();
++ }
++
++ inline bool isLocked() const { return shm; }
++
++ inline ~ShaderCacheLocker()
++ {
++ if (!shm)
++ return;
++ if (!shm->unlock())
++ shaderCacheDebug() << "Unable to unlock shader cache" << shm->errorString();
++ }
++
++private:
++ ShaderCacheSharedMemory *shm;
++};
++
++#ifdef QT_BOOTSTRAPPED
++} // end namespace
++#else
++
++static void traceCacheOverflow(const char *message)
++{
++#if defined(QT_DEBUG) || defined (QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE)
++ openlog(qPrintable(QCoreApplication::applicationName()), LOG_PID | LOG_ODELAY, LOG_USER);
++ syslog(LOG_DEBUG, message);
++ closelog();
++#endif
++ shaderCacheDebug() << message;
++}
++
++Q_GLOBAL_STATIC(ShaderCacheSharedMemory, shaderCacheSharedMemory)
++
++/*
++ Finds the index of the shader program identified by md5Sum in the cache.
++ Note: Does NOT lock the cache for reading, the cache must already be locked!
++
++ Returns -1 when no shader was found.
++ */
++static int qt_cache_index_unlocked(const QByteArray &md5Sum, CachedShaders *cache)
++{
++ for (int i = 0; i < cache->shaderCount; ++i) {
++ if (qstrncmp(md5Sum.constData(), cache->headers[i].md5Sum, 16) == 0) {
++ return i;
++ }
++ }
++ return -1;
++}
++
++/* Returns the index of the shader identified by md5Sum */
++static int qt_cache_index(const QByteArray &md5Sum)
++{
++ ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
++ if (!shm || !shm->isAttached())
++ return false;
++
++ Q_ASSERT(md5Sum.length() == 16);
++
++ ShaderCacheLocker locker(shm);
++ if (!locker.isLocked())
++ return false;
++
++ void *data = shm->data();
++ Q_ASSERT(data);
++
++ CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
++
++ return qt_cache_index_unlocked(md5Sum, cache);
++}
++
++/* Loads the cached shader at index \a shaderIndex into \a program
++ * Note: Since the cache is immutable, this operation doesn't lock the shared memory.
++ */
++static bool qt_cached_shader(QGLShaderProgram *program, const QGLContext *ctx, int shaderIndex)
++{
++ Q_ASSERT(shaderIndex >= 0 && shaderIndex <= ShaderCacheMaxEntries);
++ Q_ASSERT(program);
++
++ ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
++ if (!shm || !shm->isAttached())
++ return false;
++
++ void *data = shm->data();
++ Q_ASSERT(data);
++
++ CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
++
++ shaderCacheDebug() << "fetching cached shader at index" << shaderIndex
++ << "dataIndex" << cache->headers[shaderIndex].index
++ << "size" << cache->headers[shaderIndex].size
++ << "format" << cache->headers[shaderIndex].format;
++
++ // call program->programId first, since that resolves the glProgramBinaryOES symbol
++ GLuint programId = program->programId();
++ glProgramBinaryOES(programId, cache->headers[shaderIndex].format,
++ cache->data + cache->headers[shaderIndex].index,
++ cache->headers[shaderIndex].size);
++
++ return true;
++}
++
++/* Stores the shader program in the cache. Returns false if there's an error with the cache, or
++ if the cache is too small to hold the shader. */
++static bool qt_cache_shader(const QGLShaderProgram *shader, const QGLContext *ctx, const QByteArray &md5Sum)
++{
++ ShaderCacheSharedMemory *shm = shaderCacheSharedMemory();
++ if (!shm || !shm->isAttached())
++ return false;
++
++ void *data = shm->data();
++ Q_ASSERT(data);
++
++ CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
++
++ ShaderCacheLocker locker(shm);
++ if (!locker.isLocked())
++ return false;
++
++ int cacheIdx = cache->shaderCount;
++ if (cacheIdx >= ShaderCacheMaxEntries) {
++ traceCacheOverflow("Qt OpenGL shader cache index overflow!");
++ return false;
++ }
++
++ // now that we have the lock on the shared memory, make sure no one
++ // inserted the shader already while we were unlocked
++ if (qt_cache_index_unlocked(md5Sum, cache) != -1)
++ return true; // already cached
++
++ shaderCacheDebug() << "Caching shader at index" << cacheIdx;
++
++ GLint binaryLength = 0;
++ glGetProgramiv(shader->programId(), GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength);
++
++ if (!binaryLength) {
++ shaderCacheDebug() << "Unable to determine binary shader size!";
++ return false;
++ }
++
++ if (binaryLength > cache->availableSize()) {
++ traceCacheOverflow("Qt OpenGL shader cache data overflow!");
++ return false;
++ }
++
++ GLsizei size = 0;
++ GLenum format = 0;
++ glGetProgramBinaryOES(shader->programId(), binaryLength, &size, &format,
++ cache->data + cache->dataSize);
++
++ if (!size) {
++ shaderCacheDebug() << "Unable to get binary shader!";
++ return false;
++ }
++
++ cache->headers[cacheIdx].index = cache->dataSize;
++ cache->dataSize += binaryLength;
++ ++cache->shaderCount;
++ cache->headers[cacheIdx].size = binaryLength;
++ cache->headers[cacheIdx].format = format;
++
++ memcpy(cache->headers[cacheIdx].md5Sum, md5Sum.constData(), 16);
++
++ shaderCacheDebug() << "cached shader size" << size
++ << "format" << format
++ << "binarySize" << binaryLength
++ << "cache index" << cacheIdx
++ << "data index" << cache->headers[cacheIdx].index;
++
++ return true;
++}
++
++} // namespace
++
++QT_BEGIN_NAMESPACE
++
++QT_MODULE(OpenGL)
++
++class CachedShader
++{
++public:
++ CachedShader(const QByteArray &fragSource, const QByteArray &vertexSource)
++ : cacheIdx(-1)
++ {
++ QCryptographicHash md5Hash(QCryptographicHash::Md5);
++
++ md5Hash.addData(fragSource);
++ md5Hash.addData(vertexSource);
++
++ md5Sum = md5Hash.result();
++ }
++
++ bool isCached()
++ {
++ return cacheIndex() != -1;
++ }
++
++ int cacheIndex()
++ {
++ if (cacheIdx != -1)
++ return cacheIdx;
++ cacheIdx = qt_cache_index(md5Sum);
++ return cacheIdx;
++ }
++
++ bool load(QGLShaderProgram *program, const QGLContext *ctx)
++ {
++ if (cacheIndex() == -1)
++ return false;
++ return qt_cached_shader(program, ctx, cacheIdx);
++ }
++
++ bool store(QGLShaderProgram *program, const QGLContext *ctx)
++ {
++ return qt_cache_shader(program, ctx, md5Sum);
++ }
++
++private:
++ QByteArray md5Sum;
++ int cacheIdx;
++};
++
++
++QT_END_NAMESPACE
++
++#endif
++
++QT_END_HEADER
++
++#endif
++#endif
+Index: qt-maemo-qtp/src/opengl/gl2paintengineex/qglshadercache_p.h
+===================================================================
+--- /dev/null
++++ qt-maemo-qtp/src/opengl/gl2paintengineex/qglshadercache_p.h
+@@ -0,0 +1,98 @@
++/****************************************************************************
++**
++** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
++** All rights reserved.
++** Contact: Nokia Corporation (qt-info@nokia.com)
++**
++** This file is part of the QtOpenGL module 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$
++**
++****************************************************************************/
++
++//
++// W A R N I N G
++// -------------
++//
++// This file is not part of the Qt API. It exists purely as an
++// implementation detail. This header file may change from version to
++// version without notice, or even be removed.
++//
++// We mean it.
++//
++
++#ifndef QGLSHADERCACHE_P_H
++#define QGLSHADERCACHE_P_H
++
++#include <QtCore/qglobal.h>
++
++#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2)
++# include "qglshadercache_meego_p.h"
++#else
++
++QT_BEGIN_HEADER
++
++QT_BEGIN_NAMESPACE
++
++QT_MODULE(OpenGL)
++
++class QGLShaderProgram;
++class QGLContext;
++
++class CachedShader
++{
++public:
++ inline CachedShader(const QByteArray &, const QByteArray &)
++ {}
++
++ inline bool isCached()
++ {
++ return false;
++ }
++
++ inline bool load(QGLShaderProgram *, const QGLContext *)
++ {
++ return false;
++ }
++
++ inline bool store(QGLShaderProgram *, const QGLContext *)
++ {
++ return false;
++ }
++};
++
++QT_END_NAMESPACE
++
++QT_END_HEADER
++
++#endif
++#endif
+Index: qt-maemo-qtp/src/opengl/opengl.pro
+===================================================================
+--- qt-maemo-qtp.orig/src/opengl/opengl.pro
++++ qt-maemo-qtp/src/opengl/opengl.pro
+@@ -58,7 +58,9 @@
+ gl2paintengineex/qglcustomshaderstage_p.h \
+ gl2paintengineex/qtriangulatingstroker_p.h \
+ gl2paintengineex/qtriangulator_p.h \
+- gl2paintengineex/qtextureglyphcache_gl_p.h
++ gl2paintengineex/qtextureglyphcache_gl_p.h \
++ gl2paintengineex/qglshadercache_p.h \
++ gl2paintengineex/qglshadercache_meego_p.h
+
+ SOURCES += qglshaderprogram.cpp \
+ qglpixmapfilter.cpp \
+Index: qt-maemo-qtp/src/opengl/util/meego/main.cpp
+===================================================================
+--- /dev/null
++++ qt-maemo-qtp/src/opengl/util/meego/main.cpp
+@@ -0,0 +1,48 @@
++#include <QtCore/qdebug.h>
++
++#define QT_DEBUG_SHADER_CACHE
++#define QT_MEEGO_EXPERIMENTAL_SHADERCACHE
++#define QT_OPENGL_ES_2
++#define QT_BOOTSTRAPPED
++
++typedef int GLsizei;
++typedef unsigned int GLenum;
++
++#include "../../gl2paintengineex/qglshadercache_meego_p.h"
++
++#include <stdlib.h>
++#include <stdio.h>
++
++int main()
++{
++ ShaderCacheSharedMemory shm;
++
++ if (!shm.isAttached()) {
++ fprintf(stderr, "Unable to attach to shared memory\n");
++ return EXIT_FAILURE;
++ }
++
++ ShaderCacheLocker locker(&shm);
++ if (!locker.isLocked()) {
++ fprintf(stderr, "Unable to lock shared memory\n");
++ return EXIT_FAILURE;
++ }
++
++ void *data = shm.data();
++ Q_ASSERT(data);
++
++ CachedShaders *cache = reinterpret_cast<CachedShaders *>(data);
++
++ for (int i = 0; i < cache->shaderCount; ++i) {
++ printf("Shader %d: %d bytes\n", i, cache->headers[i].size);
++ }
++
++ printf("\nSummary:\n\n"
++ " Amount of cached shaders: %d\n"
++ " Bytes used: %d\n"
++ " Bytes available: %d\n",
++ cache->shaderCount, cache->dataSize, cache->availableSize());
++
++ return EXIT_SUCCESS;
++}
++
+Index: qt-maemo-qtp/src/opengl/util/meego/shader-cache-introspector.pro
+===================================================================
+--- /dev/null
++++ qt-maemo-qtp/src/opengl/util/meego/shader-cache-introspector.pro
+@@ -0,0 +1,7 @@
++TEMPLATE = app
++
++SOURCES += main.cpp
++
++TARGET = shader-cache-introspector
++
++QT = core