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

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

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 32.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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** 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 qt-info@nokia.com.
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 source.append(qShaderSnippets[prog.mainFragShader]);
269 source.append(qShaderSnippets[prog.srcPixelFragShader]);
270 if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
271 source.append(prog.customStageSource);
272 if (prog.compositionFragShader)
273 source.append(qShaderSnippets[prog.compositionFragShader]);
274 if (prog.maskFragShader)
275 source.append(qShaderSnippets[prog.maskFragShader]);
276 fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
277 QByteArray description;
278#if defined(QT_DEBUG)
279 // Name the shader for easier debugging
280 description.append("Fragment shader: main=");
281 description.append(snippetNameStr(prog.mainFragShader));
282 description.append(", srcPixel=");
283 description.append(snippetNameStr(prog.srcPixelFragShader));
284 if (prog.compositionFragShader) {
285 description.append(", composition=");
286 description.append(snippetNameStr(prog.compositionFragShader));
287 }
288 if (prog.maskFragShader) {
289 description.append(", mask=");
290 description.append(snippetNameStr(prog.maskFragShader));
291 }
292 fragShader->setObjectName(QString::fromLatin1(description));
293#endif
294 if (!fragShader->compileSourceCode(source)) {
295 qWarning() << "Warning:" << description << "failed to compile!";
296 break;
297 }
298
299 source.clear();
300 source.append(qShaderSnippets[prog.mainVertexShader]);
301 source.append(qShaderSnippets[prog.positionVertexShader]);
302 vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
303#if defined(QT_DEBUG)
304 // Name the shader for easier debugging
305 description.clear();
306 description.append("Vertex shader: main=");
307 description.append(snippetNameStr(prog.mainVertexShader));
308 description.append(", position=");
309 description.append(snippetNameStr(prog.positionVertexShader));
310 vertexShader->setObjectName(QString::fromLatin1(description));
311#endif
312 if (!vertexShader->compileSourceCode(source)) {
313 qWarning() << "Warning:" << description << "failed to compile!";
314 break;
315 }
316
317 newProg = new QGLEngineShaderProg(prog);
318
319 // If the shader program's not found in the cache, create it now.
320 newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
321 newProg->program->addShader(vertexShader);
322 newProg->program->addShader(fragShader);
323
324 // We have to bind the vertex attribute names before the program is linked:
325 newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
326 if (newProg->useTextureCoords)
327 newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
328 if (newProg->useOpacityAttribute)
329 newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
330 if (newProg->usePmvMatrix) {
331 newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
332 newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
333 newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR);
334 }
335
336 newProg->program->link();
337 if (!newProg->program->isLinked()) {
338 QLatin1String none("none");
339 QLatin1String br("\n");
340 QString error;
341 error = QLatin1String("Shader program failed to link,")
342#if defined(QT_DEBUG)
343 + br
344 + QLatin1String(" Shaders Used:") + br
345 + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
346 + QLatin1String(vertexShader->sourceCode()) + br
347 + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
348 + QLatin1String(fragShader->sourceCode()) + br
349#endif
350 + QLatin1String(" Error Log:\n")
351 + QLatin1String(" ") + newProg->program->log();
352 qWarning() << error;
353 break;
354 }
355 if (cachedPrograms.count() > 30) {
356 // The cache is full, so delete the last 5 programs in the list.
357 // These programs will be least used, as a program us bumped to
358 // the top of the list when it's used.
359 for (int i = 0; i < 5; ++i) {
360 delete cachedPrograms.last();
361 cachedPrograms.removeLast();
362 }
363 }
364
365 cachedPrograms.insert(0, newProg);
366
367 success = true;
368 } while (false);
369
370 // Clean up everything if we weren't successful
371 if (!success) {
372 if (newProg) {
373 delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders
374 newProg = 0;
375 }
376 else {
377 if (vertexShader)
378 delete vertexShader;
379 if (fragShader)
380 delete fragShader;
381 }
382 }
383
384 return newProg;
385}
386
387void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
388{
389 // Remove any shader programs which has this as the custom shader src:
390 for (int i = 0; i < cachedPrograms.size(); ++i) {
391 QGLEngineShaderProg *cachedProg = cachedPrograms[i];
392 if (cachedProg->customStageSource == stage->source()) {
393 delete cachedProg;
394 cachedPrograms.removeAt(i);
395 i--;
396 }
397 }
398}
399
400
401QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
402 : ctx(context),
403 shaderProgNeedsChanging(true),
404 srcPixelType(Qt::NoBrush),
405 opacityMode(NoOpacity),
406 maskType(NoMask),
407 compositionMode(QPainter::CompositionMode_SourceOver),
408 customSrcStage(0),
409 currentShaderProg(0)
410{
411 sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
412 connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
413}
414
415QGLEngineShaderManager::~QGLEngineShaderManager()
416{
417 //###
418 removeCustomStage();
419}
420
421GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
422{
423 if (!currentShaderProg)
424 return 0;
425
426 QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
427 if (uniformLocations.isEmpty())
428 uniformLocations.fill(GLuint(-1), NumUniforms);
429
430 static const char *uniformNames[] = {
431 "imageTexture",
432 "patternColor",
433 "globalOpacity",
434 "depth",
435 "maskTexture",
436 "fragmentColor",
437 "linearData",
438 "angle",
439 "halfViewportSize",
440 "fmp",
441 "fmp2_m_radius2",
442 "inverse_2_fmp2_m_radius2",
443 "invertedTextureSize",
444 "brushTransform",
445 "brushTexture"
446 };
447
448 if (uniformLocations.at(id) == GLuint(-1))
449 uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
450
451 return uniformLocations.at(id);
452}
453
454
455void QGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType)
456{
457 Q_UNUSED(transformType); // Currently ignored
458}
459
460void QGLEngineShaderManager::setDirty()
461{
462 shaderProgNeedsChanging = true;
463}
464
465void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style)
466{
467 Q_ASSERT(style != Qt::NoBrush);
468 if (srcPixelType == PixelSrcType(style))
469 return;
470
471 srcPixelType = style;
472 shaderProgNeedsChanging = true; //###
473}
474
475void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
476{
477 if (srcPixelType == type)
478 return;
479
480 srcPixelType = type;
481 shaderProgNeedsChanging = true; //###
482}
483
484void QGLEngineShaderManager::setOpacityMode(OpacityMode mode)
485{
486 if (opacityMode == mode)
487 return;
488
489 opacityMode = mode;
490 shaderProgNeedsChanging = true; //###
491}
492
493void QGLEngineShaderManager::setMaskType(MaskType type)
494{
495 if (maskType == type)
496 return;
497
498 maskType = type;
499 shaderProgNeedsChanging = true; //###
500}
501
502void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
503{
504 if (compositionMode == mode)
505 return;
506
507 compositionMode = mode;
508 shaderProgNeedsChanging = true; //###
509}
510
511void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
512{
513 if (customSrcStage)
514 removeCustomStage();
515 customSrcStage = stage;
516 shaderProgNeedsChanging = true;
517}
518
519void QGLEngineShaderManager::removeCustomStage()
520{
521 if (customSrcStage)
522 customSrcStage->setInactive();
523 customSrcStage = 0;
524 shaderProgNeedsChanging = true;
525}
526
527QGLShaderProgram* QGLEngineShaderManager::currentProgram()
528{
529 if (currentShaderProg)
530 return currentShaderProg->program;
531 else
532 return sharedShaders->simpleProgram();
533}
534
535void QGLEngineShaderManager::useSimpleProgram()
536{
537 sharedShaders->simpleProgram()->bind();
538 QGLContextPrivate* ctx_d = ctx->d_func();
539 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
540 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
541 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
542 shaderProgNeedsChanging = true;
543}
544
545void QGLEngineShaderManager::useBlitProgram()
546{
547 sharedShaders->blitProgram()->bind();
548 QGLContextPrivate* ctx_d = ctx->d_func();
549 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
550 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
551 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
552 shaderProgNeedsChanging = true;
553}
554
555QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
556{
557 return sharedShaders->simpleProgram();
558}
559
560QGLShaderProgram* QGLEngineShaderManager::blitProgram()
561{
562 return sharedShaders->blitProgram();
563}
564
565
566
567// Select & use the correct shader program using the current state.
568// Returns true if program needed changing.
569bool QGLEngineShaderManager::useCorrectShaderProg()
570{
571 if (!shaderProgNeedsChanging)
572 return false;
573
574 bool useCustomSrc = customSrcStage != 0;
575 if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) {
576 useCustomSrc = false;
577 qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
578 }
579
580 QGLEngineShaderProg requiredProgram;
581
582 bool texCoords = false;
583
584 // Choose vertex shader shader position function (which typically also sets
585 // varyings) and the source pixel (srcPixel) fragment shader function:
586 requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName;
587 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName;
588 bool isAffine = brushTransform.isAffine();
589 if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
590 if (isAffine)
591 requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
592 else
593 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
594
595 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
596 }
597 else switch (srcPixelType) {
598 default:
599 case Qt::NoBrush:
600 qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
601 break;
602 case QGLEngineShaderManager::ImageSrc:
603 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader;
604 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
605 texCoords = true;
606 break;
607 case QGLEngineShaderManager::NonPremultipliedImageSrc:
608 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
609 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
610 texCoords = true;
611 break;
612 case QGLEngineShaderManager::PatternSrc:
613 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
614 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
615 texCoords = true;
616 break;
617 case QGLEngineShaderManager::TextureSrcWithPattern:
618 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
619 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
620 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
621 break;
622 case Qt::SolidPattern:
623 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
624 requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
625 break;
626 case Qt::LinearGradientPattern:
627 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
628 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
629 : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
630 break;
631 case Qt::ConicalGradientPattern:
632 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
633 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
634 : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
635 break;
636 case Qt::RadialGradientPattern:
637 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
638 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
639 : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
640 break;
641 case Qt::TexturePattern:
642 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
643 requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
644 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
645 break;
646 };
647
648 if (useCustomSrc) {
649 requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader;
650 requiredProgram.customStageSource = customSrcStage->source();
651 }
652
653 const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
654 const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
655
656 // Choose fragment shader main function:
657 if (opacityMode == AttributeOpacity) {
658 Q_ASSERT(!hasCompose && !hasMask);
659 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
660 } else {
661 bool useGlobalOpacity = (opacityMode == UniformOpacity);
662 if (hasCompose && hasMask && useGlobalOpacity)
663 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO;
664 if (hasCompose && hasMask && !useGlobalOpacity)
665 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM;
666 if (!hasCompose && hasMask && useGlobalOpacity)
667 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO;
668 if (!hasCompose && hasMask && !useGlobalOpacity)
669 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M;
670 if (hasCompose && !hasMask && useGlobalOpacity)
671 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO;
672 if (hasCompose && !hasMask && !useGlobalOpacity)
673 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C;
674 if (!hasCompose && !hasMask && useGlobalOpacity)
675 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O;
676 if (!hasCompose && !hasMask && !useGlobalOpacity)
677 requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader;
678 }
679
680 if (hasMask) {
681 if (maskType == PixelMask) {
682 requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader;
683 texCoords = true;
684 } else if (maskType == SubPixelMaskPass1) {
685 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
686 texCoords = true;
687 } else if (maskType == SubPixelMaskPass2) {
688 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
689 texCoords = true;
690 } else if (maskType == SubPixelWithGammaMask) {
691 requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
692 texCoords = true;
693 } else {
694 qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
695 }
696 } else {
697 requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader;
698 }
699
700 if (hasCompose) {
701 switch (compositionMode) {
702 case QPainter::CompositionMode_Multiply:
703 requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
704 break;
705 case QPainter::CompositionMode_Screen:
706 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
707 break;
708 case QPainter::CompositionMode_Overlay:
709 requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
710 break;
711 case QPainter::CompositionMode_Darken:
712 requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
713 break;
714 case QPainter::CompositionMode_Lighten:
715 requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
716 break;
717 case QPainter::CompositionMode_ColorDodge:
718 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
719 break;
720 case QPainter::CompositionMode_ColorBurn:
721 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
722 break;
723 case QPainter::CompositionMode_HardLight:
724 requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
725 break;
726 case QPainter::CompositionMode_SoftLight:
727 requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
728 break;
729 case QPainter::CompositionMode_Difference:
730 requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
731 break;
732 case QPainter::CompositionMode_Exclusion:
733 requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
734 break;
735 default:
736 qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
737 }
738 } else {
739 requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader;
740 }
741
742 // Choose vertex shader main function
743 if (opacityMode == AttributeOpacity) {
744 Q_ASSERT(texCoords);
745 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
746 } else if (texCoords) {
747 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
748 } else {
749 requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
750 }
751 requiredProgram.useTextureCoords = texCoords;
752 requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
753 requiredProgram.usePmvMatrix = true;
754
755 // At this point, requiredProgram is fully populated so try to find the program in the cache
756 currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
757
758 if (currentShaderProg) {
759 currentShaderProg->program->bind();
760 if (useCustomSrc)
761 customSrcStage->setUniforms(currentShaderProg->program);
762 }
763
764 // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it
765 // doesn't use are disabled)
766 QGLContextPrivate* ctx_d = ctx->d_func();
767 ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
768 ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg->useTextureCoords);
769 ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg->useOpacityAttribute);
770
771 shaderProgNeedsChanging = false;
772 return true;
773}
774
775QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.