source: trunk/src/opengl/gl2paintengineex/qglengineshadermanager_p.h@ 890

Last change on this file since 890 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 19.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//
43// W A R N I N G
44// -------------
45//
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.
49//
50// We mean it.
51//
52
53/*
54 VERTEX SHADERS
55 ==============
56
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.
62
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).
71
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 separate 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.
79
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.
88
89 So there are the following "main" vertex shaders:
90 qglslMainVertexShader
91 qglslMainWithTexCoordsVertexShader
92
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
105
106 Leading to 23 possible vertex shaders
107
108
109 FRAGMENT SHADERS
110 ================
111
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
118 by GL).
119
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.
126
127 As eash stage can have multiple implementations, they are abstracted as
128 GLSL function calls with the following signatures:
129
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
142
143 Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
144 qglslMaskFragmentShader
145 qglslRgbMaskFragmentShaderPass1
146 qglslRgbMaskFragmentShaderPass2
147 qglslRgbMaskWithGammaFragmentShader
148
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
161
162
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
166 the implementation.
167
168 So there are differnt frament shader main functions, depending on the
169 number & type of pipelines the fragment needs to go through.
170
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
176
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();
186
187 Called:
188 qglslMainFragmentShader_CMO
189 qglslMainFragmentShader_CM
190 qglslMainFragmentShader_MO
191 qglslMainFragmentShader_M
192 qglslMainFragmentShader_CO
193 qglslMainFragmentShader_C
194 qglslMainFragmentShader_O
195 qglslMainFragmentShader
196
197 Where:
198 M = Mask
199 C = Composition
200 O = Global Opacity
201
202
203 CUSTOM SHADER CODE
204 ==================
205
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.
208
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:
212
213 lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords)
214
215 The provided src and srcCoords parameters can be used to sample from the
216 source image.
217
218 Transformations, clipping, opacity, and composition modes set using QPainter
219 will be respected when using the custom shader hook.
220*/
221
222#ifndef QGLENGINE_SHADER_MANAGER_H
223#define QGLENGINE_SHADER_MANAGER_H
224
225#include <QGLShader>
226#include <QGLShaderProgram>
227#include <QPainter>
228#include <private/qgl_p.h>
229#include <private/qglcustomshaderstage_p.h>
230
231QT_BEGIN_HEADER
232
233QT_BEGIN_NAMESPACE
234
235QT_MODULE(OpenGL)
236
237
238/*
239struct QGLEngineCachedShaderProg
240{
241 QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain,
242 QGLEngineShaderManager::ShaderName vertexPosition,
243 QGLEngineShaderManager::ShaderName fragMain,
244 QGLEngineShaderManager::ShaderName pixelSrc,
245 QGLEngineShaderManager::ShaderName mask,
246 QGLEngineShaderManager::ShaderName composition);
247
248 int cacheKey;
249 QGLShaderProgram* program;
250}
251*/
252
253static const GLuint QT_VERTEX_COORDS_ATTR = 0;
254static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
255static const GLuint QT_OPACITY_ATTR = 2;
256static const GLuint QT_PMV_MATRIX_1_ATTR = 3;
257static const GLuint QT_PMV_MATRIX_2_ATTR = 4;
258static const GLuint QT_PMV_MATRIX_3_ATTR = 5;
259
260class QGLEngineShaderProg;
261
262class QGLEngineSharedShaders : public QObject
263{
264 Q_OBJECT
265public:
266
267 enum SnippetName {
268 MainVertexShader,
269 MainWithTexCoordsVertexShader,
270 MainWithTexCoordsAndOpacityVertexShader,
271
272 // UntransformedPositionVertexShader must be first in the list:
273 UntransformedPositionVertexShader,
274 PositionOnlyVertexShader,
275 ComplexGeometryPositionOnlyVertexShader,
276 PositionWithPatternBrushVertexShader,
277 PositionWithLinearGradientBrushVertexShader,
278 PositionWithConicalGradientBrushVertexShader,
279 PositionWithRadialGradientBrushVertexShader,
280 PositionWithTextureBrushVertexShader,
281 AffinePositionWithPatternBrushVertexShader,
282 AffinePositionWithLinearGradientBrushVertexShader,
283 AffinePositionWithConicalGradientBrushVertexShader,
284 AffinePositionWithRadialGradientBrushVertexShader,
285 AffinePositionWithTextureBrushVertexShader,
286
287 // MainFragmentShader_CMO must be first in the list:
288 MainFragmentShader_CMO,
289 MainFragmentShader_CM,
290 MainFragmentShader_MO,
291 MainFragmentShader_M,
292 MainFragmentShader_CO,
293 MainFragmentShader_C,
294 MainFragmentShader_O,
295 MainFragmentShader,
296 MainFragmentShader_ImageArrays,
297
298 // ImageSrcFragmentShader must be first in the list::
299 ImageSrcFragmentShader,
300 ImageSrcWithPatternFragmentShader,
301 NonPremultipliedImageSrcFragmentShader,
302 CustomImageSrcFragmentShader,
303 SolidBrushSrcFragmentShader,
304 TextureBrushSrcFragmentShader,
305 TextureBrushSrcWithPatternFragmentShader,
306 PatternBrushSrcFragmentShader,
307 LinearGradientBrushSrcFragmentShader,
308 RadialGradientBrushSrcFragmentShader,
309 ConicalGradientBrushSrcFragmentShader,
310 ShockingPinkSrcFragmentShader,
311
312 // NoMaskFragmentShader must be first in the list:
313 NoMaskFragmentShader,
314 MaskFragmentShader,
315 RgbMaskFragmentShaderPass1,
316 RgbMaskFragmentShaderPass2,
317 RgbMaskWithGammaFragmentShader,
318
319 // NoCompositionModeFragmentShader must be first in the list:
320 NoCompositionModeFragmentShader,
321 MultiplyCompositionModeFragmentShader,
322 ScreenCompositionModeFragmentShader,
323 OverlayCompositionModeFragmentShader,
324 DarkenCompositionModeFragmentShader,
325 LightenCompositionModeFragmentShader,
326 ColorDodgeCompositionModeFragmentShader,
327 ColorBurnCompositionModeFragmentShader,
328 HardLightCompositionModeFragmentShader,
329 SoftLightCompositionModeFragmentShader,
330 DifferenceCompositionModeFragmentShader,
331 ExclusionCompositionModeFragmentShader,
332
333 TotalSnippetCount, InvalidSnippetName
334 };
335#if defined (QT_DEBUG)
336 Q_ENUMS(SnippetName)
337 static QByteArray snippetNameStr(SnippetName snippetName);
338#endif
339
340/*
341 // These allow the ShaderName enum to be used as a cache key
342 const int mainVertexOffset = 0;
343 const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
344 const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
345 const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
346 const int maskOffset = (1<<14) - NoMaskShader;
347 const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
348*/
349
350 QGLEngineSharedShaders(const QGLContext *context);
351 ~QGLEngineSharedShaders();
352
353 QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
354 QGLShaderProgram *blitProgram() { return blitShaderProg; }
355 // Compile the program if it's not already in the cache, return the item in the cache.
356 QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
357 // Compile the custom shader if it's not already in the cache, return the item in the cache.
358
359 static QGLEngineSharedShaders *shadersForContext(const QGLContext *context);
360
361 // Ideally, this would be static and cleanup all programs in all contexts which
362 // contain the custom code. Currently it is just a hint and we rely on deleted
363 // custom shaders being cleaned up by being kicked out of the cache when it's
364 // full.
365 void cleanupCustomStage(QGLCustomShaderStage* stage);
366
367signals:
368 void shaderProgNeedsChanging();
369
370private:
371 QGLSharedResourceGuard ctxGuard;
372 QGLShaderProgram *blitShaderProg;
373 QGLShaderProgram *simpleShaderProg;
374 QList<QGLEngineShaderProg*> cachedPrograms;
375
376 static const char* qShaderSnippets[TotalSnippetCount];
377};
378
379
380class QGLEngineShaderProg
381{
382public:
383 QGLEngineShaderProg() : program(0) {}
384
385 ~QGLEngineShaderProg() {
386 if (program)
387 delete program;
388 }
389
390 QGLEngineSharedShaders::SnippetName mainVertexShader;
391 QGLEngineSharedShaders::SnippetName positionVertexShader;
392 QGLEngineSharedShaders::SnippetName mainFragShader;
393 QGLEngineSharedShaders::SnippetName srcPixelFragShader;
394 QGLEngineSharedShaders::SnippetName maskFragShader;
395 QGLEngineSharedShaders::SnippetName compositionFragShader;
396
397 QByteArray customStageSource; //TODO: Decent cache key for custom stages
398 QGLShaderProgram* program;
399
400 QVector<uint> uniformLocations;
401
402 bool useTextureCoords;
403 bool useOpacityAttribute;
404 bool usePmvMatrixAttribute;
405
406 bool operator==(const QGLEngineShaderProg& other) {
407 // We don't care about the program
408 return ( mainVertexShader == other.mainVertexShader &&
409 positionVertexShader == other.positionVertexShader &&
410 mainFragShader == other.mainFragShader &&
411 srcPixelFragShader == other.srcPixelFragShader &&
412 maskFragShader == other.maskFragShader &&
413 compositionFragShader == other.compositionFragShader &&
414 customStageSource == other.customStageSource
415 );
416 }
417};
418
419class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
420{
421 Q_OBJECT
422public:
423 QGLEngineShaderManager(QGLContext* context);
424 ~QGLEngineShaderManager();
425
426 enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
427 enum PixelSrcType {
428 ImageSrc = Qt::TexturePattern+1,
429 NonPremultipliedImageSrc = Qt::TexturePattern+2,
430 PatternSrc = Qt::TexturePattern+3,
431 TextureSrcWithPattern = Qt::TexturePattern+4
432 };
433
434 enum Uniform {
435 ImageTexture,
436 PatternColor,
437 GlobalOpacity,
438 Depth,
439 MaskTexture,
440 FragmentColor,
441 LinearData,
442 Angle,
443 HalfViewportSize,
444 Fmp,
445 Fmp2MRadius2,
446 Inverse2Fmp2MRadius2,
447 InvertedTextureSize,
448 BrushTransform,
449 BrushTexture,
450 Matrix,
451 NumUniforms
452 };
453
454 enum OpacityMode {
455 NoOpacity,
456 UniformOpacity,
457 AttributeOpacity
458 };
459
460 // There are optimizations we can do, depending on the brush transform:
461 // 1) May not have to apply perspective-correction
462 // 2) Can use lower precision for matrix
463 void optimiseForBrushTransform(QTransform::TransformationType transformType);
464 void setSrcPixelType(Qt::BrushStyle);
465 void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
466 void setOpacityMode(OpacityMode);
467 void setMaskType(MaskType);
468 void setCompositionMode(QPainter::CompositionMode);
469 void setCustomStage(QGLCustomShaderStage* stage);
470 void removeCustomStage();
471
472 GLuint getUniformLocation(Uniform id);
473
474 void setDirty(); // someone has manually changed the current shader program
475 bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
476
477 void useSimpleProgram();
478 void useBlitProgram();
479 void setHasComplexGeometry(bool hasComplexGeometry)
480 {
481 complexGeometry = hasComplexGeometry;
482 shaderProgNeedsChanging = true;
483 }
484 bool hasComplexGeometry() const
485 {
486 return complexGeometry;
487 }
488
489 QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
490 QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
491 QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
492
493 QGLEngineSharedShaders* sharedShaders;
494
495private slots:
496 void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
497
498private:
499 QGLContext* ctx;
500 bool shaderProgNeedsChanging;
501 bool complexGeometry;
502
503 // Current state variables which influence the choice of shader:
504 QTransform brushTransform;
505 int srcPixelType;
506 OpacityMode opacityMode;
507 MaskType maskType;
508 QPainter::CompositionMode compositionMode;
509 QGLCustomShaderStage* customSrcStage;
510
511 QGLEngineShaderProg* currentShaderProg;
512};
513
514QT_END_NAMESPACE
515
516QT_END_HEADER
517
518#endif //QGLENGINE_SHADER_MANAGER_H
Note: See TracBrowser for help on using the repository browser.