1
/****************************************************************************
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the QtOpenGL module of the Qt Toolkit.
9
** $QT_BEGIN_LICENSE:LGPL$
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
16
** GNU Lesser General Public License Usage
17
** Alternatively, this file may be used under the terms of the GNU Lesser
18
** General Public License version 2.1 as published by the Free Software
19
** Foundation and appearing in the file LICENSE.LGPL included in the
20
** packaging of this file. Please review the following information to
21
** ensure the GNU Lesser General Public License version 2.1 requirements
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
40
****************************************************************************/
46
// This file is not part of the Qt API. It exists purely as an
47
// implementation detail. This header file may change from version to
48
// version without notice, or even be removed.
57
Vertex shaders are specified as multiple (partial) shaders. On desktop,
58
this works fine. On ES, QGLShader & QGLShaderProgram will make partial
59
shaders work by concatenating the source in each QGLShader and compiling
60
it as a single shader. This is abstracted nicely by QGLShaderProgram and
61
the GL2 engine doesn't need to worry about it.
63
Generally, there's two vertex shader objects. The position shaders are
64
the ones which set gl_Position. There's also two "main" vertex shaders,
65
one which just calls the position shader and another which also passes
66
through some texture coordinates from a vertex attribute array to a
67
varying. These texture coordinates are used for mask position in text
68
rendering and for the source coordinates in drawImage/drawPixmap. There's
69
also a "Simple" vertex shader for rendering a solid colour (used to render
70
into the stencil buffer where the actual colour value is discarded).
72
The position shaders for brushes look scary. This is because many of the
73
calculations which logically belong in the fragment shader have been moved
74
into the vertex shader to improve performance. This is why the position
75
calculation is in a seperate shader. Not only does it calculate the
76
position, but it also calculates some data to be passed to the fragment
77
shader as a varying. It is optimal to move as much of the calculation as
78
possible into the vertex shader as this is executed less often.
80
The varyings passed to the fragment shaders are interpolated (which is
81
cheap). Unfortunately, GL will apply perspective correction to the
82
interpolation calusing errors. To get around this, the vertex shader must
83
apply perspective correction itself and set the w-value of gl_Position to
84
zero. That way, GL will be tricked into thinking it doesn't need to apply a
85
perspective correction and use linear interpolation instead (which is what
86
we want). Of course, if the brush transform is affeine, no perspective
87
correction is needed and a simpler vertex shader can be used instead.
89
So there are the following "main" vertex shaders:
91
qglslMainWithTexCoordsVertexShader
93
And the the following position vertex shaders:
94
qglslPositionOnlyVertexShader
95
qglslPositionWithTextureBrushVertexShader
96
qglslPositionWithPatternBrushVertexShader
97
qglslPositionWithLinearGradientBrushVertexShader
98
qglslPositionWithRadialGradientBrushVertexShader
99
qglslPositionWithConicalGradientBrushVertexShader
100
qglslAffinePositionWithTextureBrushVertexShader
101
qglslAffinePositionWithPatternBrushVertexShader
102
qglslAffinePositionWithLinearGradientBrushVertexShader
103
qglslAffinePositionWithRadialGradientBrushVertexShader
104
qglslAffinePositionWithConicalGradientBrushVertexShader
106
Leading to 23 possible vertex shaders
112
Fragment shaders are also specified as multiple (partial) shaders. The
113
different fragment shaders represent the different stages in Qt's fragment
114
pipeline. There are 1-3 stages in this pipeline: First stage is to get the
115
fragment's colour value. The next stage is to get the fragment's mask value
116
(coverage value for anti-aliasing) and the final stage is to blend the
117
incoming fragment with the background (for composition modes not supported
120
Of these, the first stage will always be present. If Qt doesn't need to
121
apply anti-aliasing (because it's off or handled by multisampling) then
122
the coverage value doesn't need to be applied. (Note: There are two types
123
of mask, one for regular anti-aliasing and one for sub-pixel anti-
124
aliasing.) If the composition mode is one which GL supports natively then
125
the blending stage doesn't need to be applied.
127
As eash stage can have multiple implementations, they are abstracted as
128
GLSL function calls with the following signatures:
130
Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()":
131
qglslImageSrcFragShader
132
qglslImageSrcWithPatternFragShader
133
qglslNonPremultipliedImageSrcFragShader
134
qglslSolidBrushSrcFragShader
135
qglslTextureBrushSrcFragShader
136
qglslTextureBrushWithPatternFragShader
137
qglslPatternBrushSrcFragShader
138
qglslLinearGradientBrushSrcFragShader
139
qglslRadialGradientBrushSrcFragShader
140
qglslConicalGradientBrushSrcFragShader
141
NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied
143
Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
144
qglslMaskFragmentShader
145
qglslRgbMaskFragmentShaderPass1
146
qglslRgbMaskFragmentShaderPass2
147
qglslRgbMaskWithGammaFragmentShader
149
Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)":
150
qglslColorBurnCompositionModeFragmentShader
151
qglslColorDodgeCompositionModeFragmentShader
152
qglslDarkenCompositionModeFragmentShader
153
qglslDifferenceCompositionModeFragmentShader
154
qglslExclusionCompositionModeFragmentShader
155
qglslHardLightCompositionModeFragmentShader
156
qglslLightenCompositionModeFragmentShader
157
qglslMultiplyCompositionModeFragmentShader
158
qglslOverlayCompositionModeFragmentShader
159
qglslScreenCompositionModeFragmentShader
160
qglslSoftLightCompositionModeFragmentShader
163
Note: In the future, some GLSL compilers will support an extension allowing
164
a new 'color' precision specifier. To support this, qcolorp is used for
165
all color components so it can be defined to colorp or lowp depending upon
168
So there are differnt frament shader main functions, depending on the
169
number & type of pipelines the fragment needs to go through.
171
The choice of which main() fragment shader string to use depends on:
172
- Use of global opacity
173
- Brush style (some brushes apply opacity themselves)
174
- Use & type of mask (TODO: Need to support high quality anti-aliasing & text)
175
- Use of non-GL Composition mode
177
Leading to the following fragment shader main functions:
178
gl_FragColor = compose(applyMask(srcPixel()*globalOpacity));
179
gl_FragColor = compose(applyMask(srcPixel()));
180
gl_FragColor = applyMask(srcPixel()*globalOpacity);
181
gl_FragColor = applyMask(srcPixel());
182
gl_FragColor = compose(srcPixel()*globalOpacity);
183
gl_FragColor = compose(srcPixel());
184
gl_FragColor = srcPixel()*globalOpacity;
185
gl_FragColor = srcPixel();
188
qglslMainFragmentShader_CMO
189
qglslMainFragmentShader_CM
190
qglslMainFragmentShader_MO
191
qglslMainFragmentShader_M
192
qglslMainFragmentShader_CO
193
qglslMainFragmentShader_C
194
qglslMainFragmentShader_O
195
qglslMainFragmentShader
206
The use of custom shader code is supported by the engine for drawImage and
207
drawPixmap calls. This is implemented via hooks in the fragment pipeline.
209
The custom shader is passed to the engine as a partial fragment shader
210
(QGLCustomShaderStage). The shader will implement a pre-defined method name
211
which Qt's fragment pipeline will call:
213
lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords)
215
The provided src and srcCoords parameters can be used to sample from the
218
Transformations, clipping, opacity, and composition modes set using QPainter
219
will be respected when using the custom shader hook.
222
#ifndef QGLENGINE_SHADER_MANAGER_H
223
#define QGLENGINE_SHADER_MANAGER_H
226
#include <QGLShaderProgram>
228
#include <private/qgl_p.h>
229
#include <private/qglcustomshaderstage_p.h>
237
struct QGLEngineShaderProg
239
QGLShader* mainVertexShader;
240
QGLShader* positionVertexShader;
241
QGLShader* mainFragShader;
242
QGLShader* srcPixelFragShader;
243
QGLShader* maskFragShader; // Can be null for no mask
244
QGLShader* compositionFragShader; // Can be null for GL-handled mode
245
QGLShaderProgram* program;
247
QVector<uint> uniformLocations;
249
bool useTextureCoords;
250
bool useOpacityAttribute;
252
bool operator==(const QGLEngineShaderProg& other) {
253
// We don't care about the program
254
return ( mainVertexShader == other.mainVertexShader &&
255
positionVertexShader == other.positionVertexShader &&
256
mainFragShader == other.mainFragShader &&
257
srcPixelFragShader == other.srcPixelFragShader &&
258
maskFragShader == other.maskFragShader &&
259
compositionFragShader == other.compositionFragShader
265
struct QGLEngineCachedShaderProg
267
QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain,
268
QGLEngineShaderManager::ShaderName vertexPosition,
269
QGLEngineShaderManager::ShaderName fragMain,
270
QGLEngineShaderManager::ShaderName pixelSrc,
271
QGLEngineShaderManager::ShaderName mask,
272
QGLEngineShaderManager::ShaderName composition);
275
QGLShaderProgram* program;
279
static const GLuint QT_VERTEX_COORDS_ATTR = 0;
280
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
281
static const GLuint QT_OPACITY_ATTR = 2;
283
class QGLEngineSharedShaders : public QObject
289
MainWithTexCoordsVertexShader,
290
MainWithTexCoordsAndOpacityVertexShader,
292
UntransformedPositionVertexShader,
293
PositionOnlyVertexShader,
294
PositionWithPatternBrushVertexShader,
295
PositionWithLinearGradientBrushVertexShader,
296
PositionWithConicalGradientBrushVertexShader,
297
PositionWithRadialGradientBrushVertexShader,
298
PositionWithTextureBrushVertexShader,
299
AffinePositionWithPatternBrushVertexShader,
300
AffinePositionWithLinearGradientBrushVertexShader,
301
AffinePositionWithConicalGradientBrushVertexShader,
302
AffinePositionWithRadialGradientBrushVertexShader,
303
AffinePositionWithTextureBrushVertexShader,
305
MainFragmentShader_CMO,
306
MainFragmentShader_CM,
307
MainFragmentShader_MO,
308
MainFragmentShader_M,
309
MainFragmentShader_CO,
310
MainFragmentShader_C,
311
MainFragmentShader_O,
313
MainFragmentShader_ImageArrays,
315
ImageSrcFragmentShader,
316
ImageSrcWithPatternFragmentShader,
317
NonPremultipliedImageSrcFragmentShader,
318
CustomImageSrcFragmentShader,
319
SolidBrushSrcFragmentShader,
320
TextureBrushSrcFragmentShader,
321
TextureBrushSrcWithPatternFragmentShader,
322
PatternBrushSrcFragmentShader,
323
LinearGradientBrushSrcFragmentShader,
324
RadialGradientBrushSrcFragmentShader,
325
ConicalGradientBrushSrcFragmentShader,
326
ShockingPinkSrcFragmentShader,
329
RgbMaskFragmentShaderPass1,
330
RgbMaskFragmentShaderPass2,
331
RgbMaskWithGammaFragmentShader,
333
MultiplyCompositionModeFragmentShader,
334
ScreenCompositionModeFragmentShader,
335
OverlayCompositionModeFragmentShader,
336
DarkenCompositionModeFragmentShader,
337
LightenCompositionModeFragmentShader,
338
ColorDodgeCompositionModeFragmentShader,
339
ColorBurnCompositionModeFragmentShader,
340
HardLightCompositionModeFragmentShader,
341
SoftLightCompositionModeFragmentShader,
342
DifferenceCompositionModeFragmentShader,
343
ExclusionCompositionModeFragmentShader,
345
TotalShaderCount, InvalidShaderName
348
QGLEngineSharedShaders(const QGLContext *context);
350
QGLShader *compileNamedShader(ShaderName name, QGLShader::ShaderType type);
352
QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
353
QGLShaderProgram *blitProgram() { return blitShaderProg; }
354
// Compile the program if it's not already in the cache, return the item in the cache.
355
QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
356
// Compile the custom shader if it's not already in the cache, return the item in the cache.
357
QGLShader *compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type);
359
static QGLEngineSharedShaders *shadersForContext(const QGLContext *context);
362
void shaderProgNeedsChanging();
365
void shaderDestroyed(QObject *shader);
368
QGLSharedResourceGuard ctxGuard;
369
QGLShaderProgram *blitShaderProg;
370
QGLShaderProgram *simpleShaderProg;
371
QList<QGLEngineShaderProg> cachedPrograms;
372
QCache<QByteArray, QGLShader> customShaderCache;
373
QGLShader* compiledShaders[TotalShaderCount];
375
static const char* qglEngineShaderSourceCode[TotalShaderCount];
378
class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
382
QGLEngineShaderManager(QGLContext* context);
383
~QGLEngineShaderManager();
385
enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
387
ImageSrc = Qt::TexturePattern+1,
388
NonPremultipliedImageSrc = Qt::TexturePattern+2,
389
PatternSrc = Qt::TexturePattern+3,
390
TextureSrcWithPattern = Qt::TexturePattern+4
406
Inverse2Fmp2MRadius2,
419
// There are optimisations we can do, depending on the brush transform:
420
// 1) May not have to apply perspective-correction
421
// 2) Can use lower precision for matrix
422
void optimiseForBrushTransform(const QTransform &transform);
423
void setSrcPixelType(Qt::BrushStyle);
424
void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
425
void setOpacityMode(OpacityMode);
426
void setMaskType(MaskType);
427
void setCompositionMode(QPainter::CompositionMode);
428
void setCustomStage(QGLCustomShaderStage* stage);
429
void removeCustomStage(QGLCustomShaderStage* stage);
431
uint getUniformLocation(Uniform id);
433
void setDirty(); // someone has manually changed the current shader program
434
bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
436
QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
437
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
438
QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
441
// These allow the ShaderName enum to be used as a cache key
442
const int mainVertexOffset = 0;
443
const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
444
const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
445
const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
446
const int maskOffset = (1<<14) - NoMaskShader;
447
const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
450
#if defined (QT_DEBUG)
455
void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
459
bool shaderProgNeedsChanging;
461
// Current state variables which influence the choice of shader:
462
QTransform brushTransform;
464
OpacityMode opacityMode;
466
QPainter::CompositionMode compositionMode;
467
QGLCustomShaderStage* customSrcStage;
469
QGLEngineShaderProg* currentShaderProg;
470
QGLEngineSharedShaders *sharedShaders;
471
QGLShader *customShader;
478
#endif //QGLENGINE_SHADER_MANAGER_H