diff options
Diffstat (limited to 'src/opengl/gl2paintengineex/qglpexshadermanager.cpp')
-rw-r--r-- | src/opengl/gl2paintengineex/qglpexshadermanager.cpp | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp new file mode 100644 index 0000000..e460e08 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglpexshadermanager_p.h" + +#include "glgc_shader_source.h" + +QGLPEXShaderManager::QGLPEXShaderManager(const QGLContext* context) +{ + ctx = const_cast<QGLContext*>(context); + + defaultVertexShader= new QGLShader(QGLShader::VertexShader, context); + defaultVertexShader->addSource(QLatin1String(qglslDefaultVertexShader)); + if (!defaultVertexShader->compile()) + qWarning() << "Default vertex shader failed to compile: " << defaultVertexShader->log(); + + noBrushShader = new QGLShader(QGLShader::FragmentShader, context); + noBrushShader->addSource(QLatin1String(qglslFragmentShaderMain)); + noBrushShader->addSource(QLatin1String(qglslNoBrushFragmentShader)); + if (!noBrushShader->compile()) + qWarning() << "No brush shader failed to compile:" << noBrushShader->log(); + + + // Create a program for noBrush: + QGLShaderProgram* noBrushProg = new QGLShaderProgram(ctx); + noBrushProg->addShader(defaultVertexShader); + noBrushProg->addShader(noBrushShader); + if (!noBrushProg->link()) + qWarning() << "NoBrush shader program failed to link:" << noBrushProg->log(); + + // Add noBrush Program to cache: + QGLCachedShaderProg cachedProg; + cachedProg.vertexShader = defaultVertexShader; + cachedProg.brushShader = noBrushShader; + cachedProg.compositionShader = 0; + cachedProg.shader = noBrushProg; + cachedPrograms.append(cachedProg); + + + // Set state + useGlobalOpacity = true; + currentBrushStyle = Qt::NoBrush; + currentTransformType = FullTransform; + shaderProgNeedsChanging = false; + activeProgram = noBrushProg; + + solidBrushShader = 0; + + conicalBrushVertexShader = 0; + conicalBrushFragmentShader = 0; + + radialBrushVertexShader = 0; + radialBrushFragmentShader = 0; + + linearBrushVertexShader = 0; + linearBrushFragmentShader = 0; + + patternBrushVertexShader = 0; + patternBrushFragmentShader = 0; + + textureBrushFragmentShader = 0; + textureBrushVertexShader = 0; + + simpleFragmentShader = 0; + simpleShaderProgram = 0; + + imageVertexShader = 0; + imageFragmentShader = 0; + imageShaderProgram = 0; + + textVertexShader = 0; + textFragmentShader = 0; + textShaderProgram = 0; +} + +QGLPEXShaderManager::~QGLPEXShaderManager() +{ + delete defaultVertexShader; + delete imageVertexShader; + delete imageFragmentShader; + delete imageShaderProgram; + delete textVertexShader; + delete textFragmentShader; + delete textShaderProgram; + delete noBrushShader; + delete solidBrushShader; + + delete conicalBrushVertexShader; + delete conicalBrushFragmentShader; + + delete radialBrushVertexShader; + delete radialBrushFragmentShader; + + delete linearBrushFragmentShader; + delete linearBrushVertexShader; + + delete patternBrushFragmentShader; + delete patternBrushVertexShader; + + delete textureBrushFragmentShader; + delete textureBrushVertexShader; + + delete simpleFragmentShader; + delete simpleShaderProgram; +} + +void QGLPEXShaderManager::setUseGlobalOpacity(bool value) +{ + if (value != useGlobalOpacity) + shaderProgNeedsChanging = true; + + useGlobalOpacity = value; +} + +void QGLPEXShaderManager::setBrushStyle(Qt::BrushStyle style) +{ + if (currentBrushStyle != style) + shaderProgNeedsChanging = true; + + currentBrushStyle = style; +} + +void QGLPEXShaderManager::setAffineOnlyBrushTransform(bool value) +{ + Q_UNUSED(value); + // TODO +} + +bool QGLPEXShaderManager::useCorrectShaderProg() +{ + if (!shaderProgNeedsChanging) { + activeProgram->use(); + return false; + } + + const char* fragmentShaderMainSrc = qglslFragmentShaderMain; + QGLShader* vertexShader = defaultVertexShader; + QGLShader* fragmentShader = noBrushShader; + + // Make sure we compile up the correct brush shader + switch (currentBrushStyle) { + case Qt::NoBrush: + break; + case Qt::SolidPattern: + if (!solidBrushShader) { + qDebug("Compiling qglslSolidBrushFragmentShader"); + solidBrushShader = new QGLShader(QGLShader::FragmentShader, ctx); + solidBrushShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); + solidBrushShader->addSource(QLatin1String(qglslSolidBrushFragmentShader)); + if (!solidBrushShader->compile()) + qWarning() << "qglslSolidBrush failed to compile:" << solidBrushShader->log(); + } + fragmentShader = solidBrushShader; + break; + case Qt::TexturePattern: + if (!textureBrushVertexShader) { + qDebug("Compiling qglslTextureBrushVertexShader"); + textureBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + textureBrushVertexShader->addSource(QLatin1String(qglslTextureBrushVertexShader)); + if (!textureBrushVertexShader->compile()) { + qWarning() << "qglslTextureBrushVertexShader failed to compile: " + << textureBrushVertexShader->log(); + } + } + vertexShader = textureBrushVertexShader; + + if (!textureBrushFragmentShader) { + qDebug("Compiling qglslTextureBrushFragmentShader"); + textureBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + textureBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); + textureBrushFragmentShader->addSource(QLatin1String(qglslTextureBrushFragmentShader)); + if (!textureBrushFragmentShader->compile()) { + qWarning() << "qglslTextureBrushFragmentShader failed to compile:" + << textureBrushFragmentShader->log(); + } + } + fragmentShader = textureBrushFragmentShader; + break; + case Qt::LinearGradientPattern: + if (!linearBrushVertexShader) { + qDebug("Compiling qglslLinearGradientBrushVertexShader"); + linearBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + linearBrushVertexShader->addSource(QLatin1String(qglslLinearGradientBrushVertexShader)); + if (!linearBrushVertexShader->compile()) { + qWarning() << "qglslLinearGradientBrushVertexShader failed to compile: " + << linearBrushVertexShader->log(); + } + } + vertexShader = linearBrushVertexShader; + + if (!linearBrushFragmentShader) { + qDebug("Compiling qglslLinearGradientBrushFragmentShader"); + linearBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + linearBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); + linearBrushFragmentShader->addSource(QLatin1String(qglslLinearGradientBrushFragmentShader)); + if (!linearBrushFragmentShader->compile()) { + qWarning() << "qglslLinearGradientBrushFragmentShader failed to compile:" + << linearBrushFragmentShader->log(); + } + } + fragmentShader = linearBrushFragmentShader; + break; + case Qt::RadialGradientPattern: + if (!radialBrushVertexShader) { + qDebug("Compiling qglslRadialGradientBrushVertexShader"); + radialBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + radialBrushVertexShader->addSource(QLatin1String(qglslRadialGradientBrushVertexShader)); + if (!radialBrushVertexShader->compile()) { + qWarning() << "qglslRadialGradientBrushVertexShader failed to compile: " + << radialBrushVertexShader->log(); + } + } + vertexShader = radialBrushVertexShader; + + if (!radialBrushFragmentShader) { + qDebug("Compiling qglslRadialGradientBrushFragmentShader"); + radialBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + radialBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); + radialBrushFragmentShader->addSource(QLatin1String(qglslRadialGradientBrushFragmentShader)); + if (!radialBrushFragmentShader->compile()) { + qWarning() << "qglslRadialGradientBrushFragmentShader failed to compile:" + << radialBrushFragmentShader->log(); + } + } + fragmentShader = radialBrushFragmentShader; + break; + case Qt::ConicalGradientPattern: + // FIXME: We currently use the same vertex shader as radial brush + if (!conicalBrushVertexShader) { + qDebug("Compiling qglslConicalGradientBrushVertexShader"); + conicalBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + conicalBrushVertexShader->addSource(QLatin1String(qglslConicalGradientBrushVertexShader)); + if (!conicalBrushVertexShader->compile()) { + qWarning() << "qglslConicalGradientBrushVertexShader failed to compile: " + << conicalBrushVertexShader->log(); + } + } + vertexShader = conicalBrushVertexShader; + + if (!conicalBrushFragmentShader) { + qDebug("Compiling qglslConicalGradientBrushFragmentShader"); + conicalBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + conicalBrushFragmentShader->addSource(QLatin1String(fragmentShaderMainSrc)); + conicalBrushFragmentShader->addSource(QLatin1String(qglslConicalGradientBrushFragmentShader)); + if (!conicalBrushFragmentShader->compile()) { + qWarning() << "qglslConicalGradientBrushFragmentShader failed to compile:" + << conicalBrushFragmentShader->log(); + } + } + fragmentShader = conicalBrushFragmentShader; + break; + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: + if (!patternBrushVertexShader) { + qDebug("Compiling qglslPatternBrushVertexShader"); + patternBrushVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + patternBrushVertexShader->addSource(QLatin1String(qglslPatternBrushVertexShader)); + if (!patternBrushVertexShader->compile()) { + qWarning() << "qglslPatternBrushVertexShader failed to compile: " + << patternBrushVertexShader->log(); + } + } + vertexShader = patternBrushVertexShader; + + if (!patternBrushFragmentShader) { + qDebug("Compiling qglslPatternBrushFragmentShader"); + patternBrushFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + patternBrushFragmentShader->addSource(QLatin1String(qglslNoOpacityFragmentShaderMain)); + patternBrushFragmentShader->addSource(QLatin1String(qglslPatternBrushFragmentShader)); + if (!patternBrushFragmentShader->compile()) { + qWarning() << "qglslPatternBrushFragmentShader failed to compile:" + << patternBrushFragmentShader->log(); + } + } + fragmentShader = patternBrushFragmentShader; + break; + default: + qWarning("Unimplemented brush style (%d)", currentBrushStyle); + } + + // Now newBrushShader is set correctly, check to see if we already have the program + // already linked and ready to go in the cache: + bool foundProgram = false; + foreach (QGLCachedShaderProg cachedProg, cachedPrograms) { + if ((cachedProg.vertexShader == vertexShader) && + (cachedProg.brushShader == fragmentShader) && + (cachedProg.compositionShader == 0) ) { + + activeProgram = cachedProg.shader; + foundProgram = true; + break; + } + } + + if (!foundProgram) { + qDebug() << "Linking shader program for " << currentBrushStyle; + // Required program not found - create it. + QGLShaderProgram* newProg = new QGLShaderProgram(ctx); + + newProg->addShader(vertexShader); + newProg->addShader(fragmentShader); + + if (!newProg->link()) + qWarning() << "Shader program for " << currentBrushStyle << "failed to link:" << newProg->log(); + + QGLCachedShaderProg cachedProg; + cachedProg.vertexShader = vertexShader; + cachedProg.brushShader = fragmentShader; + cachedProg.compositionShader = 0; + cachedProg.shader = newProg; + + cachedPrograms.append(cachedProg); + activeProgram = newProg; + } + + activeProgram->use(); + shaderProgNeedsChanging = false; + return true; +} + +QGLShaderProgram* QGLPEXShaderManager::brushShader() +{ + return activeProgram; +} + +// The only uniform the simple shader has is the PMV matrix +QGLShaderProgram* QGLPEXShaderManager::simpleShader() +{ + if (!simpleShaderProgram) { + simpleShaderProgram = new QGLShaderProgram(ctx); + + if (!simpleFragmentShader) { + simpleFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + simpleFragmentShader->addSource(QLatin1String(qglslSimpleFragmentShader)); + if (!simpleFragmentShader->compile()) + qWarning() << "qglslSimpleFragmentShader failed to compile:" << simpleFragmentShader->log(); + } + + simpleShaderProgram->addShader(defaultVertexShader); + simpleShaderProgram->addShader(simpleFragmentShader); + if (!simpleShaderProgram->link()) + qWarning() << "Simple shader program failed to link:" << simpleShaderProgram->log(); + } + + return simpleShaderProgram; +} + +QGLShaderProgram* QGLPEXShaderManager::imageShader() +{ + if (!imageShaderProgram) { + if (!imageVertexShader) { + imageVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + imageVertexShader->addSource(QLatin1String(qglslImageVertexShader)); + if (!imageVertexShader->compile()) + qWarning() << "Image/Pixmap vertex shader failed to compile:" << imageVertexShader->log(); + } + + if (!imageFragmentShader) { + imageFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + imageFragmentShader->addSource(QLatin1String(qglslImageFragmentShader)); + if (!imageFragmentShader->compile()) + qWarning() << "Image/Pixmap fragment shader failed to compile:" << imageFragmentShader->log(); + } + + imageShaderProgram = new QGLShaderProgram(ctx); + imageShaderProgram->addShader(imageVertexShader); + imageShaderProgram->addShader(imageFragmentShader); + if (!imageShaderProgram->link()) + qWarning() << "Image/Pixmap shader program failed to link:" << imageShaderProgram->log(); + } + + return imageShaderProgram; +} + +QGLShaderProgram* QGLPEXShaderManager::textShader() +{ + if (!textShaderProgram) { + if (!textVertexShader) { + textVertexShader = new QGLShader(QGLShader::VertexShader, ctx); + textVertexShader->addSource(QLatin1String(qglslImageVertexShader)); + if (!textVertexShader->compile()) + qWarning() << "Text vertex shader failed to compile:" << textVertexShader->log(); + } + + if (!textFragmentShader) { + textFragmentShader = new QGLShader(QGLShader::FragmentShader, ctx); + textFragmentShader->addSource(QLatin1String(qglslTextFragmentShader)); + if (!textFragmentShader->compile()) + qWarning() << "Text fragment shader failed to compile:" << textFragmentShader->log(); + } + + textShaderProgram = new QGLShaderProgram(ctx); + textShaderProgram->addShader(textVertexShader); + textShaderProgram->addShader(textFragmentShader); + if (!textShaderProgram->link()) + qWarning() << "Text shader program failed to link:" << textShaderProgram->log(); + } + + return textShaderProgram; +} + |