source: trunk/src/opengl/gl2paintengineex/qglengineshadermanager.cpp@ 769

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

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

  • Property svn:eol-style set to native
File size: 33.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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#include "qglengineshadermanager_p.h"
43#include "qglengineshadersource_p.h"
44
45#if defined(QT_DEBUG)
46#include <QMetaEnum>
47#endif
48
49
50QT_BEGIN_NAMESPACE
51
52static void qt_shared_shaders_free(void *data)
53{
54 delete reinterpret_cast<QGLEngineSharedShaders *>(data);
55}
56
57Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
58
59QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
60{
61 QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
62 if (!p) {
63 QGLShareContextScope scope(context);
64 qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
65 }
66 return p;
67}
68
69const char* QGLEngineSharedShaders::qShaderSnippets[] = {
70 0,0,0,0,0,0,0,0,0,0,
71 0,0,0,0,0,0,0,0,0,0,
72 0,0,0,0,0,0,0,0,0,0,
73 0,0,0,0,0
74};
75
76QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
77 : ctxGuard(context)
78 , blitShaderProg(0)
79 , simpleShaderProg(0)
80{
81
82/*
83 Rather than having the shader source array statically initialised, it is initialised
84 here instead. This is to allow new shader names to be inserted or existing names moved
85 around without having to change the order of the glsl strings. It is hoped this will
86 make future hard-to-find runtime bugs more obvious and generally give more solid code.
87*/
88 static bool snippetsPopulated = false;
89 if (!snippetsPopulated) {
90
91 const char** code = qShaderSnippets; // shortcut
92
93 code[MainVertexShader] = qglslMainVertexShader;
94 code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
95 code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;
96
97 code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
98 code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
99 code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
100 code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
101 code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader;
102 code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader;
103 code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader;
104 code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader;
105 code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader;
106 code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader;
107 code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader;
108 code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader;
109
110 code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO;
111 code[MainFragmentShader_CM] = qglslMainFragmentShader_CM;
112 code[MainFragmentShader_MO] = qglslMainFragmentShader_MO;
113 code[MainFragmentShader_M] = qglslMainFragmentShader_M;
114 code[MainFragmentShader_CO] = qglslMainFragmentShader_CO;
115 code[MainFragmentShader_C] = qglslMainFragmentShader_C;
116 code[MainFragmentShader_O] = qglslMainFragmentShader_O;
117 code[MainFragmentShader] = qglslMainFragmentShader;
118 code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;
119
120 code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
121 code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
122 code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
123 code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
124 code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
125 code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
126 code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
127 code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader;
128 code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader;
129 code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader;
130 code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
131 code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;
132
133 code[NoMaskFragmentShader] = "";
134 code[MaskFragmentShader] = qglslMaskFragmentShader;
135 code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
136 code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
137 code[RgbMaskWithGammaFragmentShader] = ""; //###
138
139 code[NoCompositionModeFragmentShader] = "";
140 code[MultiplyCompositionModeFragmentShader] = ""; //###
141 code[ScreenCompositionModeFragmentShader] = ""; //###
142 code[OverlayCompositionModeFragmentShader] = ""; //###
143 code[DarkenCompositionModeFragmentShader] = ""; //###
144 code[LightenCompositionModeFragmentShader] = ""; //###
145 code[ColorDodgeCompositionModeFragmentShader] = ""; //###
146 code[ColorBurnCompositionModeFragmentShader] = ""; //###
147 code[HardLightCompositionModeFragmentShader] = ""; //###
148 code[SoftLightCompositionModeFragmentShader] = ""; //###
149 code[DifferenceCompositionModeFragmentShader] = ""; //###
150 code[ExclusionCompositionModeFragmentShader] = ""; //###
151
152#if defined(QT_DEBUG)
153 // Check that all the elements have been filled:
154 for (int i = 0; i < TotalSnippetCount; ++i) {
155 if (qShaderSnippets[i] == 0) {
156 qFatal("Shader snippet for %s (#%d) is missing!",
157 snippetNameStr(SnippetName(i)).constData(), i);
158 }
159 }
160#endif
161 snippetsPopulated = true;
162 }
163
164 QGLShader* fragShader;
165 QGLShader* vertexShader;
166 QByteArray source;
167
168 // Compile up the simple shader:
169 source.clear();
170 source.append(qShaderSnippets[MainVertexShader]);
171 source.append(qShaderSnippets[PositionOnlyVertexShader]);
172 vertexShader = new QGLShader(QGLShader::Vertex, context, this);
173 if (!vertexShader->compileSourceCode(source))
174 qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
175
176 source.clear();
177 source.append(qShaderSnippets[MainFragmentShader]);
178 source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
179 fragShader = new QGLShader(QGLShader::Fragment, context, this);
180 if (!fragShader->compileSourceCode(source))
181 qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
182
183 simpleShaderProg = new QGLShaderProgram(context, this);
184 simpleShaderProg->addShader(vertexShader);
185 simpleShaderProg->addShader(fragShader);
186 simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
187 simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
188 simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
189 simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
190 simpleShaderProg->link();
191 if (!simpleShaderProg->isLinked()) {
192 qCritical() << "Errors linking simple shader:"
193 << simpleShaderProg->log();
194 }
195
196 // Compile the blit shader:
197 source.clear();
198 source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
199 source.append(qShaderSnippets[UntransformedPositionVertexShader]);
200 vertexShader = new QGLShader(QGLShader::Vertex, context, this);
201 if (!vertexShader->compileSourceCode(source))
202 qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
203
204 source.clear();
205 source.append(qShaderSnippets[MainFragmentShader]);
206 source.append(qShaderSnippets[ImageSrcFragmentShader]);
207 fragShader = new QGLShader(QGLShader::Fragment, context, this);
208 if (!fragShader->compileSourceCode(source))
209 qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
210
211 blitShaderProg = new QGLShaderProgram(context, this);
212 blitShaderProg->addShader(vertexShader);
213 blitShaderProg->addShader(fragShader);
214 blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
215 blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
216 blitShaderProg->link();
217 if (!blitShaderProg->isLinked()) {
218 qCritical() << "Errors linking blit shader:"
219 << simpleShaderProg->log();
220 }
221
222}
223
224QGLEngineSharedShaders::~QGLEngineSharedShaders()
225{
226 QList<QGLEngineShaderProg*>::iterator itr;
227 for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr)
228 delete *itr;
229
230 if (blitShaderProg) {
231 delete blitShaderProg;
232 blitShaderProg = 0;
233 }
234
235 if (simpleShaderProg) {
236 delete simpleShaderProg;
237 simpleShaderProg = 0;
238 }
239}
240
241#if defined (QT_DEBUG)
242QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
243{
244 QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName"));
245 return QByteArray(m.valueToKey(name));
246}
247#endif
248
249// The address returned here will only be valid until next time this function is called.
250QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
251{
252 for (int i = 0; i < cachedPrograms.size(); ++i) {
253 QGLEngineShaderProg *cachedProg = cachedPrograms[i];
254 if (*cachedProg == prog) {
255 // Move the program to the top of the list as a poor-man's cache algo
256 cachedPrograms.move(i, 0);
257 return cachedProg;
258 }
259 }
260
261 QGLShader *vertexShader = 0;
262 QGLShader *fragShader = 0;
263 QGLEngineShaderProg *newProg = 0;
264 bool success = false;
265
266 do {
267 QByteArray source;
268 // Insert the custom stage before the srcPixel shader to work around an ATI driver bug
269 // where you cannot forward declare a function that takes a sampler as argument.
270 if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
271 source.append(prog.customStageSource);
272 source.append(qShaderSnippets[prog.mainFragShader]);
273 source.append(qShaderSnippets[prog.srcPixelFragShader]);
274 if (prog.compositionFragShader)
275 source.append(qShaderSnippets[prog.compositionFragShader]);
276 if (prog.maskFragShader)
277 source.append(qShaderSnippets[prog.maskFragShader]);
278 fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
279 QByteArray description;
280#if defined(QT_DEBUG)
281 // Name the shader for easier debugging
282 description.append("Fragment shader: main=");
283 description.append(snippetNameStr(prog.mainFragShader));
284 description.append(", srcPixel=");
285 description.append(snippetNameStr(prog.srcPixelFragShader));
286 if (prog.compositionFragShader) {
287 description.append(", composition=");
288 description.append(snippetNameStr(prog.compositionFragShader));
289 }
290 if (prog.maskFragShader) {
291 description.append(", mask=");
292 description.append(snippetNameStr(prog.maskFragShader));
293 }
294 fragShader->setObjectName(QString::fromLatin1(description));
295#endif
296 if (!fragShader->compileSourceCode(source)) {
297 qWarning() << "Warning:" << description << "failed to compile!";
298 break;
299 }
300
301 source.clear();
302 source.append(qShaderSnippets[prog.mainVertexShader]);
303 source.append(qShaderSnippets[prog.positionVertexShader]);
304 vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
305#if defined(QT_DEBUG)
306 // Name the shader for easier debugging
307 description.clear();
308 description.append("Vertex shader: main=");
309 description.append(snippetNameStr(prog.mainVertexShader));
310 description.append(", position=");
311 description.append(snippetNameStr(prog.positionVertexShader));
312 vertexShader->setObjectName(QString::fromLatin1(description));
313#endif
314 if (!vertexShader->compileSourceCode(source)) {
315 qWarning() << "Warning:" << description << "failed to compile!";
316 break;
317 }
318
319 newProg = new QGLEngineShaderProg(prog);
320
321 // If the shader program's not found in the cache, create it now.
322 newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
323 newProg->program->addShader(vertexShader);
324 newProg->program->addShader(fragShader);
325
326 // We have to bind the vertex attribute names before the program is linked:
327 newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
328 if (newProg->useTextureCoords)
329 newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
330 if (newProg->useOpacityAttribute)
331 newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
332 if (newProg->usePmvMatrix) {
333 newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
334 newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
335 newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
336 }
337
338 newProg->program->link();
339 if (!newProg->program->isLinked()) {
340 QLatin1String none("none");
341 QLatin1String br("\n");
342 QString error;
343 error = QLatin1String("Shader program failed to link,")
344#if defined(QT_DEBUG)
345 + br
346 + QLatin1String(" Shaders Used:") + br
347 + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
348 + QLatin1String(vertexShader->sourceCode()) + br
349 + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
350 + QLatin1String(fragShader->sourceCode()) + br
351#endif
352 + QLatin1String(" Error Log:\n")
353 + QLatin1String(" ") + newProg->program->log();
354 qWarning() << error;
355 break;
356 }
357 if (cachedPrograms.count() > 30) {
358 // The cache is full, so delete the last 5 programs in the list.
359 // These programs will be least used, as a program us bumped to
360 // the top of the list when it's used.
361 for (int i = 0; i < 5; ++i) {
362 delete cachedPrograms.last();
363 cachedPrograms.removeLast();
364 }
365 }
366
367 cachedPrograms.insert(0, newProg);
368
369 success = true;
370 } while (false);
371
372 // Clean up everything if we weren't successful
373 if (!success) {
374 if (newProg) {
375 delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
376 newProg = 0;
377 }
378 else {
379 if (vertexShader)
380 delete vertexShader;
381 if (fragShader)
382 delete fragShader;
383 }
384 }
385
386 return newProg;
387}
388
389void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
390{
391 // Remove any shader programs which has this as the custom shader src:
392 for (int i = 0; i < cachedPrograms.size(); ++i) {
393 QGLEngineShaderProg *cachedProg = cachedPrograms[i];
394 if (cachedProg->customStageSource == stage->source()) {
395 delete cachedProg;
396 cachedPrograms.removeAt(i);
397 i--;
398 }
399 }
400}
401
402
403QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
404 : ctx(context),
405 shaderProgNeedsChanging(true),
406 srcPixelType(Qt::NoBrush),
407 opacityMode(NoOpacity),
408 maskType(NoMask),
409 compositionMode(QPainter::CompositionMode_SourceOver),
410 customSrcStage(0),
411 currentShaderProg(0)
412{
413 sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
414 connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
415}
416
417QGLEngineShaderManager::~QGLEngineShaderManager()
418{
419 //###
420 removeCustomStage();
421}
422
423GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
424{
425 if (!currentShaderProg)
426 return 0;
427
428 QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
429 if (uniformLocations.isEmpty())
430 uniformLocations.fill(GLuint(-1), NumUniforms);
431
432 static const char *uniformNames[] = {
433 "imageTexture",
434 "patternColor",
435 "globalOpacity",
436 "depth",
437 "maskTexture",
438 "fragmentColor",
439 "linearData",
440 "angle",
441 "halfViewportSize",
442 "fmp",
443 "fmp2_m_radius2",
444 "inverse_2_fmp2_m_radius2",
445 "invertedTextureSize",
446 "brushTransform",
447 "brushTexture"
448 };
449
450 if (uniformLocations.at(id) == GLuint(-1))
451 uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
452
453 return uniformLocations.at(id);
454}
455
456
457void QGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType)
458{
459 Q_UNUSED(transformType); // Currently ignored
460}
461
462void QGLEngineShaderManager::setDirty()
463{
464 shaderProgNeedsChanging = true;
465}
466
467void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
468{
469 Q_ASSERT(style != Qt::NoBrush);
470 if (srcPixelType == PixelSrcType(style))
471 return;
472
473 srcPixelType = style;
474 shaderProgNeedsChanging = true; //###
475}
476
477void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
478{
479 if (srcPixelType == type)
480 return;
481
482 srcPixelType = type;
483 shaderProgNeedsChanging = true; //###
484}
485
486void QGLEngineShaderManager::setOpacityMode(OpacityMode mode)
487{
488 if (opacityMode == mode)
489 return;
490
491 opacityMode = mode;
492 shaderProgNeedsChanging = true; //###
493}
494
495void QGLEngineShaderManager::setMaskType(MaskType type)
496{
497 if (maskType == type)
498 return;
499
500 maskType = type;
501 shaderProgNeedsChanging = true; //###
502}
503
504void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
505{
506 if (compositionMode == mode)
507 return;
508
509 compositionMode = mode;
510 shaderProgNeedsChanging = true; //###
511}
512
513void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
514{
515 if (customSrcStage)
516 removeCustomStage();
517 customSrcStage = stage;
518 shaderProgNeedsChanging = true;
519}
520
521void QGLEngineShaderManager::removeCustomStage()
522{
523 if (customSrcStage)
524 customSrcStage->setInactive();
525 customSrcStage = 0;
526 shaderProgNeedsChanging = true;
527}
528
529QGLShaderProgram* QGLEngineShaderManager::currentProgram()
530{
531 if (currentShaderProg)
532 return currentShaderProg->program;
533 else
534 return sharedShaders->simpleProgram();
535}
536
537void QGLEngineShaderManager::useSimpleProgram()
538{
539 sharedShaders->simpleProgram()->bind();
540 QGLContextPrivate* ctx_d = ctx->d_func();
541 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
542 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
543 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
544 shaderProgNeedsChanging = true;
545}
546
547void QGLEngineShaderManager::useBlitProgram()
548{
549 sharedShaders->blitProgram()->bind();
550 QGLContextPrivate* ctx_d = ctx->d_func();
551 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
552 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
553 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
554 shaderProgNeedsChanging = true;
555}
556
557QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
558{
559 return sharedShaders->simpleProgram();
560}
561
562QGLShaderProgram* QGLEngineShaderManager::blitProgram()
563{
564 return sharedShaders->blitProgram();
565}
566
567
568
569// Select & use the correct shader program using the current state.
570// Returns true if program needed changing.
571bool QGLEngineShaderManager::useCorrectShaderProg()
572{
573 if (!shaderProgNeedsChanging)
574 return false;
575
576 bool useCustomSrc = customSrcStage != 0;
577 if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) {
578 useCustomSrc = false;
579 qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
580 }
581
582 QGLEngineShaderProg requiredProgram;
583
584 bool texCoords = false;
585
586 // Choose vertex shader shader position function (which typically also sets
587 // varyings) and the source pixel (srcPixel) fragment shader function:
588 requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName;
589 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName;
590 bool isAffine = brushTransform.isAffine();
591 if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
592 if (isAffine)
593 requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
594 else
595 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
596
597 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
598 }
599 else switch (srcPixelType) {
600 default:
601 case Qt::NoBrush:
602 qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
603 break;
604 case QGLEngineShaderManager::ImageSrc:
605 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader;
606 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
607 texCoords = true;
608 break;
609 case QGLEngineShaderManager::NonPremultipliedImageSrc:
610 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
611 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
612 texCoords = true;
613 break;
614 case QGLEngineShaderManager::PatternSrc:
615 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
616 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
617 texCoords = true;
618 break;
619 case QGLEngineShaderManager::TextureSrcWithPattern:
620 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
621 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
622 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
623 break;
624 case Qt::SolidPattern:
625 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
626 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
627 break;
628 case Qt::LinearGradientPattern:
629 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
630 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
631 : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
632 break;
633 case Qt::ConicalGradientPattern:
634 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
635 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
636 : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
637 break;
638 case Qt::RadialGradientPattern:
639 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
640 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
641 : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
642 break;
643 case Qt::TexturePattern:
644 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
645 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
646 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
647 break;
648 };
649
650 if (useCustomSrc) {
651 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader;
652 requiredProgram.customStageSource = customSrcStage->source();
653 }
654
655 const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
656 const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
657
658 // Choose fragment shader main function:
659 if (opacityMode == AttributeOpacity) {
660 Q_ASSERT(!hasCompose && !hasMask);
661 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
662 } else {
663 bool useGlobalOpacity = (opacityMode == UniformOpacity);
664 if (hasCompose && hasMask && useGlobalOpacity)
665 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO;
666 if (hasCompose && hasMask && !useGlobalOpacity)
667 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM;
668 if (!hasCompose && hasMask && useGlobalOpacity)
669 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO;
670 if (!hasCompose && hasMask && !useGlobalOpacity)
671 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M;
672 if (hasCompose && !hasMask && useGlobalOpacity)
673 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO;
674 if (hasCompose && !hasMask && !useGlobalOpacity)
675 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C;
676 if (!hasCompose && !hasMask && useGlobalOpacity)
677 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O;
678 if (!hasCompose && !hasMask && !useGlobalOpacity)
679 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader;
680 }
681
682 if (hasMask) {
683 if (maskType == PixelMask) {
684 requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader;
685 texCoords = true;
686 } else if (maskType == SubPixelMaskPass1) {
687 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
688 texCoords = true;
689 } else if (maskType == SubPixelMaskPass2) {
690 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
691 texCoords = true;
692 } else if (maskType == SubPixelWithGammaMask) {
693 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
694 texCoords = true;
695 } else {
696 qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
697 }
698 } else {
699 requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader;
700 }
701
702 if (hasCompose) {
703 switch (compositionMode) {
704 case QPainter::CompositionMode_Multiply:
705 requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
706 break;
707 case QPainter::CompositionMode_Screen:
708 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
709 break;
710 case QPainter::CompositionMode_Overlay:
711 requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
712 break;
713 case QPainter::CompositionMode_Darken:
714 requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
715 break;
716 case QPainter::CompositionMode_Lighten:
717 requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
718 break;
719 case QPainter::CompositionMode_ColorDodge:
720 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
721 break;
722 case QPainter::CompositionMode_ColorBurn:
723 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
724 break;
725 case QPainter::CompositionMode_HardLight:
726 requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
727 break;
728 case QPainter::CompositionMode_SoftLight:
729 requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
730 break;
731 case QPainter::CompositionMode_Difference:
732 requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
733 break;
734 case QPainter::CompositionMode_Exclusion:
735 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
736 break;
737 default:
738 qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
739 }
740 } else {
741 requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader;
742 }
743
744 // Choose vertex shader main function
745 if (opacityMode == AttributeOpacity) {
746 Q_ASSERT(texCoords);
747 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
748 } else if (texCoords) {
749 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
750 } else {
751 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
752 }
753 requiredProgram.useTextureCoords = texCoords;
754 requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
755 requiredProgram.usePmvMatrix = true;
756
757 // At this point, requiredProgram is fully populated so try to find the program in the cache
758 currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
759
760 if (currentShaderProg) {
761 currentShaderProg->program->bind();
762 if (useCustomSrc)
763 customSrcStage->setUniforms(currentShaderProg->program);
764 }
765
766 // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it
767 // doesn't use are disabled)
768 QGLContextPrivate* ctx_d = ctx->d_func();
769 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
770 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg && currentShaderProg->useTextureCoords);
771 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg && currentShaderProg->useOpacityAttribute);
772
773 shaderProgNeedsChanging = false;
774 return true;
775}
776
777QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.