|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtOpenGL module of the Qt Toolkit. |
|
8 ** |
|
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 |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |
|
231 QT_BEGIN_HEADER |
|
232 |
|
233 QT_BEGIN_NAMESPACE |
|
234 |
|
235 QT_MODULE(OpenGL) |
|
236 |
|
237 struct QGLEngineShaderProg |
|
238 { |
|
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; |
|
246 |
|
247 QVector<uint> uniformLocations; |
|
248 |
|
249 bool useTextureCoords; |
|
250 bool useOpacityAttribute; |
|
251 |
|
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 |
|
260 ); |
|
261 } |
|
262 }; |
|
263 |
|
264 /* |
|
265 struct QGLEngineCachedShaderProg |
|
266 { |
|
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); |
|
273 |
|
274 int cacheKey; |
|
275 QGLShaderProgram* program; |
|
276 } |
|
277 */ |
|
278 |
|
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; |
|
282 |
|
283 class QGLEngineSharedShaders : public QObject |
|
284 { |
|
285 Q_OBJECT |
|
286 public: |
|
287 enum ShaderName { |
|
288 MainVertexShader, |
|
289 MainWithTexCoordsVertexShader, |
|
290 MainWithTexCoordsAndOpacityVertexShader, |
|
291 |
|
292 UntransformedPositionVertexShader, |
|
293 PositionOnlyVertexShader, |
|
294 PositionWithPatternBrushVertexShader, |
|
295 PositionWithLinearGradientBrushVertexShader, |
|
296 PositionWithConicalGradientBrushVertexShader, |
|
297 PositionWithRadialGradientBrushVertexShader, |
|
298 PositionWithTextureBrushVertexShader, |
|
299 AffinePositionWithPatternBrushVertexShader, |
|
300 AffinePositionWithLinearGradientBrushVertexShader, |
|
301 AffinePositionWithConicalGradientBrushVertexShader, |
|
302 AffinePositionWithRadialGradientBrushVertexShader, |
|
303 AffinePositionWithTextureBrushVertexShader, |
|
304 |
|
305 MainFragmentShader_CMO, |
|
306 MainFragmentShader_CM, |
|
307 MainFragmentShader_MO, |
|
308 MainFragmentShader_M, |
|
309 MainFragmentShader_CO, |
|
310 MainFragmentShader_C, |
|
311 MainFragmentShader_O, |
|
312 MainFragmentShader, |
|
313 MainFragmentShader_ImageArrays, |
|
314 |
|
315 ImageSrcFragmentShader, |
|
316 ImageSrcWithPatternFragmentShader, |
|
317 NonPremultipliedImageSrcFragmentShader, |
|
318 CustomImageSrcFragmentShader, |
|
319 SolidBrushSrcFragmentShader, |
|
320 TextureBrushSrcFragmentShader, |
|
321 TextureBrushSrcWithPatternFragmentShader, |
|
322 PatternBrushSrcFragmentShader, |
|
323 LinearGradientBrushSrcFragmentShader, |
|
324 RadialGradientBrushSrcFragmentShader, |
|
325 ConicalGradientBrushSrcFragmentShader, |
|
326 ShockingPinkSrcFragmentShader, |
|
327 |
|
328 MaskFragmentShader, |
|
329 RgbMaskFragmentShaderPass1, |
|
330 RgbMaskFragmentShaderPass2, |
|
331 RgbMaskWithGammaFragmentShader, |
|
332 |
|
333 MultiplyCompositionModeFragmentShader, |
|
334 ScreenCompositionModeFragmentShader, |
|
335 OverlayCompositionModeFragmentShader, |
|
336 DarkenCompositionModeFragmentShader, |
|
337 LightenCompositionModeFragmentShader, |
|
338 ColorDodgeCompositionModeFragmentShader, |
|
339 ColorBurnCompositionModeFragmentShader, |
|
340 HardLightCompositionModeFragmentShader, |
|
341 SoftLightCompositionModeFragmentShader, |
|
342 DifferenceCompositionModeFragmentShader, |
|
343 ExclusionCompositionModeFragmentShader, |
|
344 |
|
345 TotalShaderCount, InvalidShaderName |
|
346 }; |
|
347 |
|
348 QGLEngineSharedShaders(const QGLContext *context); |
|
349 |
|
350 QGLShader *compileNamedShader(ShaderName name, QGLShader::ShaderType type); |
|
351 |
|
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); |
|
358 |
|
359 static QGLEngineSharedShaders *shadersForContext(const QGLContext *context); |
|
360 |
|
361 signals: |
|
362 void shaderProgNeedsChanging(); |
|
363 |
|
364 private slots: |
|
365 void shaderDestroyed(QObject *shader); |
|
366 |
|
367 private: |
|
368 QGLSharedResourceGuard ctxGuard; |
|
369 QGLShaderProgram *blitShaderProg; |
|
370 QGLShaderProgram *simpleShaderProg; |
|
371 QList<QGLEngineShaderProg> cachedPrograms; |
|
372 QCache<QByteArray, QGLShader> customShaderCache; |
|
373 QGLShader* compiledShaders[TotalShaderCount]; |
|
374 |
|
375 static const char* qglEngineShaderSourceCode[TotalShaderCount]; |
|
376 }; |
|
377 |
|
378 class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject |
|
379 { |
|
380 Q_OBJECT |
|
381 public: |
|
382 QGLEngineShaderManager(QGLContext* context); |
|
383 ~QGLEngineShaderManager(); |
|
384 |
|
385 enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask}; |
|
386 enum PixelSrcType { |
|
387 ImageSrc = Qt::TexturePattern+1, |
|
388 NonPremultipliedImageSrc = Qt::TexturePattern+2, |
|
389 PatternSrc = Qt::TexturePattern+3, |
|
390 TextureSrcWithPattern = Qt::TexturePattern+4 |
|
391 }; |
|
392 |
|
393 enum Uniform { |
|
394 ImageTexture, |
|
395 PatternColor, |
|
396 GlobalOpacity, |
|
397 Depth, |
|
398 PmvMatrix, |
|
399 MaskTexture, |
|
400 FragmentColor, |
|
401 LinearData, |
|
402 Angle, |
|
403 HalfViewportSize, |
|
404 Fmp, |
|
405 Fmp2MRadius2, |
|
406 Inverse2Fmp2MRadius2, |
|
407 InvertedTextureSize, |
|
408 BrushTransform, |
|
409 BrushTexture, |
|
410 NumUniforms |
|
411 }; |
|
412 |
|
413 enum OpacityMode { |
|
414 NoOpacity, |
|
415 UniformOpacity, |
|
416 AttributeOpacity |
|
417 }; |
|
418 |
|
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); |
|
430 |
|
431 uint getUniformLocation(Uniform id); |
|
432 |
|
433 void setDirty(); // someone has manually changed the current shader program |
|
434 bool useCorrectShaderProg(); // returns true if the shader program needed to be changed |
|
435 |
|
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 |
|
439 |
|
440 /* |
|
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; |
|
448 */ |
|
449 |
|
450 #if defined (QT_DEBUG) |
|
451 Q_ENUMS(ShaderName) |
|
452 #endif |
|
453 |
|
454 private slots: |
|
455 void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; } |
|
456 |
|
457 private: |
|
458 QGLContext* ctx; |
|
459 bool shaderProgNeedsChanging; |
|
460 |
|
461 // Current state variables which influence the choice of shader: |
|
462 QTransform brushTransform; |
|
463 int srcPixelType; |
|
464 OpacityMode opacityMode; |
|
465 MaskType maskType; |
|
466 QPainter::CompositionMode compositionMode; |
|
467 QGLCustomShaderStage* customSrcStage; |
|
468 |
|
469 QGLEngineShaderProg* currentShaderProg; |
|
470 QGLEngineSharedShaders *sharedShaders; |
|
471 QGLShader *customShader; |
|
472 }; |
|
473 |
|
474 QT_END_NAMESPACE |
|
475 |
|
476 QT_END_HEADER |
|
477 |
|
478 #endif //QGLENGINE_SHADER_MANAGER_H |