1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 //
41 //  W A R N I N G
42 //  -------------
43 //
44 // This file is not part of the Qt API.  It exists purely as an
45 // implementation detail.  This header file may change from version to
46 // version without notice, or even be removed.
47 //
48 // We mean it.
49 //
50 
51 /*
52     VERTEX SHADERS
53     ==============
54 
55     Vertex shaders are specified as multiple (partial) shaders. On desktop,
56     this works fine. On ES, QGLShader & QGLShaderProgram will make partial
57     shaders work by concatenating the source in each QGLShader and compiling
58     it as a single shader. This is abstracted nicely by QGLShaderProgram and
59     the GL2 engine doesn't need to worry about it.
60 
61     Generally, there's two vertex shader objects. The position shaders are
62     the ones which set gl_Position. There's also two "main" vertex shaders,
63     one which just calls the position shader and another which also passes
64     through some texture coordinates from a vertex attribute array to a
65     varying. These texture coordinates are used for mask position in text
66     rendering and for the source coordinates in drawImage/drawPixmap. There's
67     also a "Simple" vertex shader for rendering a solid colour (used to render
68     into the stencil buffer where the actual colour value is discarded).
69 
70     The position shaders for brushes look scary. This is because many of the
71     calculations which logically belong in the fragment shader have been moved
72     into the vertex shader to improve performance. This is why the position
73     calculation is in a separate shader. Not only does it calculate the
74     position, but it also calculates some data to be passed to the fragment
75     shader as a varying. It is optimal to move as much of the calculation as
76     possible into the vertex shader as this is executed less often.
77 
78     The varyings passed to the fragment shaders are interpolated (which is
79     cheap). Unfortunately, GL will apply perspective correction to the
80     interpolation calusing errors. To get around this, the vertex shader must
81     apply perspective correction itself and set the w-value of gl_Position to
82     zero. That way, GL will be tricked into thinking it doesn't need to apply a
83     perspective correction and use linear interpolation instead (which is what
84     we want). Of course, if the brush transform is affeine, no perspective
85     correction is needed and a simpler vertex shader can be used instead.
86 
87     So there are the following "main" vertex shaders:
88         qglslMainVertexShader
89         qglslMainWithTexCoordsVertexShader
90 
91     And the following position vertex shaders:
92         qglslPositionOnlyVertexShader
93         qglslPositionWithTextureBrushVertexShader
94         qglslPositionWithPatternBrushVertexShader
95         qglslPositionWithLinearGradientBrushVertexShader
96         qglslPositionWithRadialGradientBrushVertexShader
97         qglslPositionWithConicalGradientBrushVertexShader
98         qglslAffinePositionWithTextureBrushVertexShader
99         qglslAffinePositionWithPatternBrushVertexShader
100         qglslAffinePositionWithLinearGradientBrushVertexShader
101         qglslAffinePositionWithRadialGradientBrushVertexShader
102         qglslAffinePositionWithConicalGradientBrushVertexShader
103 
104     Leading to 23 possible vertex shaders
105 
106 
107     FRAGMENT SHADERS
108     ================
109 
110     Fragment shaders are also specified as multiple (partial) shaders. The
111     different fragment shaders represent the different stages in Qt's fragment
112     pipeline. There are 1-3 stages in this pipeline: First stage is to get the
113     fragment's colour value. The next stage is to get the fragment's mask value
114     (coverage value for anti-aliasing) and the final stage is to blend the
115     incoming fragment with the background (for composition modes not supported
116     by GL).
117 
118     Of these, the first stage will always be present. If Qt doesn't need to
119     apply anti-aliasing (because it's off or handled by multisampling) then
120     the coverage value doesn't need to be applied. (Note: There are two types
121     of mask, one for regular anti-aliasing and one for sub-pixel anti-
122     aliasing.) If the composition mode is one which GL supports natively then
123     the blending stage doesn't need to be applied.
124 
125     As eash stage can have multiple implementations, they are abstracted as
126     GLSL function calls with the following signatures:
127 
128     Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()":
129         qglslImageSrcFragShader
130         qglslImageSrcWithPatternFragShader
131         qglslNonPremultipliedImageSrcFragShader
132         qglslSolidBrushSrcFragShader
133         qglslTextureBrushSrcFragShader
134         qglslTextureBrushWithPatternFragShader
135         qglslPatternBrushSrcFragShader
136         qglslLinearGradientBrushSrcFragShader
137         qglslRadialGradientBrushSrcFragShader
138         qglslConicalGradientBrushSrcFragShader
139     NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied
140 
141     Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
142         qglslMaskFragmentShader
143         qglslRgbMaskFragmentShaderPass1
144         qglslRgbMaskFragmentShaderPass2
145         qglslRgbMaskWithGammaFragmentShader
146 
147     Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)":
148         qglslColorBurnCompositionModeFragmentShader
149         qglslColorDodgeCompositionModeFragmentShader
150         qglslDarkenCompositionModeFragmentShader
151         qglslDifferenceCompositionModeFragmentShader
152         qglslExclusionCompositionModeFragmentShader
153         qglslHardLightCompositionModeFragmentShader
154         qglslLightenCompositionModeFragmentShader
155         qglslMultiplyCompositionModeFragmentShader
156         qglslOverlayCompositionModeFragmentShader
157         qglslScreenCompositionModeFragmentShader
158         qglslSoftLightCompositionModeFragmentShader
159 
160 
161     Note: In the future, some GLSL compilers will support an extension allowing
162           a new 'color' precision specifier. To support this, qcolorp is used for
163           all color components so it can be defined to colorp or lowp depending upon
164           the implementation.
165 
166     So there are differnt frament shader main functions, depending on the
167     number & type of pipelines the fragment needs to go through.
168 
169     The choice of which main() fragment shader string to use depends on:
170         - Use of global opacity
171         - Brush style (some brushes apply opacity themselves)
172         - Use & type of mask (TODO: Need to support high quality anti-aliasing & text)
173         - Use of non-GL Composition mode
174 
175     Leading to the following fragment shader main functions:
176         gl_FragColor = compose(applyMask(srcPixel()*globalOpacity));
177         gl_FragColor = compose(applyMask(srcPixel()));
178         gl_FragColor = applyMask(srcPixel()*globalOpacity);
179         gl_FragColor = applyMask(srcPixel());
180         gl_FragColor = compose(srcPixel()*globalOpacity);
181         gl_FragColor = compose(srcPixel());
182         gl_FragColor = srcPixel()*globalOpacity;
183         gl_FragColor = srcPixel();
184 
185     Called:
186         qglslMainFragmentShader_CMO
187         qglslMainFragmentShader_CM
188         qglslMainFragmentShader_MO
189         qglslMainFragmentShader_M
190         qglslMainFragmentShader_CO
191         qglslMainFragmentShader_C
192         qglslMainFragmentShader_O
193         qglslMainFragmentShader
194 
195     Where:
196         M = Mask
197         C = Composition
198         O = Global Opacity
199 
200 
201     CUSTOM SHADER CODE
202     ==================
203 
204     The use of custom shader code is supported by the engine for drawImage and
205     drawPixmap calls. This is implemented via hooks in the fragment pipeline.
206 
207     The custom shader is passed to the engine as a partial fragment shader
208     (QGLCustomShaderStage). The shader will implement a pre-defined method name
209     which Qt's fragment pipeline will call:
210 
211         lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords)
212 
213     The provided src and srcCoords parameters can be used to sample from the
214     source image.
215 
216     Transformations, clipping, opacity, and composition modes set using QPainter
217     will be respected when using the custom shader hook.
218 */
219 
220 #ifndef QGLENGINE_SHADER_MANAGER_H
221 #define QGLENGINE_SHADER_MANAGER_H
222 
223 #include <QGLShader>
224 #include <QGLShaderProgram>
225 #include <QPainter>
226 #include <private/qgl_p.h>
227 #include <private/qglcustomshaderstage_p.h>
228 
229 QT_BEGIN_NAMESPACE
230 
231 
232 
233 /*
234 struct QGLEngineCachedShaderProg
235 {
236     QGLEngineCachedShaderProg(QGLEngineShaderManager::ShaderName vertexMain,
237                               QGLEngineShaderManager::ShaderName vertexPosition,
238                               QGLEngineShaderManager::ShaderName fragMain,
239                               QGLEngineShaderManager::ShaderName pixelSrc,
240                               QGLEngineShaderManager::ShaderName mask,
241                               QGLEngineShaderManager::ShaderName composition);
242 
243     int cacheKey;
244     QGLShaderProgram* program;
245 }
246 */
247 
248 static const GLuint QT_VERTEX_COORDS_ATTR  = 0;
249 static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
250 static const GLuint QT_OPACITY_ATTR = 2;
251 static const GLuint QT_PMV_MATRIX_1_ATTR = 3;
252 static const GLuint QT_PMV_MATRIX_2_ATTR = 4;
253 static const GLuint QT_PMV_MATRIX_3_ATTR = 5;
254 
255 class QGLEngineShaderProg;
256 
257 class Q_OPENGL_EXPORT QGLEngineSharedShaders
258 {
259     Q_GADGET
260 public:
261 
262     enum SnippetName {
263         MainVertexShader,
264         MainWithTexCoordsVertexShader,
265         MainWithTexCoordsAndOpacityVertexShader,
266 
267         // UntransformedPositionVertexShader must be first in the list:
268         UntransformedPositionVertexShader,
269         PositionOnlyVertexShader,
270         ComplexGeometryPositionOnlyVertexShader,
271         PositionWithPatternBrushVertexShader,
272         PositionWithLinearGradientBrushVertexShader,
273         PositionWithConicalGradientBrushVertexShader,
274         PositionWithRadialGradientBrushVertexShader,
275         PositionWithTextureBrushVertexShader,
276         AffinePositionWithPatternBrushVertexShader,
277         AffinePositionWithLinearGradientBrushVertexShader,
278         AffinePositionWithConicalGradientBrushVertexShader,
279         AffinePositionWithRadialGradientBrushVertexShader,
280         AffinePositionWithTextureBrushVertexShader,
281 
282         // MainFragmentShader_CMO must be first in the list:
283         MainFragmentShader_CMO,
284         MainFragmentShader_CM,
285         MainFragmentShader_MO,
286         MainFragmentShader_M,
287         MainFragmentShader_CO,
288         MainFragmentShader_C,
289         MainFragmentShader_O,
290         MainFragmentShader,
291         MainFragmentShader_ImageArrays,
292 
293         // ImageSrcFragmentShader must be first in the list::
294         ImageSrcFragmentShader,
295         ImageSrcWithPatternFragmentShader,
296         NonPremultipliedImageSrcFragmentShader,
297         CustomImageSrcFragmentShader,
298         SolidBrushSrcFragmentShader,
299         TextureBrushSrcFragmentShader,
300         TextureBrushSrcWithPatternFragmentShader,
301         PatternBrushSrcFragmentShader,
302         LinearGradientBrushSrcFragmentShader,
303         RadialGradientBrushSrcFragmentShader,
304         ConicalGradientBrushSrcFragmentShader,
305         ShockingPinkSrcFragmentShader,
306 
307         // NoMaskFragmentShader must be first in the list:
308         NoMaskFragmentShader,
309         MaskFragmentShader,
310         RgbMaskFragmentShaderPass1,
311         RgbMaskFragmentShaderPass2,
312         RgbMaskWithGammaFragmentShader,
313 
314         // NoCompositionModeFragmentShader must be first in the list:
315         NoCompositionModeFragmentShader,
316         MultiplyCompositionModeFragmentShader,
317         ScreenCompositionModeFragmentShader,
318         OverlayCompositionModeFragmentShader,
319         DarkenCompositionModeFragmentShader,
320         LightenCompositionModeFragmentShader,
321         ColorDodgeCompositionModeFragmentShader,
322         ColorBurnCompositionModeFragmentShader,
323         HardLightCompositionModeFragmentShader,
324         SoftLightCompositionModeFragmentShader,
325         DifferenceCompositionModeFragmentShader,
326         ExclusionCompositionModeFragmentShader,
327 
328         TotalSnippetCount, InvalidSnippetName
329     };
330 #if defined (QT_DEBUG)
331     Q_ENUMS(SnippetName)
332     static QByteArray snippetNameStr(SnippetName snippetName);
333 #endif
334 
335 /*
336     // These allow the ShaderName enum to be used as a cache key
337     const int mainVertexOffset = 0;
338     const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader;
339     const int mainFragOffset = (1<<6) - MainFragmentShader_CMO;
340     const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader;
341     const int maskOffset = (1<<14) - NoMaskShader;
342     const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
343 */
344 
345     QGLEngineSharedShaders(const QGLContext *context);
346     ~QGLEngineSharedShaders();
347 
simpleProgram()348     QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
blitProgram()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 
362 private:
363     QGLShaderProgram *blitShaderProg;
364     QGLShaderProgram *simpleShaderProg;
365     QList<QGLEngineShaderProg*> cachedPrograms;
366     QList<QGLShader *> shaders;
367 
368     static const char* qShaderSnippets[TotalSnippetCount];
369 };
370 
371 
372 class QGLEngineShaderProg
373 {
374 public:
QGLEngineShaderProg()375     QGLEngineShaderProg() : program(nullptr) {}
376 
~QGLEngineShaderProg()377     ~QGLEngineShaderProg() {
378         if (program)
379             delete program;
380     }
381 
382     QGLEngineSharedShaders::SnippetName mainVertexShader;
383     QGLEngineSharedShaders::SnippetName positionVertexShader;
384     QGLEngineSharedShaders::SnippetName mainFragShader;
385     QGLEngineSharedShaders::SnippetName srcPixelFragShader;
386     QGLEngineSharedShaders::SnippetName maskFragShader;
387     QGLEngineSharedShaders::SnippetName compositionFragShader;
388 
389     QByteArray          customStageSource; //TODO: Decent cache key for custom stages
390     QGLShaderProgram*   program;
391 
392     QVector<uint> uniformLocations;
393 
394     bool                useTextureCoords;
395     bool                useOpacityAttribute;
396     bool                usePmvMatrixAttribute;
397 
398     bool operator==(const QGLEngineShaderProg& other) const {
399         // We don't care about the program
400         return ( mainVertexShader      == other.mainVertexShader &&
401                  positionVertexShader  == other.positionVertexShader &&
402                  mainFragShader        == other.mainFragShader &&
403                  srcPixelFragShader    == other.srcPixelFragShader &&
404                  maskFragShader        == other.maskFragShader &&
405                  compositionFragShader == other.compositionFragShader &&
406                  customStageSource     == other.customStageSource
407                );
408     }
409 };
410 
411 class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
412 {
413     Q_OBJECT
414 public:
415     QGLEngineShaderManager(QGLContext* context);
416     ~QGLEngineShaderManager();
417 
418     enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask};
419     enum PixelSrcType {
420         ImageSrc = Qt::TexturePattern+1,
421         NonPremultipliedImageSrc = Qt::TexturePattern+2,
422         PatternSrc = Qt::TexturePattern+3,
423         TextureSrcWithPattern = Qt::TexturePattern+4
424     };
425 
426     enum Uniform {
427         ImageTexture,
428         PatternColor,
429         GlobalOpacity,
430         Depth,
431         MaskTexture,
432         FragmentColor,
433         LinearData,
434         Angle,
435         HalfViewportSize,
436         Fmp,
437         Fmp2MRadius2,
438         Inverse2Fmp2MRadius2,
439         SqrFr,
440         BRadius,
441         InvertedTextureSize,
442         BrushTransform,
443         BrushTexture,
444         Matrix,
445         TranslateZ,
446         NumUniforms
447     };
448 
449     enum OpacityMode {
450         NoOpacity,
451         UniformOpacity,
452         AttributeOpacity
453     };
454 
455     // There are optimizations we can do, depending on the brush transform:
456     //    1) May not have to apply perspective-correction
457     //    2) Can use lower precision for matrix
458     void optimiseForBrushTransform(QTransform::TransformationType transformType);
459     void setSrcPixelType(Qt::BrushStyle);
460     void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
461     void setOpacityMode(OpacityMode);
462     void setMaskType(MaskType);
463     void setCompositionMode(QPainter::CompositionMode);
464     void setCustomStage(QGLCustomShaderStage* stage);
465     void removeCustomStage();
466 
467     GLuint getUniformLocation(Uniform id);
468 
469     void setDirty(); // someone has manually changed the current shader program
470     bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
471 
472     void useSimpleProgram();
473     void useBlitProgram();
setHasComplexGeometry(bool hasComplexGeometry)474     void setHasComplexGeometry(bool hasComplexGeometry)
475     {
476         complexGeometry = hasComplexGeometry;
477         shaderProgNeedsChanging = true;
478     }
hasComplexGeometry()479     bool hasComplexGeometry() const
480     {
481         return complexGeometry;
482     }
483 
484     QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
485     QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
486     QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
487 
488     QGLEngineSharedShaders* sharedShaders;
489 
490 private:
491     QGLContext*     ctx;
492     bool            shaderProgNeedsChanging;
493     bool            complexGeometry;
494 
495     // Current state variables which influence the choice of shader:
496     QTransform                  brushTransform;
497     int                         srcPixelType;
498     OpacityMode                 opacityMode;
499     MaskType                    maskType;
500     QPainter::CompositionMode   compositionMode;
501     QGLCustomShaderStage*       customSrcStage;
502 
503     QGLEngineShaderProg*    currentShaderProg;
504 };
505 
506 QT_END_NAMESPACE
507 
508 #endif //QGLENGINE_SHADER_MANAGER_H
509