diff options
author | Tom Cooksey <thomas.cooksey@nokia.com> | 2009-04-15 11:33:25 (GMT) |
---|---|---|
committer | Tom Cooksey <thomas.cooksey@nokia.com> | 2009-04-16 14:19:02 (GMT) |
commit | adf67f5ab53758f9661b65a940ec34b4d4db6390 (patch) | |
tree | fb971f1a52a26469e34e9c394ab92260b677859e /src/opengl/gl2paintengineex | |
parent | 2485575f1883fe990d0072eed2231a5bd06948af (diff) | |
download | Qt-adf67f5ab53758f9661b65a940ec34b4d4db6390.zip Qt-adf67f5ab53758f9661b65a940ec34b4d4db6390.tar.gz Qt-adf67f5ab53758f9661b65a940ec34b4d4db6390.tar.bz2 |
Re-write the shader manager & completely break everything ;-)
Diffstat (limited to 'src/opengl/gl2paintengineex')
-rw-r--r-- | src/opengl/gl2paintengineex/glgc_shader_source.h | 137 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager.cpp | 367 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager_p.h | 385 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglpexshadermanager.cpp | 450 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglpexshadermanager_p.h | 156 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 4 |
6 files changed, 754 insertions, 745 deletions
diff --git a/src/opengl/gl2paintengineex/glgc_shader_source.h b/src/opengl/gl2paintengineex/glgc_shader_source.h index 47a1cbb..5184c78 100644 --- a/src/opengl/gl2paintengineex/glgc_shader_source.h +++ b/src/opengl/gl2paintengineex/glgc_shader_source.h @@ -49,143 +49,6 @@ QT_BEGIN_NAMESPACE QT_MODULE(OpenGL) -/* - VERTEX SHADERS - ============== - - Vertex shaders are specified as multiple (partial) shaders. On desktop, - this works fine. On ES, QGLShader & QGLShaderProgram will make partial - shaders work by concatenating the source in each QGLShader and compiling - it as a single shader. This is abstracted nicely by QGLShaderProgram and - the GL2 engine doesn't need to worry about it. - - Generally, there's two vertex shader objects. The position shaders are - the ones which set gl_Position. There's also two "main" vertex shaders, - one which just calls the position shader and another which also passes - through some texture coordinates from a vertex attribute array to a - varying. These texture coordinates are used for mask position in text - rendering and for the source coordinates in drawImage/drawPixmap. There's - also a "Simple" vertex shader for rendering a solid colour (used to render - into the stencil buffer where the actual colour value is discarded). - - The position shaders for brushes look scary. This is because many of the - calculations which logically belong in the fragment shader have been moved - into the vertex shader to improve performance. This is why the position - calculation is in a seperate shader. Not only does it calculate the - position, but it also calculates some data to be passed to the fragment - shader as a varying. It is optimal to move as much of the calculation as - possible into the vertex shader as this is executed less often. - - The varyings passed to the fragment shaders are interpolated (which is - cheap). Unfortunately, GL will apply perspective correction to the - interpolation calusing errors. To get around this, the vertex shader must - apply perspective correction itself and set the w-value of gl_Position to - zero. That way, GL will be tricked into thinking it doesn't need to apply a - perspective correction and use linear interpolation instead (which is what - we want). Of course, if the brush transform is affeine, no perspective - correction is needed and a simpler vertex shader can be used instead. - - So there are the following "main" vertex shaders: - qglslSimpleVertexShader - qglslMainVertexShader - qglslMainWithTexCoordsVertexShader - - And the the following position vertex shaders: - qglslPositionOnlyVertexShader - qglslPositionWithTextureBrushVertexShader - qglslPositionWithPatternBrushVertexShader - qglslPositionWithLinearGradientBrushVertexShader - qglslPositionWithRadialGradientBrushVertexShader - qglslPositionWithConicalGradientBrushVertexShader - qglslAffinePositionWithTextureBrushVertexShader - qglslAffinePositionWithPatternBrushVertexShader - qglslAffinePositionWithLinearGradientBrushVertexShader - qglslAffinePositionWithRadialGradientBrushVertexShader - qglslAffinePositionWithConicalGradientBrushVertexShader - - Leading to 23 possible vertex shaders - - - FRAGMENT SHADERS - ================ - - Fragment shaders are also specified as multiple (partial) shaders. The - different fragment shaders represent the different stages in Qt's fragment - pipeline. There are 1-3 stages in this pipeline: First stage is to get the - fragment's colour value. The next stage is to get the fragment's mask value - (coverage value for anti-aliasing) and the final stage is to blend the - incoming fragment with the background (for composition modes not supported - by GL). - - Of these, the first stage will always be present. If Qt doesn't need to - apply anti-aliasing (because it's off or handled by multisampling) then - the coverage value doesn't need to be applied. (Note: There are two types - of mask, one for regular anti-aliasing and one for sub-pixel anti- - aliasing.) If the composition mode is one which GL supports natively then - the blending stage doesn't need to be applied. - - As eash stage can have multiple implementations, they are abstracted as - GLSL function calls, with the following signatures: - - Brushes & image drawing are implementations of "mediump vec4 srcPixel()": - qglslImageFragmentShader - qglslNonPremultipliedImageFragmentShader - qglslSolidBrushFragmentShader - qglslTextureBrushFragmentShader - qglslPatternBrushFragmentShader - qglslLinearGradientBrushFragmentShader - qglslRadialGradientBrushFragmentShader - qglslConicalGradientBrushFragmentShader - - NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied - - The two masks are have these signature and are called: - qglslMaskFragmentShader: "mediump float mask()" - qglslRgbMaskFragmentShader: "mediump vec3 rgbMask()" - - Composition modes are "mediump vec4 composite(mediump vec4 src, mediump vec4 dest)": - qglslColorBurnCompositionModeFragmentShader - qglslColorDodgeCompositionModeFragmentShader - qglslDarkenCompositionModeFragmentShader - qglslDifferenceCompositionModeFragmentShader - qglslExclusionCompositionModeFragmentShader - qglslHardLightCompositionModeFragmentShader - qglslLightenCompositionModeFragmentShader - qglslMultiplyCompositionModeFragmentShader - qglslOverlayCompositionModeFragmentShader - qglslScreenCompositionModeFragmentShader - qglslSoftLightCompositionModeFragmentShader - - - So there are differnt frament shader main functions, depending on the - number & type of pipelines the fragment needs to go through. - - The choice of which main() fragment shader string to use depends on: - - Use of global opacity - - Brush style (some brushes apply opacity themselves) - - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) - - Use of gamma-correction - - Use of non-GL Composition mode - - - CUSTOM SHADER CODE (idea) - ================== - - The use of custom shader code is supported by the engine for drawImage and - drawPixmap calls. This is implemented via hooks in the fragment pipeline. - The custom shader is passed to the engine as a partial fragment shader - (QGLCustomizedShader). The shader will implement a pre-defined method name - which Qt's fragment pipeline will call. There are two different hooks which - can be implemented as custom shader code: - - mediump vec4 customShader(sampler2d src, vec2 srcCoords) - mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords) - -*/ - -///////////////////////////////////////////////////////////////////// - - static const char* qglslImageVertexShader = "\ attribute highp vec4 inputVertex; \ attribute lowp vec2 textureCoord; \ diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp new file mode 100644 index 0000000..1086430 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** 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 "qglengineshadermanager_p.h" + +#if defined(QT_DEBUG) +#include <QMetaEnum> +#endif + + +QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) + : ctx(context), + shaderProgNeedsChanging(true), + srcPixelType(Qt::NoBrush), + useGlobalOpacity(false), + maskType(NoMask), + useTextureCoords(false), + compositionMode(QPainter::CompositionMode_SourceOver), + simpleShaderProg(0), + currentShaderProg(0) +{ + memset(compiledShaders, 0, sizeof(compiledShaders)); +} + +QGLEngineShaderManager::~QGLEngineShaderManager() +{ + //### +} + + + + + +void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform transform) +{ + Q_UNUSED(transform); // Currently ignored +} + +void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) +{ + srcPixelType = style; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type) +{ + srcPixelType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setTextureCoordsEnabled(bool enabled) +{ + useTextureCoords = enabled; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setUseGlobalOpacity(bool useOpacity) +{ + useGlobalOpacity = useOpacity; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setMaskType(MaskType type) +{ + maskType = type; + shaderProgNeedsChanging = true; //### +} + +void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) +{ + compositionMode = mode; + shaderProgNeedsChanging = true; //### +} + +bool QGLEngineShaderManager::shaderProgramDirty() +{ + return shaderProgNeedsChanging; +} + +QGLShaderProgram* QGLEngineShaderManager::currentProgram() +{ + return currentShaderProg; +} + +QGLShaderProgram* QGLEngineShaderManager::simpleProgram() +{ + return simpleShaderProg; +} + + + + +// Select & use the correct shader program using the current state +void QGLEngineShaderManager::useCorrectShaderProg() +{ + QGLEngineShaderProg requiredProgram; + + // Choose vertex shader main function + QGLEngineShaderManager::ShaderName mainVertexShaderName = InvalidShaderName; + if (useTextureCoords) + mainVertexShaderName = MainWithTexCoordsVertexShader; + else + mainVertexShaderName = MainVertexShader; + compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); + requiredProgram.mainVertexShader = compiledShaders[mainVertexShaderName]; + + // Choose vertex shader shader position function (which typically also sets + // varyings) and the source pixel (srcPixel) fragment shader function: + QGLEngineShaderManager::ShaderName positionVertexShaderName = InvalidShaderName; + QGLEngineShaderManager::ShaderName srcPixelFragShaderName = InvalidShaderName; + bool isAffine = transform.isAffine(); + if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { + if (isAffine) + positionVertexShaderName = AffinePositionWithPatternBrushVertexShader; + else + positionVertexShaderName = PositionWithPatternBrushVertexShader; + + srcPixelFragShaderName = PatternBrushSrcFragmentShader; + } + else switch (srcPixelType) { + default: + case Qt::NoBrush: + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set"); + break; + case QGLEngineShaderManager::ImageSrc: + srcPixelFragShaderName = ImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case QGLEngineShaderManager::NonPremultipliedImageSrc: + srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::SolidPattern: + srcPixelFragShaderName = SolidBrushSrcFragmentShader; + positionVertexShaderName = PositionOnlyVertexShader; + break; + case Qt::LinearGradientPattern: + srcPixelFragShaderName = LinearGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithLinearGradientBrushVertexShader + : PositionWithLinearGradientBrushVertexShader; + break; + case Qt::ConicalGradientPattern: + srcPixelFragShaderName = ConicalGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithConicalGradientBrushVertexShader + : PositionWithConicalGradientBrushVertexShader; + break; + case Qt::RadialGradientPattern: + srcPixelFragShaderName = RadialGradientBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithRadialGradientBrushVertexShader + : PositionWithRadialGradientBrushVertexShader; + break; + case Qt::TexturePattern: + srcPixelFragShaderName = TextureBrushSrcFragmentShader; + positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader + : PositionWithTextureBrushVertexShader; + break; + }; + compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader); + compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName]; + requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName]; + + + const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; + const bool hasMask = maskType != QGLEngineShaderManager::NoMask; + + // Choose fragment shader main function: + QGLEngineShaderManager::ShaderName mainFragShaderName; + + if (hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CMO; + if (hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CM; + if (!hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_MO; + if (!hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_M; + if (hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_CO; + if (hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader_C; + if (!hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = MainFragmentShader_O; + if (!hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = MainFragmentShader; + + compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); + requiredProgram.mainFragShader = compiledShaders[mainFragShaderName]; + + if (hasMask) { + QGLEngineShaderManager::ShaderName maskShaderName = QGLEngineShaderManager::InvalidShaderName; + if (maskType == PixelMask) + maskShaderName = MaskFragmentShader; + else if (maskType == SubPixelMask) + maskShaderName = RgbMaskFragmentShader; + else if (maskType == SubPixelWithGammaMask) + maskShaderName = RgbMaskWithGammaFragmentShader; + else + qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); + + compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader); + requiredProgram.maskFragShader = compiledShaders[maskShaderName]; + } + else + requiredProgram.maskFragShader = 0; + + if (hasCompose) { + QGLEngineShaderManager::ShaderName compositionShaderName = QGLEngineShaderManager::InvalidShaderName; + switch (compositionMode) { + case QPainter::CompositionMode_Multiply: + compositionShaderName = MultiplyCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Screen: + compositionShaderName = ScreenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Overlay: + compositionShaderName = OverlayCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Darken: + compositionShaderName = DarkenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Lighten: + compositionShaderName = LightenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorDodge: + compositionShaderName = ColorDodgeCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorBurn: + compositionShaderName = ColorBurnCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_HardLight: + compositionShaderName = HardLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_SoftLight: + compositionShaderName = SoftLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Difference: + compositionShaderName = DifferenceCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Exclusion: + compositionShaderName = ExclusionCompositionModeFragmentShader; + break; + default: + qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); + } + compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader); + requiredProgram.compositionFragShader = compiledShaders[compositionShaderName]; + } + else + requiredProgram.compositionFragShader = 0; + + + // At this point, requiredProgram is fully populated so try to find the program in the cache + foreach (const QGLEngineShaderProg &prog, cachedPrograms) { + if ( (prog.mainVertexShader == requiredProgram.mainVertexShader) + && (prog.positionVertexShader == requiredProgram.positionVertexShader) + && (prog.mainFragShader == requiredProgram.mainFragShader) + && (prog.srcPixelFragShader == requiredProgram.srcPixelFragShader) + && (prog.compositionFragShader == requiredProgram.compositionFragShader) ) + { + currentShaderProg = requiredProgram.program; + currentShaderProg->enable(); + shaderProgNeedsChanging = false; + return; + } + } + +/* + 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; +*/ + // Shader program not found in cache, create it now. + requiredProgram.program = new QGLShaderProgram(ctx, this); + requiredProgram.program->addShader(requiredProgram.mainVertexShader); + requiredProgram.program->addShader(requiredProgram.positionVertexShader); + requiredProgram.program->addShader(requiredProgram.mainFragShader); + requiredProgram.program->addShader(requiredProgram.srcPixelFragShader); + requiredProgram.program->addShader(requiredProgram.maskFragShader); + requiredProgram.program->addShader(requiredProgram.compositionFragShader); + requiredProgram.program->link(); + if (!requiredProgram.program->isValid()) { + QString error; + qWarning() << "Shader program failed to link," +#if defined(QT_DEBUG) + << '\n' + << " Shaders Used:" << '\n' + << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n' + << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n' + << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n' + << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n' + << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n' + << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n' +#endif + << " Error Log:" << '\n' + << " " << requiredProgram.program->errors(); + qWarning() << error; + } + else { + cachedPrograms.append(requiredProgram); + currentShaderProg = requiredProgram.program; + currentShaderProg->enable(); + } + shaderProgNeedsChanging = false; +} + +void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type) +{ + if (compiledShaders[name]) + return; + + QGLShader *newShader = new QGLShader(type, ctx, this); + newShader->setSourceCode(qglEngineShaderSourceCode[name]); + // newShader->compile(); ### does not exist? + +#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; +} + + diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h new file mode 100644 index 0000000..fe30a70 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// +// 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. +// + +/* + VERTEX SHADERS + ============== + + Vertex shaders are specified as multiple (partial) shaders. On desktop, + this works fine. On ES, QGLShader & QGLShaderProgram will make partial + shaders work by concatenating the source in each QGLShader and compiling + it as a single shader. This is abstracted nicely by QGLShaderProgram and + the GL2 engine doesn't need to worry about it. + + Generally, there's two vertex shader objects. The position shaders are + the ones which set gl_Position. There's also two "main" vertex shaders, + one which just calls the position shader and another which also passes + through some texture coordinates from a vertex attribute array to a + varying. These texture coordinates are used for mask position in text + rendering and for the source coordinates in drawImage/drawPixmap. There's + also a "Simple" vertex shader for rendering a solid colour (used to render + into the stencil buffer where the actual colour value is discarded). + + The position shaders for brushes look scary. This is because many of the + calculations which logically belong in the fragment shader have been moved + into the vertex shader to improve performance. This is why the position + calculation is in a seperate shader. Not only does it calculate the + position, but it also calculates some data to be passed to the fragment + shader as a varying. It is optimal to move as much of the calculation as + possible into the vertex shader as this is executed less often. + + The varyings passed to the fragment shaders are interpolated (which is + cheap). Unfortunately, GL will apply perspective correction to the + interpolation calusing errors. To get around this, the vertex shader must + apply perspective correction itself and set the w-value of gl_Position to + zero. That way, GL will be tricked into thinking it doesn't need to apply a + perspective correction and use linear interpolation instead (which is what + we want). Of course, if the brush transform is affeine, no perspective + correction is needed and a simpler vertex shader can be used instead. + + So there are the following "main" vertex shaders: + qglslSimpleVertexShader + qglslMainVertexShader + qglslMainWithTexCoordsVertexShader + + And the the following position vertex shaders: + qglslPositionOnlyVertexShader + qglslPositionWithTextureBrushVertexShader + qglslPositionWithPatternBrushVertexShader + qglslPositionWithLinearGradientBrushVertexShader + qglslPositionWithRadialGradientBrushVertexShader + qglslPositionWithConicalGradientBrushVertexShader + qglslAffinePositionWithTextureBrushVertexShader + qglslAffinePositionWithPatternBrushVertexShader + qglslAffinePositionWithLinearGradientBrushVertexShader + qglslAffinePositionWithRadialGradientBrushVertexShader + qglslAffinePositionWithConicalGradientBrushVertexShader + + Leading to 23 possible vertex shaders + + + FRAGMENT SHADERS + ================ + + Fragment shaders are also specified as multiple (partial) shaders. The + different fragment shaders represent the different stages in Qt's fragment + pipeline. There are 1-3 stages in this pipeline: First stage is to get the + fragment's colour value. The next stage is to get the fragment's mask value + (coverage value for anti-aliasing) and the final stage is to blend the + incoming fragment with the background (for composition modes not supported + by GL). + + Of these, the first stage will always be present. If Qt doesn't need to + apply anti-aliasing (because it's off or handled by multisampling) then + the coverage value doesn't need to be applied. (Note: There are two types + of mask, one for regular anti-aliasing and one for sub-pixel anti- + aliasing.) If the composition mode is one which GL supports natively then + the blending stage doesn't need to be applied. + + As eash stage can have multiple implementations, they are abstracted as + GLSL function calls with the following signatures: + + Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()": + qglslImageSrcFragShader + qglslNonPremultipliedImageSrcFragShader + qglslSolidBrushSrcFragShader + qglslTextureBrushSrcFragShader + qglslPatternBrushSrcFragShader + qglslLinearGradientBrushSrcFragShader + qglslRadialGradientBrushSrcFragShader + qglslConicalGradientBrushSrcFragShader + NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied + + Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)": + qglslMaskFragmentShader + qglslRgbMaskFragmentShader + qglslRgbMaskWithGammaFragmentShader + + Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)": + qglslColorBurnCompositionModeFragmentShader + qglslColorDodgeCompositionModeFragmentShader + qglslDarkenCompositionModeFragmentShader + qglslDifferenceCompositionModeFragmentShader + qglslExclusionCompositionModeFragmentShader + qglslHardLightCompositionModeFragmentShader + qglslLightenCompositionModeFragmentShader + qglslMultiplyCompositionModeFragmentShader + qglslOverlayCompositionModeFragmentShader + qglslScreenCompositionModeFragmentShader + qglslSoftLightCompositionModeFragmentShader + + + Note: In the future, some GLSL compilers will support an extension allowing + a new 'color' precision specifier. To support this, qcolorp is used for + all color components so it can be defined to colorp or lowp depending upon + the implementation. + + So there are differnt frament shader main functions, depending on the + number & type of pipelines the fragment needs to go through. + + The choice of which main() fragment shader string to use depends on: + - Use of global opacity + - Brush style (some brushes apply opacity themselves) + - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) + - Use of non-GL Composition mode + + Leading to the following fragment shader main functions: + gl_FragColor = compose(applyMask(srcPixel()*globalOpacity)); + gl_FragColor = compose(applyMask(srcPixel())); + gl_FragColor = applyMask(srcPixel()*globalOpacity); + gl_FragColor = applyMask(srcPixel()); + gl_FragColor = compose(srcPixel()*globalOpacity); + gl_FragColor = compose(srcPixel()); + gl_FragColor = srcPixel()*globalOpacity; + gl_FragColor = srcPixel(); + + Called: + qglslMainFragmentShader_CMO + qglslMainFragmentShader_CM + qglslMainFragmentShader_MO + qglslMainFragmentShader_M + qglslMainFragmentShader_CO + qglslMainFragmentShader_C + qglslMainFragmentShader_O + qglslMainFragmentShader + + Where: + M = Mask + C = Composition + O = Global Opacity + + + CUSTOM SHADER CODE (idea, depricated) + ================== + + The use of custom shader code is supported by the engine for drawImage and + drawPixmap calls. This is implemented via hooks in the fragment pipeline. + The custom shader is passed to the engine as a partial fragment shader + (QGLCustomizedShader). The shader will implement a pre-defined method name + which Qt's fragment pipeline will call. There are two different hooks which + can be implemented as custom shader code: + + mediump vec4 customShader(sampler2d src, vec2 srcCoords) + mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords) + +*/ + +#ifndef QGLENGINE_SHADER_MANAGER_H +#define QGLENGINE_SHADER_MANAGER_H + +#include <QGLShader> +#include <QGLShaderProgram> +#include <QPainter> + +QT_BEGIN_HEADER + +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; +}; + +/* +struct QGLEngineCachedShaderProg +{ + QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain, + QGLEngineShaderManager::ShaderName vertexPosition, + QGLEngineShaderManager::ShaderName fragMain, + QGLEngineShaderManager::ShaderName pixelSrc, + QGLEngineShaderManager::ShaderName mask, + QGLEngineShaderManager::ShaderName composition); + + int cacheKey; + QGLShaderProgram* program; +} +*/ + +class QGLEngineShaderManager : public QObject +{ + Q_OBJECT; +public: + QGLEngineShaderManager(QGLContext* context); + ~QGLEngineShaderManager(); + + enum MaskType {NoMask, PixelMask, SubPixelMask, SubPixelWithGammaMask}; + enum PixelSrcType { + ImageSrc = Qt::TexturePattern+1, + NonPremultipliedImageSrc = Qt::TexturePattern+2 + }; + + // There are optimisations we can do, depending on the transform: + // 1) May not have to apply perspective-correction + // 2) Can use lower precision for vertecies + void optimiseForBrushTransform(const QTransform transform); + void setSrcPixelType(Qt::BrushStyle); + void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images + void setTextureCoordsEnabled(bool); // For images & text glyphs + void setUseGlobalOpacity(bool); + void setMaskType(MaskType); + void setCompositionMode(QPainter::CompositionMode); + + bool shaderProgramDirty(); // returns true if the shader program needs to be changed + void useCorrectShaderProg(); + + QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen + QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers + + enum ShaderName { + SimpleVertexShader, + MainVertexShader, + MainWithTexCoordsVertexShader, + + PositionOnlyVertexShader, + PositionWithPatternBrushVertexShader, + PositionWithLinearGradientBrushVertexShader, + PositionWithConicalGradientBrushVertexShader, + PositionWithRadialGradientBrushVertexShader, + PositionWithTextureBrushVertexShader, + AffinePositionWithPatternBrushVertexShader, + AffinePositionWithLinearGradientBrushVertexShader, + AffinePositionWithConicalGradientBrushVertexShader, + AffinePositionWithRadialGradientBrushVertexShader, + AffinePositionWithTextureBrushVertexShader, + + MainFragmentShader_CMO, + MainFragmentShader_CM, + MainFragmentShader_MO, + MainFragmentShader_M, + MainFragmentShader_CO, + MainFragmentShader_C, + MainFragmentShader_O, + MainFragmentShader, + + ImageSrcFragmentShader, + NonPremultipliedImageSrcFragmentShader, + SolidBrushSrcFragmentShader, + TextureBrushSrcFragmentShader, + PatternBrushSrcFragmentShader, + LinearGradientBrushSrcFragmentShader, + RadialGradientBrushSrcFragmentShader, + ConicalGradientBrushSrcFragmentShader, + + MaskFragmentShader, + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, + + TotalShaderCount, InvalidShaderName + }; + +/* + // 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); +#else +#error Release build not supported yet +#endif + + +private: + QGLContext* ctx; + bool shaderProgNeedsChanging; + + // Current state variables which influence the choice of shader: + QTransform transform; + int srcPixelType; + bool useGlobalOpacity; + MaskType maskType; + bool useTextureCoords; + QPainter::CompositionMode compositionMode; + + QGLShaderProgram* simpleShaderProg; + QGLShaderProgram* currentShaderProg; + + // TODO: Possibly convert to a LUT + QList<QGLEngineShaderProg> cachedPrograms; + + QGLShader* compiledShaders[TotalShaderCount]; + + void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QGLENGINE_SHADER_MANAGER_H diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp b/src/opengl/gl2paintengineex/qglpexshadermanager.cpp deleted file mode 100644 index e460e08..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/**************************************************************************** -** -** 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; -} - diff --git a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h b/src/opengl/gl2paintengineex/qglpexshadermanager_p.h deleted file mode 100644 index c8f47b2..0000000 --- a/src/opengl/gl2paintengineex/qglpexshadermanager_p.h +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -// -// 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. -// - -#include "qglshader_p.h" - - -// Worstcase combo: Brush->Mask->Composition - -/* - Vertex shader source is specified with a single string. This string - contains the main function and sets the gl_Position. The choice of - which vertex shader to use depends on: - - Brush style - - Brush transform->isAffine() - - Fragment shaders are specified as multiple strings, one for the main - function, one for the brush calculation and optionally one for the - extended composition mode. Brushes are implementations of - "mediump vec4 brush()" - Composition modes are implemented as a - "mediump vec4 compose(mediump vec4 color)" - NOTE: Precision may change in future. - - The choice of which main() fragment shader string to use depends on: - - Global opacity - - Brush style (some brushes apply opacity themselves) - - Use of mask (TODO: Need to support high quality anti-aliasing & text) - - Composition mode - - The choice of which brush() fragment shader to use depends on: - - Brush style - -*/ - - -struct QGLCachedShaderProg -{ - QGLShader* vertexShader; - QGLShader* brushShader; - QGLShader* compositionShader; - QGLShaderProgram* shader; -}; - -class QGLPEXShaderManager -{ -public: - QGLPEXShaderManager(const QGLContext* context); - ~QGLPEXShaderManager(); - - enum TransformType {IdentityTransform, ScaleTransform, TranslateTransform, FullTransform}; - - void optimiseForBrushTransform(const QTransform& transform); - void setBrushStyle(Qt::BrushStyle style); - void setUseGlobalOpacity(bool value); - void setAffineOnlyBrushTransform(bool value); // I.e. Do we need to apply perspective-correction? - // Not doing so saves some vertex shader calculations. - - bool useCorrectShaderProg(); // returns true if the shader program has changed - - QGLShaderProgram* brushShader(); - QGLShaderProgram* simpleShader(); // Used to draw into e.g. stencil buffers - QGLShaderProgram* imageShader(); - QGLShaderProgram* textShader(); - -private: - QGLShader* defaultVertexShader; - - QGLShader* imageVertexShader; - QGLShader* imageFragmentShader; - QGLShaderProgram* imageShaderProgram; - - QGLShader* textVertexShader; - QGLShader* textFragmentShader; - QGLShaderProgram* textShaderProgram; - - QGLShader* noBrushShader; - QGLShader* solidBrushShader; - - QGLShader* conicalBrushVertexShader; - QGLShader* conicalBrushFragmentShader; - - QGLShader* radialBrushVertexShader; - QGLShader* radialBrushFragmentShader; - - QGLShader* linearBrushVertexShader; - QGLShader* linearBrushFragmentShader; - - QGLShader* patternBrushVertexShader; - QGLShader* patternBrushFragmentShader; - - QGLShader* textureBrushFragmentShader; - QGLShader* textureBrushVertexShader; - - QGLShader* simpleFragmentShader; - QGLShaderProgram* simpleShaderProgram; - - QGLShaderProgram* activeProgram; - - Qt::BrushStyle currentBrushStyle; - bool useGlobalOpacity; - TransformType currentTransformType; - bool shaderProgNeedsChanging; - - QList<QGLCachedShaderProg> cachedPrograms; - - QGLContext* ctx; -}; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 89ed1f7..53ae4fb 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -77,7 +77,7 @@ #include <private/qtextureglyphcache_p.h> #include "qglgradientcache_p.h" -#include "qglpexshadermanager_p.h" +#include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" @@ -170,7 +170,7 @@ public: GLfloat pmvMatrix[4][4]; - QGLPEXShaderManager* shaderManager; + QGLEngineShaderManager* shaderManager; // Clipping & state stuff stolen from QOpenGLPaintEngine: void updateDepthClip(); |