|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtOpenGL module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qglengineshadermanager_p.h" |
|
43 #include "qglengineshadersource_p.h" |
|
44 |
|
45 #if defined(QT_DEBUG) |
|
46 #include <QMetaEnum> |
|
47 #endif |
|
48 |
|
49 |
|
50 QT_BEGIN_NAMESPACE |
|
51 |
|
52 static void qt_shared_shaders_free(void *data) |
|
53 { |
|
54 delete reinterpret_cast<QGLEngineSharedShaders *>(data); |
|
55 } |
|
56 |
|
57 Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free)) |
|
58 |
|
59 QGLEngineSharedShaders *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 |
|
69 const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = { |
|
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 |
|
76 QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) |
|
77 : ctxGuard(context) |
|
78 , blitShaderProg(0) |
|
79 , simpleShaderProg(0) |
|
80 { |
|
81 memset(compiledShaders, 0, sizeof(compiledShaders)); |
|
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 qglEngineShaderSourceCodePopulated = false; |
|
90 if (!qglEngineShaderSourceCodePopulated) { |
|
91 |
|
92 const char** code = qglEngineShaderSourceCode; // 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[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader; |
|
101 code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader; |
|
102 code[PositionWithConicalGradientBrushVertexShader] = qglslPositionWithConicalGradientBrushVertexShader; |
|
103 code[PositionWithRadialGradientBrushVertexShader] = qglslPositionWithRadialGradientBrushVertexShader; |
|
104 code[PositionWithTextureBrushVertexShader] = qglslPositionWithTextureBrushVertexShader; |
|
105 code[AffinePositionWithPatternBrushVertexShader] = qglslAffinePositionWithPatternBrushVertexShader; |
|
106 code[AffinePositionWithLinearGradientBrushVertexShader] = qglslAffinePositionWithLinearGradientBrushVertexShader; |
|
107 code[AffinePositionWithConicalGradientBrushVertexShader] = qglslAffinePositionWithConicalGradientBrushVertexShader; |
|
108 code[AffinePositionWithRadialGradientBrushVertexShader] = qglslAffinePositionWithRadialGradientBrushVertexShader; |
|
109 code[AffinePositionWithTextureBrushVertexShader] = qglslAffinePositionWithTextureBrushVertexShader; |
|
110 |
|
111 code[MainFragmentShader_CMO] = qglslMainFragmentShader_CMO; |
|
112 code[MainFragmentShader_CM] = qglslMainFragmentShader_CM; |
|
113 code[MainFragmentShader_MO] = qglslMainFragmentShader_MO; |
|
114 code[MainFragmentShader_M] = qglslMainFragmentShader_M; |
|
115 code[MainFragmentShader_CO] = qglslMainFragmentShader_CO; |
|
116 code[MainFragmentShader_C] = qglslMainFragmentShader_C; |
|
117 code[MainFragmentShader_O] = qglslMainFragmentShader_O; |
|
118 code[MainFragmentShader] = qglslMainFragmentShader; |
|
119 code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays; |
|
120 |
|
121 code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader; |
|
122 code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader; |
|
123 code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader; |
|
124 code[CustomImageSrcFragmentShader] = ""; // Supplied by app. |
|
125 code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader; |
|
126 code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader; |
|
127 code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader; |
|
128 code[PatternBrushSrcFragmentShader] = qglslPatternBrushSrcFragmentShader; |
|
129 code[LinearGradientBrushSrcFragmentShader] = qglslLinearGradientBrushSrcFragmentShader; |
|
130 code[RadialGradientBrushSrcFragmentShader] = qglslRadialGradientBrushSrcFragmentShader; |
|
131 code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader; |
|
132 code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader; |
|
133 |
|
134 code[MaskFragmentShader] = qglslMaskFragmentShader; |
|
135 code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1; |
|
136 code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2; |
|
137 code[RgbMaskWithGammaFragmentShader] = ""; //### |
|
138 |
|
139 code[MultiplyCompositionModeFragmentShader] = ""; //### |
|
140 code[ScreenCompositionModeFragmentShader] = ""; //### |
|
141 code[OverlayCompositionModeFragmentShader] = ""; //### |
|
142 code[DarkenCompositionModeFragmentShader] = ""; //### |
|
143 code[LightenCompositionModeFragmentShader] = ""; //### |
|
144 code[ColorDodgeCompositionModeFragmentShader] = ""; //### |
|
145 code[ColorBurnCompositionModeFragmentShader] = ""; //### |
|
146 code[HardLightCompositionModeFragmentShader] = ""; //### |
|
147 code[SoftLightCompositionModeFragmentShader] = ""; //### |
|
148 code[DifferenceCompositionModeFragmentShader] = ""; //### |
|
149 code[ExclusionCompositionModeFragmentShader] = ""; //### |
|
150 |
|
151 #if defined(QT_DEBUG) |
|
152 // Check that all the elements have been filled: |
|
153 for (int i = 0; i < TotalShaderCount; ++i) { |
|
154 if (qglEngineShaderSourceCode[i] == 0) { |
|
155 int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName"); |
|
156 QMetaEnum m = staticMetaObject.enumerator(enumIndex); |
|
157 |
|
158 qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i) |
|
159 << "(shader" << i << ") missing!"; |
|
160 } |
|
161 } |
|
162 #endif |
|
163 qglEngineShaderSourceCodePopulated = true; |
|
164 } |
|
165 |
|
166 // Compile up the simple shader: |
|
167 simpleShaderProg = new QGLShaderProgram(context, this); |
|
168 compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader); |
|
169 compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader); |
|
170 compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); |
|
171 compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader); |
|
172 simpleShaderProg->addShader(compiledShaders[MainVertexShader]); |
|
173 simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]); |
|
174 simpleShaderProg->addShader(compiledShaders[MainFragmentShader]); |
|
175 simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]); |
|
176 simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); |
|
177 simpleShaderProg->link(); |
|
178 if (!simpleShaderProg->isLinked()) { |
|
179 qCritical() << "Errors linking simple shader:" |
|
180 << simpleShaderProg->log(); |
|
181 } |
|
182 |
|
183 // Compile the blit shader: |
|
184 blitShaderProg = new QGLShaderProgram(context, this); |
|
185 compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader); |
|
186 compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader); |
|
187 compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader); |
|
188 compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader); |
|
189 blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]); |
|
190 blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]); |
|
191 blitShaderProg->addShader(compiledShaders[MainFragmentShader]); |
|
192 blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]); |
|
193 blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); |
|
194 blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); |
|
195 blitShaderProg->link(); |
|
196 if (!blitShaderProg->isLinked()) { |
|
197 qCritical() << "Errors linking blit shader:" |
|
198 << blitShaderProg->log(); |
|
199 } |
|
200 } |
|
201 |
|
202 void QGLEngineSharedShaders::shaderDestroyed(QObject *shader) |
|
203 { |
|
204 // Remove any shader programs which has this as the srcPixel shader: |
|
205 for (int i = 0; i < cachedPrograms.size(); ++i) { |
|
206 if (cachedPrograms.at(i).srcPixelFragShader == shader) { |
|
207 delete cachedPrograms.at(i).program; |
|
208 cachedPrograms.removeAt(i--); |
|
209 } |
|
210 } |
|
211 |
|
212 emit shaderProgNeedsChanging(); |
|
213 } |
|
214 |
|
215 QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader::ShaderType type) |
|
216 { |
|
217 Q_ASSERT(name != CustomImageSrcFragmentShader); |
|
218 Q_ASSERT(name < InvalidShaderName); |
|
219 |
|
220 if (compiledShaders[name]) |
|
221 return compiledShaders[name]; |
|
222 |
|
223 QByteArray source = qglEngineShaderSourceCode[name]; |
|
224 QGLShader *newShader = new QGLShader(type, ctxGuard.context(), this); |
|
225 newShader->compile(source); |
|
226 |
|
227 #if defined(QT_DEBUG) |
|
228 // Name the shader for easier debugging |
|
229 QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); |
|
230 newShader->setObjectName(QLatin1String(m.valueToKey(name))); |
|
231 #endif |
|
232 |
|
233 compiledShaders[name] = newShader; |
|
234 return newShader; |
|
235 } |
|
236 |
|
237 QGLShader *QGLEngineSharedShaders::compileCustomShader(QGLCustomShaderStage *stage, QGLShader::ShaderType type) |
|
238 { |
|
239 QByteArray source = stage->source(); |
|
240 source += qglslCustomSrcFragmentShader; |
|
241 |
|
242 QGLShader *newShader = customShaderCache.object(source); |
|
243 if (newShader) |
|
244 return newShader; |
|
245 |
|
246 newShader = new QGLShader(type, ctxGuard.context(), this); |
|
247 newShader->compile(source); |
|
248 customShaderCache.insert(source, newShader); |
|
249 |
|
250 connect(newShader, SIGNAL(destroyed(QObject *)), |
|
251 this, SLOT(shaderDestroyed(QObject *))); |
|
252 |
|
253 #if defined(QT_DEBUG) |
|
254 // Name the shader for easier debugging |
|
255 QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName")); |
|
256 newShader->setObjectName(QLatin1String(m.valueToKey(CustomImageSrcFragmentShader))); |
|
257 #endif |
|
258 |
|
259 return newShader; |
|
260 } |
|
261 |
|
262 // The address returned here will only be valid until next time this function is called. |
|
263 QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog) |
|
264 { |
|
265 for (int i = 0; i < cachedPrograms.size(); ++i) { |
|
266 if (cachedPrograms[i] == prog) |
|
267 return &cachedPrograms[i]; |
|
268 } |
|
269 |
|
270 cachedPrograms.append(prog); |
|
271 QGLEngineShaderProg &cached = cachedPrograms.last(); |
|
272 |
|
273 // If the shader program's not found in the cache, create it now. |
|
274 cached.program = new QGLShaderProgram(ctxGuard.context(), this); |
|
275 cached.program->addShader(cached.mainVertexShader); |
|
276 cached.program->addShader(cached.positionVertexShader); |
|
277 cached.program->addShader(cached.mainFragShader); |
|
278 cached.program->addShader(cached.srcPixelFragShader); |
|
279 cached.program->addShader(cached.maskFragShader); |
|
280 cached.program->addShader(cached.compositionFragShader); |
|
281 |
|
282 // We have to bind the vertex attribute names before the program is linked: |
|
283 cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); |
|
284 if (cached.useTextureCoords) |
|
285 cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); |
|
286 if (cached.useOpacityAttribute) |
|
287 cached.program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); |
|
288 |
|
289 cached.program->link(); |
|
290 if (!cached.program->isLinked()) { |
|
291 QLatin1String none("none"); |
|
292 QLatin1String br("\n"); |
|
293 QString error; |
|
294 error = QLatin1String("Shader program failed to link,") |
|
295 #if defined(QT_DEBUG) |
|
296 + br |
|
297 + QLatin1String(" Shaders Used:\n") |
|
298 + QLatin1String(" mainVertexShader = ") |
|
299 + (cached.mainVertexShader ? |
|
300 cached.mainVertexShader->objectName() : none) + br |
|
301 + QLatin1String(" positionVertexShader = ") |
|
302 + (cached.positionVertexShader ? |
|
303 cached.positionVertexShader->objectName() : none) + br |
|
304 + QLatin1String(" mainFragShader = ") |
|
305 + (cached.mainFragShader ? |
|
306 cached.mainFragShader->objectName() : none) + br |
|
307 + QLatin1String(" srcPixelFragShader = ") |
|
308 + (cached.srcPixelFragShader ? |
|
309 cached.srcPixelFragShader->objectName() : none) + br |
|
310 + QLatin1String(" maskFragShader = ") |
|
311 + (cached.maskFragShader ? |
|
312 cached.maskFragShader->objectName() : none) + br |
|
313 + QLatin1String(" compositionFragShader = ") |
|
314 + (cached.compositionFragShader ? |
|
315 cached.compositionFragShader->objectName() : none) + br |
|
316 #endif |
|
317 + QLatin1String(" Error Log:\n") |
|
318 + QLatin1String(" ") + cached.program->log(); |
|
319 qWarning() << error; |
|
320 delete cached.program; |
|
321 cachedPrograms.removeLast(); |
|
322 return 0; |
|
323 } else { |
|
324 // taking the address here is safe since |
|
325 // cachePrograms isn't resized anywhere else |
|
326 return &cached; |
|
327 } |
|
328 } |
|
329 |
|
330 QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) |
|
331 : ctx(context), |
|
332 shaderProgNeedsChanging(true), |
|
333 srcPixelType(Qt::NoBrush), |
|
334 opacityMode(NoOpacity), |
|
335 maskType(NoMask), |
|
336 compositionMode(QPainter::CompositionMode_SourceOver), |
|
337 customSrcStage(0), |
|
338 currentShaderProg(0), |
|
339 customShader(0) |
|
340 { |
|
341 sharedShaders = QGLEngineSharedShaders::shadersForContext(context); |
|
342 connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot())); |
|
343 } |
|
344 |
|
345 QGLEngineShaderManager::~QGLEngineShaderManager() |
|
346 { |
|
347 //### |
|
348 } |
|
349 |
|
350 uint QGLEngineShaderManager::getUniformLocation(Uniform id) |
|
351 { |
|
352 QVector<uint> &uniformLocations = currentShaderProg->uniformLocations; |
|
353 if (uniformLocations.isEmpty()) |
|
354 uniformLocations.fill(GLuint(-1), NumUniforms); |
|
355 |
|
356 static const char *uniformNames[] = { |
|
357 "imageTexture", |
|
358 "patternColor", |
|
359 "globalOpacity", |
|
360 "depth", |
|
361 "pmvMatrix", |
|
362 "maskTexture", |
|
363 "fragmentColor", |
|
364 "linearData", |
|
365 "angle", |
|
366 "halfViewportSize", |
|
367 "fmp", |
|
368 "fmp2_m_radius2", |
|
369 "inverse_2_fmp2_m_radius2", |
|
370 "invertedTextureSize", |
|
371 "brushTransform", |
|
372 "brushTexture" |
|
373 }; |
|
374 |
|
375 if (uniformLocations.at(id) == GLuint(-1)) |
|
376 uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]); |
|
377 |
|
378 return uniformLocations.at(id); |
|
379 } |
|
380 |
|
381 |
|
382 void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform) |
|
383 { |
|
384 Q_UNUSED(transform); // Currently ignored |
|
385 } |
|
386 |
|
387 void QGLEngineShaderManager::setDirty() |
|
388 { |
|
389 shaderProgNeedsChanging = true; |
|
390 } |
|
391 |
|
392 void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) |
|
393 { |
|
394 if (srcPixelType == PixelSrcType(style)) |
|
395 return; |
|
396 |
|
397 srcPixelType = style; |
|
398 shaderProgNeedsChanging = true; //### |
|
399 } |
|
400 |
|
401 void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type) |
|
402 { |
|
403 if (srcPixelType == type) |
|
404 return; |
|
405 |
|
406 srcPixelType = type; |
|
407 shaderProgNeedsChanging = true; //### |
|
408 } |
|
409 |
|
410 void QGLEngineShaderManager::setOpacityMode(OpacityMode mode) |
|
411 { |
|
412 if (opacityMode == mode) |
|
413 return; |
|
414 |
|
415 opacityMode = mode; |
|
416 shaderProgNeedsChanging = true; //### |
|
417 } |
|
418 |
|
419 void QGLEngineShaderManager::setMaskType(MaskType type) |
|
420 { |
|
421 if (maskType == type) |
|
422 return; |
|
423 |
|
424 maskType = type; |
|
425 shaderProgNeedsChanging = true; //### |
|
426 } |
|
427 |
|
428 void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) |
|
429 { |
|
430 if (compositionMode == mode) |
|
431 return; |
|
432 |
|
433 compositionMode = mode; |
|
434 shaderProgNeedsChanging = true; //### |
|
435 } |
|
436 |
|
437 void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage) |
|
438 { |
|
439 customSrcStage = stage; |
|
440 customShader = 0; // Will be compiled from 'customSrcStage' later. |
|
441 shaderProgNeedsChanging = true; |
|
442 } |
|
443 |
|
444 void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage) |
|
445 { |
|
446 Q_UNUSED(stage); // Currently we only support one at a time... |
|
447 |
|
448 customSrcStage = 0; |
|
449 customShader = 0; |
|
450 shaderProgNeedsChanging = true; |
|
451 } |
|
452 |
|
453 |
|
454 QGLShaderProgram* QGLEngineShaderManager::currentProgram() |
|
455 { |
|
456 return currentShaderProg->program; |
|
457 } |
|
458 |
|
459 QGLShaderProgram* QGLEngineShaderManager::simpleProgram() |
|
460 { |
|
461 return sharedShaders->simpleProgram(); |
|
462 } |
|
463 |
|
464 QGLShaderProgram* QGLEngineShaderManager::blitProgram() |
|
465 { |
|
466 return sharedShaders->blitProgram(); |
|
467 } |
|
468 |
|
469 |
|
470 |
|
471 // Select & use the correct shader program using the current state. |
|
472 // Returns true if program needed changing. |
|
473 bool QGLEngineShaderManager::useCorrectShaderProg() |
|
474 { |
|
475 if (!shaderProgNeedsChanging) |
|
476 return false; |
|
477 |
|
478 bool useCustomSrc = customSrcStage != 0; |
|
479 if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc) { |
|
480 useCustomSrc = false; |
|
481 qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src"); |
|
482 } |
|
483 |
|
484 QGLEngineShaderProg requiredProgram; |
|
485 requiredProgram.program = 0; |
|
486 |
|
487 bool texCoords = false; |
|
488 |
|
489 // Choose vertex shader shader position function (which typically also sets |
|
490 // varyings) and the source pixel (srcPixel) fragment shader function: |
|
491 QGLEngineSharedShaders::ShaderName positionVertexShaderName = QGLEngineSharedShaders::InvalidShaderName; |
|
492 QGLEngineSharedShaders::ShaderName srcPixelFragShaderName = QGLEngineSharedShaders::InvalidShaderName; |
|
493 bool isAffine = brushTransform.isAffine(); |
|
494 if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { |
|
495 if (isAffine) |
|
496 positionVertexShaderName = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader; |
|
497 else |
|
498 positionVertexShaderName = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader; |
|
499 |
|
500 srcPixelFragShaderName = QGLEngineSharedShaders::PatternBrushSrcFragmentShader; |
|
501 } |
|
502 else switch (srcPixelType) { |
|
503 default: |
|
504 case Qt::NoBrush: |
|
505 qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set"); |
|
506 break; |
|
507 case QGLEngineShaderManager::ImageSrc: |
|
508 srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcFragmentShader; |
|
509 positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; |
|
510 texCoords = true; |
|
511 break; |
|
512 case QGLEngineShaderManager::NonPremultipliedImageSrc: |
|
513 srcPixelFragShaderName = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; |
|
514 positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; |
|
515 texCoords = true; |
|
516 break; |
|
517 case QGLEngineShaderManager::PatternSrc: |
|
518 srcPixelFragShaderName = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; |
|
519 positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; |
|
520 texCoords = true; |
|
521 break; |
|
522 case QGLEngineShaderManager::TextureSrcWithPattern: |
|
523 srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; |
|
524 positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader |
|
525 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader; |
|
526 break; |
|
527 case Qt::SolidPattern: |
|
528 srcPixelFragShaderName = QGLEngineSharedShaders::SolidBrushSrcFragmentShader; |
|
529 positionVertexShaderName = QGLEngineSharedShaders::PositionOnlyVertexShader; |
|
530 break; |
|
531 case Qt::LinearGradientPattern: |
|
532 srcPixelFragShaderName = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; |
|
533 positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader |
|
534 : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader; |
|
535 break; |
|
536 case Qt::ConicalGradientPattern: |
|
537 srcPixelFragShaderName = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; |
|
538 positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader |
|
539 : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader; |
|
540 break; |
|
541 case Qt::RadialGradientPattern: |
|
542 srcPixelFragShaderName = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; |
|
543 positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader |
|
544 : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader; |
|
545 break; |
|
546 case Qt::TexturePattern: |
|
547 srcPixelFragShaderName = QGLEngineSharedShaders::TextureBrushSrcFragmentShader; |
|
548 positionVertexShaderName = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader |
|
549 : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader; |
|
550 break; |
|
551 }; |
|
552 requiredProgram.positionVertexShader = sharedShaders->compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader); |
|
553 if (useCustomSrc) { |
|
554 if (!customShader) |
|
555 customShader = sharedShaders->compileCustomShader(customSrcStage, QGLShader::PartialFragmentShader); |
|
556 requiredProgram.srcPixelFragShader = customShader; |
|
557 } else { |
|
558 requiredProgram.srcPixelFragShader = sharedShaders->compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader); |
|
559 } |
|
560 |
|
561 const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; |
|
562 const bool hasMask = maskType != QGLEngineShaderManager::NoMask; |
|
563 |
|
564 // Choose fragment shader main function: |
|
565 QGLEngineSharedShaders::ShaderName mainFragShaderName; |
|
566 |
|
567 if (opacityMode == AttributeOpacity) { |
|
568 Q_ASSERT(!hasCompose && !hasMask); |
|
569 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_ImageArrays; |
|
570 } else { |
|
571 bool useGlobalOpacity = (opacityMode == UniformOpacity); |
|
572 if (hasCompose && hasMask && useGlobalOpacity) |
|
573 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO; |
|
574 if (hasCompose && hasMask && !useGlobalOpacity) |
|
575 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM; |
|
576 if (!hasCompose && hasMask && useGlobalOpacity) |
|
577 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO; |
|
578 if (!hasCompose && hasMask && !useGlobalOpacity) |
|
579 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M; |
|
580 if (hasCompose && !hasMask && useGlobalOpacity) |
|
581 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO; |
|
582 if (hasCompose && !hasMask && !useGlobalOpacity) |
|
583 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C; |
|
584 if (!hasCompose && !hasMask && useGlobalOpacity) |
|
585 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O; |
|
586 if (!hasCompose && !hasMask && !useGlobalOpacity) |
|
587 mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader; |
|
588 } |
|
589 |
|
590 requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); |
|
591 |
|
592 if (hasMask) { |
|
593 QGLEngineSharedShaders::ShaderName maskShaderName = QGLEngineSharedShaders::InvalidShaderName; |
|
594 if (maskType == PixelMask) { |
|
595 maskShaderName = QGLEngineSharedShaders::MaskFragmentShader; |
|
596 texCoords = true; |
|
597 } else if (maskType == SubPixelMaskPass1) { |
|
598 maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1; |
|
599 texCoords = true; |
|
600 } else if (maskType == SubPixelMaskPass2) { |
|
601 maskShaderName = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2; |
|
602 texCoords = true; |
|
603 } else if (maskType == SubPixelWithGammaMask) { |
|
604 maskShaderName = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; |
|
605 texCoords = true; |
|
606 } else { |
|
607 qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); |
|
608 } |
|
609 |
|
610 requiredProgram.maskFragShader = sharedShaders->compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader); |
|
611 } else { |
|
612 requiredProgram.maskFragShader = 0; |
|
613 } |
|
614 |
|
615 if (hasCompose) { |
|
616 QGLEngineSharedShaders::ShaderName compositionShaderName = QGLEngineSharedShaders::InvalidShaderName; |
|
617 switch (compositionMode) { |
|
618 case QPainter::CompositionMode_Multiply: |
|
619 compositionShaderName = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader; |
|
620 break; |
|
621 case QPainter::CompositionMode_Screen: |
|
622 compositionShaderName = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader; |
|
623 break; |
|
624 case QPainter::CompositionMode_Overlay: |
|
625 compositionShaderName = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader; |
|
626 break; |
|
627 case QPainter::CompositionMode_Darken: |
|
628 compositionShaderName = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader; |
|
629 break; |
|
630 case QPainter::CompositionMode_Lighten: |
|
631 compositionShaderName = QGLEngineSharedShaders::LightenCompositionModeFragmentShader; |
|
632 break; |
|
633 case QPainter::CompositionMode_ColorDodge: |
|
634 compositionShaderName = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader; |
|
635 break; |
|
636 case QPainter::CompositionMode_ColorBurn: |
|
637 compositionShaderName = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader; |
|
638 break; |
|
639 case QPainter::CompositionMode_HardLight: |
|
640 compositionShaderName = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader; |
|
641 break; |
|
642 case QPainter::CompositionMode_SoftLight: |
|
643 compositionShaderName = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader; |
|
644 break; |
|
645 case QPainter::CompositionMode_Difference: |
|
646 compositionShaderName = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader; |
|
647 break; |
|
648 case QPainter::CompositionMode_Exclusion: |
|
649 compositionShaderName = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader; |
|
650 break; |
|
651 default: |
|
652 qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); |
|
653 } |
|
654 requiredProgram.compositionFragShader = sharedShaders->compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader); |
|
655 } else { |
|
656 requiredProgram.compositionFragShader = 0; |
|
657 } |
|
658 |
|
659 // Choose vertex shader main function |
|
660 QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName; |
|
661 if (opacityMode == AttributeOpacity) { |
|
662 Q_ASSERT(texCoords); |
|
663 mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; |
|
664 } else if (texCoords) { |
|
665 mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader; |
|
666 } else { |
|
667 mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader; |
|
668 } |
|
669 requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); |
|
670 requiredProgram.useTextureCoords = texCoords; |
|
671 requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity); |
|
672 |
|
673 |
|
674 // At this point, requiredProgram is fully populated so try to find the program in the cache |
|
675 currentShaderProg = sharedShaders->findProgramInCache(requiredProgram); |
|
676 |
|
677 if (currentShaderProg) { |
|
678 currentShaderProg->program->enable(); |
|
679 if (useCustomSrc) |
|
680 customSrcStage->setUniforms(currentShaderProg->program); |
|
681 } |
|
682 |
|
683 shaderProgNeedsChanging = false; |
|
684 return true; |
|
685 } |
|
686 |
|
687 QT_END_NAMESPACE |