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

Last change on this file since 1023 was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

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