diff options
Diffstat (limited to 'config.profiles/harmattan/patches/glshadercache.diff')
-rw-r--r-- | config.profiles/harmattan/patches/glshadercache.diff | 1003 |
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 0000000..2c6ad9a --- /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 |