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

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 19.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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 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.
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;
256
257class QGLEngineShaderProg;
258
259class QGLEngineSharedShaders : public QObject
260{
261 Q_OBJECT
262public:
263
264 enum SnippetName {
265 MainVertexShader,
266 MainWithTexCoordsVertexShader,
267 MainWithTexCoordsAndOpacityVertexShader,
268
269 // UntransformedPositionVertexShader must be first in the list:
270 UntransformedPositionVertexShader,
271 PositionOnlyVertexShader,
272 PositionWithPatternBrushVertexShader,
273 PositionWithLinearGradientBrushVertexShader,
274 PositionWithConicalGradientBrushVertexShader,
275 PositionWithRadialGradientBrushVertexShader,
276 PositionWithTextureBrushVertexShader,
277 AffinePositionWithPatternBrushVertexShader,
278 AffinePositionWithLinearGradientBrushVertexShader,
279 AffinePositionWithConicalGradientBrushVertexShader,
280 AffinePositionWithRadialGradientBrushVertexShader,
281 AffinePositionWithTextureBrushVertexShader,
282
283 // MainFragmentShader_CMO must be first in the list:
284 MainFragmentShader_CMO,
285 MainFragmentShader_CM,
286 MainFragmentShader_MO,
287 MainFragmentShader_M,
288 MainFragmentShader_CO,
289 MainFragmentShader_C,
290 MainFragmentShader_O,
291 MainFragmentShader,
292 MainFragmentShader_ImageArrays,
293
294 // ImageSrcFragmentShader must be first in the list::
295 ImageSrcFragmentShader,
296 ImageSrcWithPatternFragmentShader,
297 NonPremultipliedImageSrcFragmentShader,
298 CustomImageSrcFragmentShader,
299 SolidBrushSrcFragmentShader,
300 TextureBrushSrcFragmentShader,
301 TextureBrushSrcWithPatternFragmentShader,
302 PatternBrushSrcFragmentShader,
303 LinearGradientBrushSrcFragmentShader,
304 RadialGradientBrushSrcFragmentShader,
305 ConicalGradientBrushSrcFragmentShader,
306 ShockingPinkSrcFragmentShader,
307
308 // NoMaskFragmentShader must be first in the list:
309 NoMaskFragmentShader,
310 MaskFragmentShader,
311 RgbMaskFragmentShaderPass1,
312 RgbMaskFragmentShaderPass2,
313 RgbMaskWithGammaFragmentShader,
314
315 // NoCompositionModeFragmentShader must be first in the list:
316 NoCompositionModeFragmentShader,
317 MultiplyCompositionModeFragmentShader,
318 ScreenCompositionModeFragmentShader,
319 OverlayCompositionModeFragmentShader,
320 DarkenCompositionModeFragmentShader,
321 LightenCompositionModeFragmentShader,
322 ColorDodgeCompositionModeFragmentShader,
323 ColorBurnCompositionModeFragmentShader,
324 HardLightCompositionModeFragmentShader,
325 SoftLightCompositionModeFragmentShader,
326 DifferenceCompositionModeFragmentShader,
327 ExclusionCompositionModeFragmentShader,
328
329 TotalSnippetCount, InvalidSnippetName
330 };
331#if defined (QT_DEBUG)
332 Q_ENUMS(SnippetName)
333 static QByteArray snippetNameStr(SnippetName snippetName);
334#endif
335
336/*
337 // These allow the ShaderName enum to be used as a cache key
338 const int mainVertexOffset = 0;
339 const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
340 const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
341 const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
342 const int maskOffset = (1<<14) - NoMaskShader;
343 const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
344*/
345
346 QGLEngineSharedShaders(const QGLContext *context);
347
348 QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
349 QGLShaderProgram *blitProgram() { return blitShaderProg; }
350 // Compile the program if it's not already in the cache, return the item in the cache.
351 QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
352 // Compile the custom shader if it's not already in the cache, return the item in the cache.
353
354 static QGLEngineSharedShaders *shadersForContext(const QGLContext *context);
355
356 // Ideally, this would be static and cleanup all programs in all contexts which
357 // contain the custom code. Currently it is just a hint and we rely on deleted
358 // custom shaders being cleaned up by being kicked out of the cache when it's
359 // full.
360 void cleanupCustomStage(QGLCustomShaderStage* stage);
361
362signals:
363 void shaderProgNeedsChanging();
364
365private:
366 QGLSharedResourceGuard ctxGuard;
367 QGLShaderProgram *blitShaderProg;
368 QGLShaderProgram *simpleShaderProg;
369 QList<QGLEngineShaderProg*> cachedPrograms;
370
371 static const char* qShaderSnippets[TotalSnippetCount];
372};
373
374
375class QGLEngineShaderProg
376{
377public:
378 QGLEngineShaderProg() : program(0) {}
379
380 ~QGLEngineShaderProg() {
381 if (program)
382 delete program;
383 }
384
385 QGLEngineSharedShaders::SnippetName mainVertexShader;
386 QGLEngineSharedShaders::SnippetName positionVertexShader;
387 QGLEngineSharedShaders::SnippetName mainFragShader;
388 QGLEngineSharedShaders::SnippetName srcPixelFragShader;
389 QGLEngineSharedShaders::SnippetName maskFragShader;
390 QGLEngineSharedShaders::SnippetName compositionFragShader;
391
392 QByteArray customStageSource; //TODO: Decent cache key for custom stages
393 QGLShaderProgram* program;
394
395 QVector<uint> uniformLocations;
396
397 bool useTextureCoords;
398 bool useOpacityAttribute;
399
400 bool operator==(const QGLEngineShaderProg& other) {
401 // We don't care about the program
402 return ( mainVertexShader == other.mainVertexShader &&
403 positionVertexShader == other.positionVertexShader &&
404 mainFragShader == other.mainFragShader &&
405 srcPixelFragShader == other.srcPixelFragShader &&
406 maskFragShader == other.maskFragShader &&
407 compositionFragShader == other.compositionFragShader &&
408 customStageSource == other.customStageSource
409 );
410 }
411};
412
413class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
414{
415 Q_OBJECT
416public:
417 QGLEngineShaderManager(QGLContext* context);
418 ~QGLEngineShaderManager();
419
420 enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
421 enum PixelSrcType {
422 ImageSrc = Qt::TexturePattern+1,
423 NonPremultipliedImageSrc = Qt::TexturePattern+2,
424 PatternSrc = Qt::TexturePattern+3,
425 TextureSrcWithPattern = Qt::TexturePattern+4
426 };
427
428 enum Uniform {
429 ImageTexture,
430 PatternColor,
431 GlobalOpacity,
432 Depth,
433 PmvMatrix,
434 MaskTexture,
435 FragmentColor,
436 LinearData,
437 Angle,
438 HalfViewportSize,
439 Fmp,
440 Fmp2MRadius2,
441 Inverse2Fmp2MRadius2,
442 InvertedTextureSize,
443 BrushTransform,
444 BrushTexture,
445 NumUniforms
446 };
447
448 enum OpacityMode {
449 NoOpacity,
450 UniformOpacity,
451 AttributeOpacity
452 };
453
454 // There are optimisations we can do, depending on the brush transform:
455 // 1) May not have to apply perspective-correction
456 // 2) Can use lower precision for matrix
457 void optimiseForBrushTransform(const QTransform::TransformationType transformType);
458 void setSrcPixelType(Qt::BrushStyle);
459 void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
460 void setOpacityMode(OpacityMode);
461 void setMaskType(MaskType);
462 void setCompositionMode(QPainter::CompositionMode);
463 void setCustomStage(QGLCustomShaderStage* stage);
464 void removeCustomStage();
465
466 GLuint getUniformLocation(const Uniform id);
467
468 void setDirty(); // someone has manually changed the current shader program
469 bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
470
471 QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
472 QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
473 QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
474
475 QGLEngineSharedShaders* sharedShaders;
476
477private slots:
478 void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
479
480private:
481 QGLContext* ctx;
482 bool shaderProgNeedsChanging;
483
484 // Current state variables which influence the choice of shader:
485 QTransform brushTransform;
486 int srcPixelType;
487 OpacityMode opacityMode;
488 MaskType maskType;
489 QPainter::CompositionMode compositionMode;
490 QGLCustomShaderStage* customSrcStage;
491
492 QGLEngineShaderProg* currentShaderProg;
493};
494
495QT_END_NAMESPACE
496
497QT_END_HEADER
498
499#endif //QGLENGINE_SHADER_MANAGER_H
Note: See TracBrowser for help on using the repository browser.