1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qopenglshaderprogram.h" |
41 | #include "qopenglprogrambinarycache_p.h" |
42 | #include "qopenglextrafunctions.h" |
43 | #include "private/qopenglcontext_p.h" |
44 | #include <QtCore/private/qobject_p.h> |
45 | #include <QtCore/qdebug.h> |
46 | #include <QtCore/qfile.h> |
47 | #include <QtCore/qvarlengtharray.h> |
48 | #include <QtCore/qvector.h> |
49 | #include <QtCore/qloggingcategory.h> |
50 | #include <QtCore/qcryptographichash.h> |
51 | #include <QtCore/qcoreapplication.h> |
52 | #include <QtGui/qtransform.h> |
53 | #include <QtGui/QColor> |
54 | #include <QtGui/QSurfaceFormat> |
55 | |
56 | #if !defined(QT_OPENGL_ES_2) |
57 | #include <QtGui/qopenglfunctions_4_0_core.h> |
58 | #endif |
59 | |
60 | #include <algorithm> |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | /*! |
65 | \class QOpenGLShaderProgram |
66 | \brief The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used. |
67 | \since 5.0 |
68 | \ingroup painting-3D |
69 | \inmodule QtGui |
70 | |
71 | \section1 Introduction |
72 | |
73 | This class supports shader programs written in the OpenGL Shading |
74 | Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). |
75 | |
76 | QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of |
77 | compiling and linking vertex and fragment shaders. |
78 | |
79 | The following example creates a vertex shader program using the |
80 | supplied source \c{code}. Once compiled and linked, the shader |
81 | program is activated in the current QOpenGLContext by calling |
82 | QOpenGLShaderProgram::bind(): |
83 | |
84 | \snippet code/src_gui_qopenglshaderprogram.cpp 0 |
85 | |
86 | \section1 Writing Portable Shaders |
87 | |
88 | Shader programs can be difficult to reuse across OpenGL implementations |
89 | because of varying levels of support for standard vertex attributes and |
90 | uniform variables. In particular, GLSL/ES lacks all of the |
91 | standard variables that are present on desktop OpenGL systems: |
92 | \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL |
93 | lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. |
94 | |
95 | The QOpenGLShaderProgram class makes the process of writing portable shaders |
96 | easier by prefixing all shader programs with the following lines on |
97 | desktop OpenGL: |
98 | |
99 | \code |
100 | #define highp |
101 | #define mediump |
102 | #define lowp |
103 | \endcode |
104 | |
105 | This makes it possible to run most GLSL/ES shader programs |
106 | on desktop systems. The programmer should restrict themselves |
107 | to just features that are present in GLSL/ES, and avoid |
108 | standard variable names that only work on the desktop. |
109 | |
110 | \section1 Simple Shader Example |
111 | |
112 | \snippet code/src_gui_qopenglshaderprogram.cpp 1 |
113 | |
114 | With the above shader program active, we can draw a green triangle |
115 | as follows: |
116 | |
117 | \snippet code/src_gui_qopenglshaderprogram.cpp 2 |
118 | |
119 | \section1 Binary Shaders and Programs |
120 | |
121 | Binary shaders may be specified using \c{glShaderBinary()} on |
122 | the return value from QOpenGLShader::shaderId(). The QOpenGLShader instance |
123 | containing the binary can then be added to the shader program with |
124 | addShader() and linked in the usual fashion with link(). |
125 | |
126 | Binary programs may be specified using \c{glProgramBinaryOES()} |
127 | on the return value from programId(). Then the application should |
128 | call link(), which will notice that the program has already been |
129 | specified and linked, allowing other operations to be performed |
130 | on the shader program. The shader program's id can be explicitly |
131 | created using the create() function. |
132 | |
133 | \section2 Caching Program Binaries |
134 | |
135 | As of Qt 5.9, support for caching program binaries on disk is built in. To |
136 | enable this, switch to using addCacheableShaderFromSourceCode() and |
137 | addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support |
138 | for \c{GL_ARB_get_program_binary}, this will transparently cache program |
139 | binaries under QStandardPaths::GenericCacheLocation or |
140 | QStandardPaths::CacheLocation. When support is not available, calling the |
141 | cacheable function variants is equivalent to the normal ones. |
142 | |
143 | \note Some drivers do not have any binary formats available, even though |
144 | they advertise the extension or offer OpenGL ES 3.0. In this case program |
145 | binary support will be disabled. |
146 | |
147 | \sa QOpenGLShader |
148 | */ |
149 | |
150 | /*! |
151 | \class QOpenGLShader |
152 | \brief The QOpenGLShader class allows OpenGL shaders to be compiled. |
153 | \since 5.0 |
154 | \ingroup painting-3D |
155 | \inmodule QtGui |
156 | |
157 | This class supports shaders written in the OpenGL Shading Language (GLSL) |
158 | and in the OpenGL/ES Shading Language (GLSL/ES). |
159 | |
160 | QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of |
161 | compiling and linking vertex and fragment shaders. |
162 | |
163 | \sa QOpenGLShaderProgram |
164 | */ |
165 | |
166 | /*! |
167 | \enum QOpenGLShader::ShaderTypeBit |
168 | This enum specifies the type of QOpenGLShader that is being created. |
169 | |
170 | \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). |
171 | \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). |
172 | \value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL) |
173 | (requires OpenGL >= 3.2 or OpenGL ES >= 3.2). |
174 | \value TessellationControl Tessellation control shaders written in the OpenGL |
175 | shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). |
176 | \value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL |
177 | shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). |
178 | \value Compute Compute shaders written in the OpenGL shading language (GLSL) |
179 | (requires OpenGL >= 4.3 or OpenGL ES >= 3.1). |
180 | */ |
181 | |
182 | Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache" ) |
183 | |
184 | // For GLES 3.1/3.2 |
185 | #ifndef GL_GEOMETRY_SHADER |
186 | #define GL_GEOMETRY_SHADER 0x8DD9 |
187 | #endif |
188 | #ifndef GL_TESS_CONTROL_SHADER |
189 | #define GL_TESS_CONTROL_SHADER 0x8E88 |
190 | #endif |
191 | #ifndef GL_TESS_EVALUATION_SHADER |
192 | #define GL_TESS_EVALUATION_SHADER 0x8E87 |
193 | #endif |
194 | #ifndef GL_COMPUTE_SHADER |
195 | #define GL_COMPUTE_SHADER 0x91B9 |
196 | #endif |
197 | #ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES |
198 | #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 |
199 | #endif |
200 | #ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS |
201 | #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 |
202 | #endif |
203 | #ifndef GL_PATCH_VERTICES |
204 | #define GL_PATCH_VERTICES 0x8E72 |
205 | #endif |
206 | #ifndef GL_PATCH_DEFAULT_OUTER_LEVEL |
207 | #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 |
208 | #endif |
209 | #ifndef GL_PATCH_DEFAULT_INNER_LEVEL |
210 | #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 |
211 | #endif |
212 | |
213 | #ifndef GL_NUM_PROGRAM_BINARY_FORMATS |
214 | #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE |
215 | #endif |
216 | |
217 | #ifndef QT_OPENGL_ES_2 |
218 | static inline bool isFormatGLES(const QSurfaceFormat &f) |
219 | { |
220 | return (f.renderableType() == QSurfaceFormat::OpenGLES); |
221 | } |
222 | #endif |
223 | |
224 | static inline bool supportsGeometry(const QSurfaceFormat &f) |
225 | { |
226 | return f.version() >= qMakePair(3, 2); |
227 | } |
228 | |
229 | static inline bool supportsCompute(const QSurfaceFormat &f) |
230 | { |
231 | #ifndef QT_OPENGL_ES_2 |
232 | if (!isFormatGLES(f)) |
233 | return f.version() >= qMakePair(4, 3); |
234 | else |
235 | return f.version() >= qMakePair(3, 1); |
236 | #else |
237 | return f.version() >= qMakePair(3, 1); |
238 | #endif |
239 | } |
240 | |
241 | static inline bool supportsTessellation(const QSurfaceFormat &f) |
242 | { |
243 | #ifndef QT_OPENGL_ES_2 |
244 | if (!isFormatGLES(f)) |
245 | return f.version() >= qMakePair(4, 0); |
246 | else |
247 | return f.version() >= qMakePair(3, 2); |
248 | #else |
249 | return f.version() >= qMakePair(3, 2); |
250 | #endif |
251 | } |
252 | |
253 | class QOpenGLShaderPrivate : public QObjectPrivate |
254 | { |
255 | Q_DECLARE_PUBLIC(QOpenGLShader) |
256 | public: |
257 | QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type) |
258 | : shaderGuard(0) |
259 | , shaderType(type) |
260 | , compiled(false) |
261 | , glfuncs(new QOpenGLExtraFunctions(ctx)) |
262 | , supportsGeometryShaders(false) |
263 | , supportsTessellationShaders(false) |
264 | , supportsComputeShaders(false) |
265 | { |
266 | if (shaderType & QOpenGLShader::Geometry) |
267 | supportsGeometryShaders = supportsGeometry(ctx->format()); |
268 | else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) |
269 | supportsTessellationShaders = supportsTessellation(ctx->format()); |
270 | else if (shaderType & QOpenGLShader::Compute) |
271 | supportsComputeShaders = supportsCompute(ctx->format()); |
272 | } |
273 | ~QOpenGLShaderPrivate(); |
274 | |
275 | QOpenGLSharedResourceGuard *shaderGuard; |
276 | QOpenGLShader::ShaderType shaderType; |
277 | bool compiled; |
278 | QString log; |
279 | |
280 | QOpenGLExtraFunctions *glfuncs; |
281 | |
282 | // Support for geometry shaders |
283 | bool supportsGeometryShaders; |
284 | // Support for tessellation shaders |
285 | bool supportsTessellationShaders; |
286 | // Support for compute shaders |
287 | bool supportsComputeShaders; |
288 | |
289 | |
290 | bool create(); |
291 | bool compile(QOpenGLShader *q); |
292 | void deleteShader(); |
293 | }; |
294 | |
295 | namespace { |
296 | void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id) |
297 | { |
298 | funcs->glDeleteShader(id); |
299 | } |
300 | } |
301 | |
302 | QOpenGLShaderPrivate::~QOpenGLShaderPrivate() |
303 | { |
304 | delete glfuncs; |
305 | if (shaderGuard) |
306 | shaderGuard->free(); |
307 | } |
308 | |
309 | bool QOpenGLShaderPrivate::create() |
310 | { |
311 | QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); |
312 | if (!context) |
313 | return false; |
314 | GLuint shader = 0; |
315 | if (shaderType == QOpenGLShader::Vertex) { |
316 | shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); |
317 | } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { |
318 | shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); |
319 | } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { |
320 | shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); |
321 | } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { |
322 | shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); |
323 | } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { |
324 | shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); |
325 | } else if (shaderType == QOpenGLShader::Fragment) { |
326 | shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); |
327 | } |
328 | if (!shader) { |
329 | qWarning("QOpenGLShader: could not create shader" ); |
330 | return false; |
331 | } |
332 | shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc); |
333 | return true; |
334 | } |
335 | |
336 | bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) |
337 | { |
338 | GLuint shader = shaderGuard ? shaderGuard->id() : 0; |
339 | if (!shader) |
340 | return false; |
341 | |
342 | // Try to compile shader |
343 | glfuncs->glCompileShader(shader); |
344 | GLint value = 0; |
345 | |
346 | // Get compilation status |
347 | glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value); |
348 | compiled = (value != 0); |
349 | |
350 | if (!compiled) { |
351 | // Compilation failed, try to provide some information about the failure |
352 | QString name = q->objectName(); |
353 | |
354 | const char *types[] = { |
355 | "Fragment" , |
356 | "Vertex" , |
357 | "Geometry" , |
358 | "Tessellation Control" , |
359 | "Tessellation Evaluation" , |
360 | "Compute" , |
361 | "" |
362 | }; |
363 | |
364 | const char *type = types[6]; |
365 | switch (shaderType) { |
366 | case QOpenGLShader::Fragment: |
367 | type = types[0]; break; |
368 | case QOpenGLShader::Vertex: |
369 | type = types[1]; break; |
370 | case QOpenGLShader::Geometry: |
371 | type = types[2]; break; |
372 | case QOpenGLShader::TessellationControl: |
373 | type = types[3]; break; |
374 | case QOpenGLShader::TessellationEvaluation: |
375 | type = types[4]; break; |
376 | case QOpenGLShader::Compute: |
377 | type = types[5]; break; |
378 | } |
379 | |
380 | // Get info and source code lengths |
381 | GLint infoLogLength = 0; |
382 | GLint sourceCodeLength = 0; |
383 | char *logBuffer = 0; |
384 | char *sourceCodeBuffer = 0; |
385 | |
386 | // Get the compilation info log |
387 | glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); |
388 | |
389 | if (infoLogLength > 1) { |
390 | GLint temp; |
391 | logBuffer = new char [infoLogLength]; |
392 | glfuncs->glGetShaderInfoLog(shader, infoLogLength, &temp, logBuffer); |
393 | } |
394 | |
395 | // Get the source code |
396 | glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceCodeLength); |
397 | |
398 | if (sourceCodeLength > 1) { |
399 | GLint temp; |
400 | sourceCodeBuffer = new char [sourceCodeLength]; |
401 | glfuncs->glGetShaderSource(shader, sourceCodeLength, &temp, sourceCodeBuffer); |
402 | } |
403 | |
404 | if (logBuffer) |
405 | log = QString::fromLatin1(logBuffer); |
406 | else |
407 | log = QLatin1String("failed" ); |
408 | |
409 | if (name.isEmpty()) |
410 | qWarning("QOpenGLShader::compile(%s): %s" , type, qPrintable(log)); |
411 | else |
412 | qWarning("QOpenGLShader::compile(%s)[%s]: %s" , type, qPrintable(name), qPrintable(log)); |
413 | |
414 | // Dump the source code if we got it |
415 | if (sourceCodeBuffer) { |
416 | qWarning("*** Problematic %s shader source code ***\n" |
417 | "%ls\n" |
418 | "***" , |
419 | type, qUtf16Printable(QString::fromLatin1(sourceCodeBuffer))); |
420 | } |
421 | |
422 | // Cleanup |
423 | delete [] logBuffer; |
424 | delete [] sourceCodeBuffer; |
425 | } |
426 | |
427 | return compiled; |
428 | } |
429 | |
430 | void QOpenGLShaderPrivate::deleteShader() |
431 | { |
432 | if (shaderGuard) { |
433 | shaderGuard->free(); |
434 | shaderGuard = 0; |
435 | } |
436 | } |
437 | |
438 | /*! |
439 | Constructs a new QOpenGLShader object of the specified \a type |
440 | and attaches it to \a parent. If shader programs are not supported, |
441 | QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false. |
442 | |
443 | This constructor is normally followed by a call to compileSourceCode() |
444 | or compileSourceFile(). |
445 | |
446 | The shader will be associated with the current QOpenGLContext. |
447 | |
448 | \sa compileSourceCode(), compileSourceFile() |
449 | */ |
450 | QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent) |
451 | : QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent) |
452 | { |
453 | Q_D(QOpenGLShader); |
454 | d->create(); |
455 | } |
456 | |
457 | /*! |
458 | Deletes this shader. If the shader has been attached to a |
459 | QOpenGLShaderProgram object, then the actual shader will stay around |
460 | until the QOpenGLShaderProgram is destroyed. |
461 | */ |
462 | QOpenGLShader::~QOpenGLShader() |
463 | { |
464 | } |
465 | |
466 | /*! |
467 | Returns the type of this shader. |
468 | */ |
469 | QOpenGLShader::ShaderType QOpenGLShader::shaderType() const |
470 | { |
471 | Q_D(const QOpenGLShader); |
472 | return d->shaderType; |
473 | } |
474 | |
475 | static const char qualifierDefines[] = |
476 | "#define lowp\n" |
477 | "#define mediump\n" |
478 | "#define highp\n" ; |
479 | |
480 | #if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES) |
481 | // The "highp" qualifier doesn't exist in fragment shaders |
482 | // on all ES platforms. When it doesn't exist, use "mediump". |
483 | #define QOpenGL_REDEFINE_HIGHP 1 |
484 | static const char redefineHighp[] = |
485 | "#ifndef GL_FRAGMENT_PRECISION_HIGH\n" |
486 | "#define highp mediump\n" |
487 | "#endif\n" ; |
488 | #endif |
489 | |
490 | // Boiler-plate header to have the layout attributes available we need later |
491 | static const char [] = |
492 | "#ifdef GL_KHR_blend_equation_advanced\n" |
493 | "#extension GL_ARB_fragment_coord_conventions : enable\n" |
494 | "#extension GL_KHR_blend_equation_advanced : enable\n" |
495 | "#endif\n" ; |
496 | |
497 | struct QVersionDirectivePosition |
498 | { |
499 | Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) |
500 | : position(position) |
501 | , line(line) |
502 | { |
503 | } |
504 | |
505 | Q_DECL_CONSTEXPR bool hasPosition() const |
506 | { |
507 | return position > 0; |
508 | } |
509 | |
510 | const int position; |
511 | const int line; |
512 | }; |
513 | |
514 | static QVersionDirectivePosition findVersionDirectivePosition(const char *source) |
515 | { |
516 | Q_ASSERT(source); |
517 | |
518 | // According to the GLSL spec the #version directive must not be |
519 | // preceded by anything but whitespace and comments. |
520 | // In order to not get confused by #version directives within a |
521 | // multiline comment, we need to do some minimal comment parsing |
522 | // while searching for the directive. |
523 | enum { |
524 | Normal, |
525 | StartOfLine, |
526 | PreprocessorDirective, |
527 | , |
528 | , |
529 | , |
530 | |
531 | } state = StartOfLine; |
532 | |
533 | const char *c = source; |
534 | while (*c) { |
535 | switch (state) { |
536 | case PreprocessorDirective: |
537 | if (*c == ' ' || *c == '\t') |
538 | break; |
539 | if (!strncmp(c, "version" , strlen("version" ))) { |
540 | // Found version directive |
541 | c += strlen("version" ); |
542 | while (*c && *c != '\n') |
543 | ++c; |
544 | int splitPosition = c - source + 1; |
545 | int linePosition = int(std::count(source, c, '\n')) + 1; |
546 | return QVersionDirectivePosition(splitPosition, linePosition); |
547 | } else if (*c == '/') |
548 | state = CommentStarting; |
549 | else if (*c == '\n') |
550 | state = StartOfLine; |
551 | else |
552 | state = Normal; |
553 | break; |
554 | case StartOfLine: |
555 | if (*c == ' ' || *c == '\t') |
556 | break; |
557 | else if (*c == '#') { |
558 | state = PreprocessorDirective; |
559 | break; |
560 | } |
561 | state = Normal; |
562 | Q_FALLTHROUGH(); |
563 | case Normal: |
564 | if (*c == '/') |
565 | state = CommentStarting; |
566 | else if (*c == '\n') |
567 | state = StartOfLine; |
568 | break; |
569 | case CommentStarting: |
570 | if (*c == '*') |
571 | state = MultiLineComment; |
572 | else if (*c == '/') |
573 | state = SingleLineComment; |
574 | else |
575 | state = Normal; |
576 | break; |
577 | case MultiLineComment: |
578 | if (*c == '*') |
579 | state = CommentEnding; |
580 | break; |
581 | case SingleLineComment: |
582 | if (*c == '\n') |
583 | state = Normal; |
584 | break; |
585 | case CommentEnding: |
586 | if (*c == '/') |
587 | state = Normal; |
588 | else if (*c != QLatin1Char('*')) |
589 | state = MultiLineComment; |
590 | break; |
591 | } |
592 | ++c; |
593 | } |
594 | |
595 | return QVersionDirectivePosition(0, 1); |
596 | } |
597 | |
598 | /*! |
599 | Sets the \a source code for this shader and compiles it. |
600 | Returns \c true if the source was successfully compiled, false otherwise. |
601 | |
602 | \sa compileSourceFile() |
603 | */ |
604 | bool QOpenGLShader::compileSourceCode(const char *source) |
605 | { |
606 | Q_D(QOpenGLShader); |
607 | // This method breaks the shader code into two parts: |
608 | // 1. Up to and including an optional #version directive. |
609 | // 2. The rest. |
610 | // If a #version directive exists, qualifierDefines and redefineHighp |
611 | // are inserted after. Otherwise they are inserted right at the start. |
612 | // In both cases a #line directive is appended in order to compensate |
613 | // for line number changes in case of compiler errors. |
614 | |
615 | if (d->shaderGuard && d->shaderGuard->id() && source) { |
616 | const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source); |
617 | |
618 | QVarLengthArray<const char *, 5> sourceChunks; |
619 | QVarLengthArray<GLint, 5> sourceChunkLengths; |
620 | QOpenGLContext *ctx = QOpenGLContext::currentContext(); |
621 | |
622 | if (versionDirectivePosition.hasPosition()) { |
623 | // Append source up to and including the #version directive |
624 | sourceChunks.append(source); |
625 | sourceChunkLengths.append(GLint(versionDirectivePosition.position)); |
626 | } else { |
627 | // QTBUG-55733: Intel on Windows with Compatibility profile requires a #version always |
628 | if (ctx->format().profile() == QSurfaceFormat::CompatibilityProfile) { |
629 | const char *vendor = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VENDOR)); |
630 | if (vendor && !strcmp(vendor, "Intel" )) { |
631 | static const char version110[] = "#version 110\n" ; |
632 | sourceChunks.append(version110); |
633 | sourceChunkLengths.append(GLint(sizeof(version110)) - 1); |
634 | } |
635 | } |
636 | } |
637 | if (d->shaderType == Fragment) { |
638 | sourceChunks.append(blendEquationAdvancedHeader); |
639 | sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1)); |
640 | } |
641 | |
642 | // The precision qualifiers are useful on OpenGL/ES systems, |
643 | // but usually not present on desktop systems. |
644 | const QSurfaceFormat currentSurfaceFormat = ctx->format(); |
645 | QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(QOpenGLContext::currentContext()); |
646 | if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL |
647 | || ctx_d->workaround_missingPrecisionQualifiers |
648 | #ifdef QT_OPENGL_FORCE_SHADER_DEFINES |
649 | || true |
650 | #endif |
651 | ) { |
652 | sourceChunks.append(qualifierDefines); |
653 | sourceChunkLengths.append(GLint(sizeof(qualifierDefines) - 1)); |
654 | } |
655 | |
656 | #ifdef QOpenGL_REDEFINE_HIGHP |
657 | if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers |
658 | && QOpenGLContext::currentContext()->isOpenGLES()) { |
659 | sourceChunks.append(redefineHighp); |
660 | sourceChunkLengths.append(GLint(sizeof(redefineHighp) - 1)); |
661 | } |
662 | #endif |
663 | |
664 | QByteArray lineDirective; |
665 | // #line is rejected by some drivers: |
666 | // "2.1 Mesa 8.1-devel (git-48a3d4e)" or "MESA 2.1 Mesa 8.1-devel" |
667 | const char *version = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VERSION)); |
668 | if (!version || !strstr(version, "2.1 Mesa 8" )) { |
669 | // Append #line directive in order to compensate for text insertion |
670 | lineDirective = QStringLiteral("#line %1\n" ).arg(versionDirectivePosition.line).toUtf8(); |
671 | sourceChunks.append(lineDirective.constData()); |
672 | sourceChunkLengths.append(GLint(lineDirective.length())); |
673 | } |
674 | |
675 | // Append rest of shader code |
676 | sourceChunks.append(source + versionDirectivePosition.position); |
677 | sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position))); |
678 | |
679 | d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data()); |
680 | return d->compile(this); |
681 | } else { |
682 | return false; |
683 | } |
684 | } |
685 | |
686 | /*! |
687 | \overload |
688 | |
689 | Sets the \a source code for this shader and compiles it. |
690 | Returns \c true if the source was successfully compiled, false otherwise. |
691 | |
692 | \sa compileSourceFile() |
693 | */ |
694 | bool QOpenGLShader::compileSourceCode(const QByteArray& source) |
695 | { |
696 | return compileSourceCode(source.constData()); |
697 | } |
698 | |
699 | /*! |
700 | \overload |
701 | |
702 | Sets the \a source code for this shader and compiles it. |
703 | Returns \c true if the source was successfully compiled, false otherwise. |
704 | |
705 | \sa compileSourceFile() |
706 | */ |
707 | bool QOpenGLShader::compileSourceCode(const QString& source) |
708 | { |
709 | return compileSourceCode(source.toLatin1().constData()); |
710 | } |
711 | |
712 | /*! |
713 | Sets the source code for this shader to the contents of \a fileName |
714 | and compiles it. Returns \c true if the file could be opened and the |
715 | source compiled, false otherwise. |
716 | |
717 | \sa compileSourceCode() |
718 | */ |
719 | bool QOpenGLShader::compileSourceFile(const QString& fileName) |
720 | { |
721 | QFile file(fileName); |
722 | if (!file.open(QFile::ReadOnly)) { |
723 | qWarning() << "QOpenGLShader: Unable to open file" << fileName; |
724 | return false; |
725 | } |
726 | |
727 | QByteArray contents = file.readAll(); |
728 | return compileSourceCode(contents.constData()); |
729 | } |
730 | |
731 | /*! |
732 | Returns the source code for this shader. |
733 | |
734 | \sa compileSourceCode() |
735 | */ |
736 | QByteArray QOpenGLShader::sourceCode() const |
737 | { |
738 | Q_D(const QOpenGLShader); |
739 | GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; |
740 | if (!shader) |
741 | return QByteArray(); |
742 | GLint size = 0; |
743 | d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); |
744 | if (size <= 0) |
745 | return QByteArray(); |
746 | GLint len = 0; |
747 | char *source = new char [size]; |
748 | d->glfuncs->glGetShaderSource(shader, size, &len, source); |
749 | QByteArray src(source); |
750 | delete [] source; |
751 | return src; |
752 | } |
753 | |
754 | /*! |
755 | Returns \c true if this shader has been compiled; false otherwise. |
756 | |
757 | \sa compileSourceCode(), compileSourceFile() |
758 | */ |
759 | bool QOpenGLShader::isCompiled() const |
760 | { |
761 | Q_D(const QOpenGLShader); |
762 | return d->compiled; |
763 | } |
764 | |
765 | /*! |
766 | Returns the errors and warnings that occurred during the last compile. |
767 | |
768 | \sa compileSourceCode(), compileSourceFile() |
769 | */ |
770 | QString QOpenGLShader::log() const |
771 | { |
772 | Q_D(const QOpenGLShader); |
773 | return d->log; |
774 | } |
775 | |
776 | /*! |
777 | Returns the OpenGL identifier associated with this shader. |
778 | |
779 | \sa QOpenGLShaderProgram::programId() |
780 | */ |
781 | GLuint QOpenGLShader::shaderId() const |
782 | { |
783 | Q_D(const QOpenGLShader); |
784 | return d->shaderGuard ? d->shaderGuard->id() : 0; |
785 | } |
786 | |
787 | class QOpenGLShaderProgramPrivate : public QObjectPrivate |
788 | { |
789 | Q_DECLARE_PUBLIC(QOpenGLShaderProgram) |
790 | public: |
791 | QOpenGLShaderProgramPrivate() |
792 | : programGuard(0) |
793 | , linked(false) |
794 | , inited(false) |
795 | , removingShaders(false) |
796 | , glfuncs(new QOpenGLExtraFunctions) |
797 | #ifndef QT_OPENGL_ES_2 |
798 | , tessellationFuncs(0) |
799 | #endif |
800 | , linkBinaryRecursion(false) |
801 | { |
802 | } |
803 | ~QOpenGLShaderProgramPrivate(); |
804 | |
805 | QOpenGLSharedResourceGuard *programGuard; |
806 | bool linked; |
807 | bool inited; |
808 | bool removingShaders; |
809 | |
810 | QString log; |
811 | QList<QOpenGLShader *> shaders; |
812 | QList<QOpenGLShader *> anonShaders; |
813 | |
814 | QOpenGLExtraFunctions *glfuncs; |
815 | #ifndef QT_OPENGL_ES_2 |
816 | // for tessellation features not in GLES 3.2 |
817 | QOpenGLFunctions_4_0_Core *tessellationFuncs; |
818 | #endif |
819 | |
820 | bool hasShader(QOpenGLShader::ShaderType type) const; |
821 | |
822 | QOpenGLProgramBinaryCache::ProgramDesc binaryProgram; |
823 | bool isCacheDisabled() const; |
824 | bool compileCacheable(); |
825 | bool linkBinary(); |
826 | |
827 | bool linkBinaryRecursion; |
828 | }; |
829 | |
830 | namespace { |
831 | void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id) |
832 | { |
833 | funcs->glDeleteProgram(id); |
834 | } |
835 | } |
836 | |
837 | |
838 | QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate() |
839 | { |
840 | delete glfuncs; |
841 | if (programGuard) |
842 | programGuard->free(); |
843 | } |
844 | |
845 | bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const |
846 | { |
847 | for (QOpenGLShader *shader : shaders) { |
848 | if (shader->shaderType() == type) |
849 | return true; |
850 | } |
851 | return false; |
852 | } |
853 | |
854 | /*! |
855 | Constructs a new shader program and attaches it to \a parent. |
856 | The program will be invalid until addShader() is called. |
857 | |
858 | The shader program will be associated with the current QOpenGLContext. |
859 | |
860 | \sa addShader() |
861 | */ |
862 | QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent) |
863 | : QObject(*new QOpenGLShaderProgramPrivate, parent) |
864 | { |
865 | } |
866 | |
867 | /*! |
868 | Deletes this shader program. |
869 | */ |
870 | QOpenGLShaderProgram::~QOpenGLShaderProgram() |
871 | { |
872 | } |
873 | |
874 | /*! |
875 | Requests the shader program's id to be created immediately. Returns \c true |
876 | if successful; \c false otherwise. |
877 | |
878 | This function is primarily useful when combining QOpenGLShaderProgram |
879 | with other OpenGL functions that operate directly on the shader |
880 | program id, like \c {GL_OES_get_program_binary}. |
881 | |
882 | When the shader program is used normally, the shader program's id will |
883 | be created on demand. |
884 | |
885 | \sa programId() |
886 | |
887 | \since 5.3 |
888 | */ |
889 | bool QOpenGLShaderProgram::create() |
890 | { |
891 | return init(); |
892 | } |
893 | |
894 | bool QOpenGLShaderProgram::init() |
895 | { |
896 | Q_D(QOpenGLShaderProgram); |
897 | if ((d->programGuard && d->programGuard->id()) || d->inited) |
898 | return true; |
899 | d->inited = true; |
900 | QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); |
901 | if (!context) |
902 | return false; |
903 | d->glfuncs->initializeOpenGLFunctions(); |
904 | |
905 | #ifndef QT_OPENGL_ES_2 |
906 | if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) { |
907 | d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>(); |
908 | d->tessellationFuncs->initializeOpenGLFunctions(); |
909 | } |
910 | #endif |
911 | |
912 | GLuint program = d->glfuncs->glCreateProgram(); |
913 | if (!program) { |
914 | qWarning("QOpenGLShaderProgram: could not create shader program" ); |
915 | return false; |
916 | } |
917 | if (d->programGuard) |
918 | delete d->programGuard; |
919 | d->programGuard = new QOpenGLSharedResourceGuard(context, program, freeProgramFunc); |
920 | return true; |
921 | } |
922 | |
923 | /*! |
924 | Adds a compiled \a shader to this shader program. Returns \c true |
925 | if the shader could be added, or false otherwise. |
926 | |
927 | Ownership of the \a shader object remains with the caller. |
928 | It will not be deleted when this QOpenGLShaderProgram instance |
929 | is deleted. This allows the caller to add the same shader |
930 | to multiple shader programs. |
931 | |
932 | \sa addShaderFromSourceCode(), addShaderFromSourceFile() |
933 | \sa removeShader(), link(), removeAllShaders() |
934 | */ |
935 | bool QOpenGLShaderProgram::addShader(QOpenGLShader *shader) |
936 | { |
937 | Q_D(QOpenGLShaderProgram); |
938 | if (!init()) |
939 | return false; |
940 | if (d->shaders.contains(shader)) |
941 | return true; // Already added to this shader program. |
942 | if (d->programGuard && d->programGuard->id() && shader) { |
943 | if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id()) |
944 | return false; |
945 | if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) { |
946 | qWarning("QOpenGLShaderProgram::addShader: Program and shader are not associated with same context." ); |
947 | return false; |
948 | } |
949 | d->glfuncs->glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); |
950 | d->linked = false; // Program needs to be relinked. |
951 | d->shaders.append(shader); |
952 | connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); |
953 | return true; |
954 | } else { |
955 | return false; |
956 | } |
957 | } |
958 | |
959 | /*! |
960 | Compiles \a source as a shader of the specified \a type and |
961 | adds it to this shader program. Returns \c true if compilation |
962 | was successful, false otherwise. The compilation errors |
963 | and warnings will be made available via log(). |
964 | |
965 | This function is intended to be a short-cut for quickly |
966 | adding vertex and fragment shaders to a shader program without |
967 | creating an instance of QOpenGLShader first. |
968 | |
969 | \sa addShader(), addShaderFromSourceFile() |
970 | \sa removeShader(), link(), log(), removeAllShaders() |
971 | */ |
972 | bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) |
973 | { |
974 | Q_D(QOpenGLShaderProgram); |
975 | if (!init()) |
976 | return false; |
977 | QOpenGLShader *shader = new QOpenGLShader(type, this); |
978 | if (!shader->compileSourceCode(source)) { |
979 | d->log = shader->log(); |
980 | delete shader; |
981 | return false; |
982 | } |
983 | d->anonShaders.append(shader); |
984 | return addShader(shader); |
985 | } |
986 | |
987 | /*! |
988 | \overload |
989 | |
990 | Compiles \a source as a shader of the specified \a type and |
991 | adds it to this shader program. Returns \c true if compilation |
992 | was successful, false otherwise. The compilation errors |
993 | and warnings will be made available via log(). |
994 | |
995 | This function is intended to be a short-cut for quickly |
996 | adding vertex and fragment shaders to a shader program without |
997 | creating an instance of QOpenGLShader first. |
998 | |
999 | \sa addShader(), addShaderFromSourceFile() |
1000 | \sa removeShader(), link(), log(), removeAllShaders() |
1001 | */ |
1002 | bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source) |
1003 | { |
1004 | return addShaderFromSourceCode(type, source.constData()); |
1005 | } |
1006 | |
1007 | /*! |
1008 | \overload |
1009 | |
1010 | Compiles \a source as a shader of the specified \a type and |
1011 | adds it to this shader program. Returns \c true if compilation |
1012 | was successful, false otherwise. The compilation errors |
1013 | and warnings will be made available via log(). |
1014 | |
1015 | This function is intended to be a short-cut for quickly |
1016 | adding vertex and fragment shaders to a shader program without |
1017 | creating an instance of QOpenGLShader first. |
1018 | |
1019 | \sa addShader(), addShaderFromSourceFile() |
1020 | \sa removeShader(), link(), log(), removeAllShaders() |
1021 | */ |
1022 | bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source) |
1023 | { |
1024 | return addShaderFromSourceCode(type, source.toLatin1().constData()); |
1025 | } |
1026 | |
1027 | /*! |
1028 | Compiles the contents of \a fileName as a shader of the specified |
1029 | \a type and adds it to this shader program. Returns \c true if |
1030 | compilation was successful, false otherwise. The compilation errors |
1031 | and warnings will be made available via log(). |
1032 | |
1033 | This function is intended to be a short-cut for quickly |
1034 | adding vertex and fragment shaders to a shader program without |
1035 | creating an instance of QOpenGLShader first. |
1036 | |
1037 | \sa addShader(), addShaderFromSourceCode() |
1038 | */ |
1039 | bool QOpenGLShaderProgram::addShaderFromSourceFile |
1040 | (QOpenGLShader::ShaderType type, const QString& fileName) |
1041 | { |
1042 | Q_D(QOpenGLShaderProgram); |
1043 | if (!init()) |
1044 | return false; |
1045 | QOpenGLShader *shader = new QOpenGLShader(type, this); |
1046 | if (!shader->compileSourceFile(fileName)) { |
1047 | d->log = shader->log(); |
1048 | delete shader; |
1049 | return false; |
1050 | } |
1051 | d->anonShaders.append(shader); |
1052 | return addShader(shader); |
1053 | } |
1054 | |
1055 | /*! |
1056 | Registers the shader of the specified \a type and \a source to this |
1057 | program. Unlike addShaderFromSourceCode(), this function does not perform |
1058 | compilation. Compilation is deferred to link(), and may not happen at all, |
1059 | because link() may potentially use a program binary from Qt's shader disk |
1060 | cache. This will typically lead to a significant increase in performance. |
1061 | |
1062 | \return true if the shader has been registered or, in the non-cached case, |
1063 | compiled successfully; false if there was an error. The compilation error |
1064 | messages can be retrieved via log(). |
1065 | |
1066 | When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for |
1067 | example, or the OpenGL context has no support for context binaries, calling |
1068 | this function is equivalent to addShaderFromSourceCode(). |
1069 | |
1070 | \since 5.9 |
1071 | \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() |
1072 | */ |
1073 | bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) |
1074 | { |
1075 | Q_D(QOpenGLShaderProgram); |
1076 | if (!init()) |
1077 | return false; |
1078 | if (d->isCacheDisabled()) |
1079 | return addShaderFromSourceCode(type, source); |
1080 | |
1081 | return addCacheableShaderFromSourceCode(type, QByteArray(source)); |
1082 | } |
1083 | |
1084 | /*! |
1085 | \overload |
1086 | |
1087 | Registers the shader of the specified \a type and \a source to this |
1088 | program. Unlike addShaderFromSourceCode(), this function does not perform |
1089 | compilation. Compilation is deferred to link(), and may not happen at all, |
1090 | because link() may potentially use a program binary from Qt's shader disk |
1091 | cache. This will typically lead to a significant increase in performance. |
1092 | |
1093 | \return true if the shader has been registered or, in the non-cached case, |
1094 | compiled successfully; false if there was an error. The compilation error |
1095 | messages can be retrieved via log(). |
1096 | |
1097 | When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for |
1098 | example, or the OpenGL context has no support for context binaries, calling |
1099 | this function is equivalent to addShaderFromSourceCode(). |
1100 | |
1101 | \since 5.9 |
1102 | \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() |
1103 | */ |
1104 | bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source) |
1105 | { |
1106 | Q_D(QOpenGLShaderProgram); |
1107 | if (!init()) |
1108 | return false; |
1109 | if (d->isCacheDisabled()) |
1110 | return addShaderFromSourceCode(type, source); |
1111 | |
1112 | d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source)); |
1113 | return true; |
1114 | } |
1115 | |
1116 | /*! |
1117 | \overload |
1118 | |
1119 | Registers the shader of the specified \a type and \a source to this |
1120 | program. Unlike addShaderFromSourceCode(), this function does not perform |
1121 | compilation. Compilation is deferred to link(), and may not happen at all, |
1122 | because link() may potentially use a program binary from Qt's shader disk |
1123 | cache. This will typically lead to a significant increase in performance. |
1124 | |
1125 | When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for |
1126 | example, or the OpenGL context has no support for context binaries, calling |
1127 | this function is equivalent to addShaderFromSourceCode(). |
1128 | |
1129 | \since 5.9 |
1130 | \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() |
1131 | */ |
1132 | bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source) |
1133 | { |
1134 | Q_D(QOpenGLShaderProgram); |
1135 | if (!init()) |
1136 | return false; |
1137 | if (d->isCacheDisabled()) |
1138 | return addShaderFromSourceCode(type, source); |
1139 | |
1140 | return addCacheableShaderFromSourceCode(type, source.toUtf8().constData()); |
1141 | } |
1142 | |
1143 | /*! |
1144 | Registers the shader of the specified \a type and \a fileName to this |
1145 | program. Unlike addShaderFromSourceFile(), this function does not perform |
1146 | compilation. Compilation is deferred to link(), and may not happen at all, |
1147 | because link() may potentially use a program binary from Qt's shader disk |
1148 | cache. This will typically lead to a significant increase in performance. |
1149 | |
1150 | \return true if the file has been read successfully, false if the file could |
1151 | not be opened or the normal, non-cached compilation of the shader has |
1152 | failed. The compilation error messages can be retrieved via log(). |
1153 | |
1154 | When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for |
1155 | example, or the OpenGL context has no support for context binaries, calling |
1156 | this function is equivalent to addShaderFromSourceFile(). |
1157 | |
1158 | \since 5.9 |
1159 | \sa addShaderFromSourceFile(), addCacheableShaderFromSourceCode() |
1160 | */ |
1161 | bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName) |
1162 | { |
1163 | Q_D(QOpenGLShaderProgram); |
1164 | if (!init()) |
1165 | return false; |
1166 | if (d->isCacheDisabled()) |
1167 | return addShaderFromSourceFile(type, fileName); |
1168 | |
1169 | QOpenGLProgramBinaryCache::ShaderDesc shader(type); |
1170 | // NB! It could be tempting to defer reading the file contents and just |
1171 | // hash the filename as the cache key, perhaps combined with last-modified |
1172 | // timestamp checks. However, this would raise a number of issues (no |
1173 | // timestamps for files in the resource system; preference for global, not |
1174 | // per-application cache items (where filenames may clash); resource-based |
1175 | // shaders from libraries like Qt Quick; etc.), so just avoid it. |
1176 | QFile f(fileName); |
1177 | if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { |
1178 | shader.source = f.readAll(); |
1179 | f.close(); |
1180 | } else { |
1181 | qWarning("QOpenGLShaderProgram: Unable to open file %s" , qPrintable(fileName)); |
1182 | return false; |
1183 | } |
1184 | d->binaryProgram.shaders.append(shader); |
1185 | return true; |
1186 | } |
1187 | |
1188 | /*! |
1189 | Removes \a shader from this shader program. The object is not deleted. |
1190 | |
1191 | The shader program must be valid in the current QOpenGLContext. |
1192 | |
1193 | \sa addShader(), link(), removeAllShaders() |
1194 | */ |
1195 | void QOpenGLShaderProgram::removeShader(QOpenGLShader *shader) |
1196 | { |
1197 | Q_D(QOpenGLShaderProgram); |
1198 | if (d->programGuard && d->programGuard->id() |
1199 | && shader && shader->d_func()->shaderGuard) |
1200 | { |
1201 | d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); |
1202 | } |
1203 | d->linked = false; // Program needs to be relinked. |
1204 | if (shader) { |
1205 | d->shaders.removeAll(shader); |
1206 | d->anonShaders.removeAll(shader); |
1207 | disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); |
1208 | } |
1209 | } |
1210 | |
1211 | /*! |
1212 | Returns a list of all shaders that have been added to this shader |
1213 | program using addShader(). |
1214 | |
1215 | \sa addShader(), removeShader() |
1216 | */ |
1217 | QList<QOpenGLShader *> QOpenGLShaderProgram::shaders() const |
1218 | { |
1219 | Q_D(const QOpenGLShaderProgram); |
1220 | return d->shaders; |
1221 | } |
1222 | |
1223 | /*! |
1224 | Removes all of the shaders that were added to this program previously. |
1225 | The QOpenGLShader objects for the shaders will not be deleted if they |
1226 | were constructed externally. QOpenGLShader objects that are constructed |
1227 | internally by QOpenGLShaderProgram will be deleted. |
1228 | |
1229 | \sa addShader(), removeShader() |
1230 | */ |
1231 | void QOpenGLShaderProgram::removeAllShaders() |
1232 | { |
1233 | Q_D(QOpenGLShaderProgram); |
1234 | d->removingShaders = true; |
1235 | for (QOpenGLShader *shader : qAsConst(d->shaders)) { |
1236 | if (d->programGuard && d->programGuard->id() |
1237 | && shader && shader->d_func()->shaderGuard) |
1238 | { |
1239 | d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); |
1240 | } |
1241 | } |
1242 | // Delete shader objects that were created anonymously. |
1243 | qDeleteAll(d->anonShaders); |
1244 | d->shaders.clear(); |
1245 | d->anonShaders.clear(); |
1246 | d->binaryProgram = QOpenGLProgramBinaryCache::ProgramDesc(); |
1247 | d->linked = false; // Program needs to be relinked. |
1248 | d->removingShaders = false; |
1249 | } |
1250 | |
1251 | /*! |
1252 | Links together the shaders that were added to this program with |
1253 | addShader(). Returns \c true if the link was successful or |
1254 | false otherwise. If the link failed, the error messages can |
1255 | be retrieved with log(). |
1256 | |
1257 | Subclasses can override this function to initialize attributes |
1258 | and uniform variables for use in specific shader programs. |
1259 | |
1260 | If the shader program was already linked, calling this |
1261 | function again will force it to be re-linked. |
1262 | |
1263 | When shaders were added to this program via |
1264 | addCacheableShaderFromSourceCode() or addCacheableShaderFromSourceFile(), |
1265 | program binaries are supported, and a cached binary is available on disk, |
1266 | actual compilation and linking are skipped. Instead, link() will initialize |
1267 | the program with the binary blob via glProgramBinary(). If there is no |
1268 | cached version of the program or it was generated with a different driver |
1269 | version, the shaders will be compiled from source and the program will get |
1270 | linked normally. This allows seamless upgrading of the graphics drivers, |
1271 | without having to worry about potentially incompatible binary formats. |
1272 | |
1273 | \sa addShader(), log() |
1274 | */ |
1275 | bool QOpenGLShaderProgram::link() |
1276 | { |
1277 | Q_D(QOpenGLShaderProgram); |
1278 | GLuint program = d->programGuard ? d->programGuard->id() : 0; |
1279 | if (!program) |
1280 | return false; |
1281 | |
1282 | if (!d->linkBinaryRecursion && d->shaders.isEmpty() && !d->binaryProgram.shaders.isEmpty()) |
1283 | return d->linkBinary(); |
1284 | |
1285 | GLint value; |
1286 | if (d->shaders.isEmpty()) { |
1287 | // If there are no explicit shaders, then it is possible that the |
1288 | // application added a program binary with glProgramBinaryOES(), or |
1289 | // otherwise populated the shaders itself. This is also the case when |
1290 | // we are recursively called back from linkBinary() after a successful |
1291 | // glProgramBinary(). Check to see if the program is already linked and |
1292 | // bail out if so. |
1293 | value = 0; |
1294 | d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); |
1295 | d->linked = (value != 0); |
1296 | if (d->linked) |
1297 | return true; |
1298 | } |
1299 | |
1300 | d->glfuncs->glLinkProgram(program); |
1301 | value = 0; |
1302 | d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); |
1303 | d->linked = (value != 0); |
1304 | value = 0; |
1305 | d->glfuncs->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); |
1306 | d->log = QString(); |
1307 | if (value > 1) { |
1308 | char *logbuf = new char [value]; |
1309 | GLint len; |
1310 | d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf); |
1311 | d->log = QString::fromLatin1(logbuf); |
1312 | if (!d->linked && !d->linkBinaryRecursion) { |
1313 | QString name = objectName(); |
1314 | if (name.isEmpty()) |
1315 | qWarning("QOpenGLShader::link: %ls" , qUtf16Printable(d->log)); |
1316 | else |
1317 | qWarning("QOpenGLShader::link[%ls]: %ls" , qUtf16Printable(name), qUtf16Printable(d->log)); |
1318 | } |
1319 | delete [] logbuf; |
1320 | } |
1321 | return d->linked; |
1322 | } |
1323 | |
1324 | /*! |
1325 | Returns \c true if this shader program has been linked; false otherwise. |
1326 | |
1327 | \sa link() |
1328 | */ |
1329 | bool QOpenGLShaderProgram::isLinked() const |
1330 | { |
1331 | Q_D(const QOpenGLShaderProgram); |
1332 | return d->linked; |
1333 | } |
1334 | |
1335 | /*! |
1336 | Returns the errors and warnings that occurred during the last link() |
1337 | or addShader() with explicitly specified source code. |
1338 | |
1339 | \sa link() |
1340 | */ |
1341 | QString QOpenGLShaderProgram::log() const |
1342 | { |
1343 | Q_D(const QOpenGLShaderProgram); |
1344 | return d->log; |
1345 | } |
1346 | |
1347 | /*! |
1348 | Binds this shader program to the active QOpenGLContext and makes |
1349 | it the current shader program. Any previously bound shader program |
1350 | is released. This is equivalent to calling \c{glUseProgram()} on |
1351 | programId(). Returns \c true if the program was successfully bound; |
1352 | false otherwise. If the shader program has not yet been linked, |
1353 | or it needs to be re-linked, this function will call link(). |
1354 | |
1355 | \sa link(), release() |
1356 | */ |
1357 | bool QOpenGLShaderProgram::bind() |
1358 | { |
1359 | Q_D(QOpenGLShaderProgram); |
1360 | GLuint program = d->programGuard ? d->programGuard->id() : 0; |
1361 | if (!program) |
1362 | return false; |
1363 | if (!d->linked && !link()) |
1364 | return false; |
1365 | #ifndef QT_NO_DEBUG |
1366 | if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) { |
1367 | qWarning("QOpenGLShaderProgram::bind: program is not valid in the current context." ); |
1368 | return false; |
1369 | } |
1370 | #endif |
1371 | d->glfuncs->glUseProgram(program); |
1372 | return true; |
1373 | } |
1374 | |
1375 | /*! |
1376 | Releases the active shader program from the current QOpenGLContext. |
1377 | This is equivalent to calling \c{glUseProgram(0)}. |
1378 | |
1379 | \sa bind() |
1380 | */ |
1381 | void QOpenGLShaderProgram::release() |
1382 | { |
1383 | Q_D(QOpenGLShaderProgram); |
1384 | #ifndef QT_NO_DEBUG |
1385 | if (d->programGuard && d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) |
1386 | qWarning("QOpenGLShaderProgram::release: program is not valid in the current context." ); |
1387 | #endif |
1388 | d->glfuncs->glUseProgram(0); |
1389 | } |
1390 | |
1391 | /*! |
1392 | Returns the OpenGL identifier associated with this shader program. |
1393 | |
1394 | \sa QOpenGLShader::shaderId() |
1395 | */ |
1396 | GLuint QOpenGLShaderProgram::programId() const |
1397 | { |
1398 | Q_D(const QOpenGLShaderProgram); |
1399 | GLuint id = d->programGuard ? d->programGuard->id() : 0; |
1400 | if (id) |
1401 | return id; |
1402 | |
1403 | // Create the identifier if we don't have one yet. This is for |
1404 | // applications that want to create the attached shader configuration |
1405 | // themselves, particularly those using program binaries. |
1406 | if (!const_cast<QOpenGLShaderProgram *>(this)->init()) |
1407 | return 0; |
1408 | return d->programGuard ? d->programGuard->id() : 0; |
1409 | } |
1410 | |
1411 | /*! |
1412 | Binds the attribute \a name to the specified \a location. This |
1413 | function can be called before or after the program has been linked. |
1414 | Any attributes that have not been explicitly bound when the program |
1415 | is linked will be assigned locations automatically. |
1416 | |
1417 | When this function is called after the program has been linked, |
1418 | the program will need to be relinked for the change to take effect. |
1419 | |
1420 | \sa attributeLocation() |
1421 | */ |
1422 | void QOpenGLShaderProgram::bindAttributeLocation(const char *name, int location) |
1423 | { |
1424 | Q_D(QOpenGLShaderProgram); |
1425 | if (!init() || !d->programGuard || !d->programGuard->id()) |
1426 | return; |
1427 | d->glfuncs->glBindAttribLocation(d->programGuard->id(), location, name); |
1428 | d->linked = false; // Program needs to be relinked. |
1429 | } |
1430 | |
1431 | /*! |
1432 | \overload |
1433 | |
1434 | Binds the attribute \a name to the specified \a location. This |
1435 | function can be called before or after the program has been linked. |
1436 | Any attributes that have not been explicitly bound when the program |
1437 | is linked will be assigned locations automatically. |
1438 | |
1439 | When this function is called after the program has been linked, |
1440 | the program will need to be relinked for the change to take effect. |
1441 | |
1442 | \sa attributeLocation() |
1443 | */ |
1444 | void QOpenGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) |
1445 | { |
1446 | bindAttributeLocation(name.constData(), location); |
1447 | } |
1448 | |
1449 | /*! |
1450 | \overload |
1451 | |
1452 | Binds the attribute \a name to the specified \a location. This |
1453 | function can be called before or after the program has been linked. |
1454 | Any attributes that have not been explicitly bound when the program |
1455 | is linked will be assigned locations automatically. |
1456 | |
1457 | When this function is called after the program has been linked, |
1458 | the program will need to be relinked for the change to take effect. |
1459 | |
1460 | \sa attributeLocation() |
1461 | */ |
1462 | void QOpenGLShaderProgram::bindAttributeLocation(const QString& name, int location) |
1463 | { |
1464 | bindAttributeLocation(name.toLatin1().constData(), location); |
1465 | } |
1466 | |
1467 | /*! |
1468 | Returns the location of the attribute \a name within this shader |
1469 | program's parameter list. Returns -1 if \a name is not a valid |
1470 | attribute for this shader program. |
1471 | |
1472 | \sa uniformLocation(), bindAttributeLocation() |
1473 | */ |
1474 | int QOpenGLShaderProgram::attributeLocation(const char *name) const |
1475 | { |
1476 | Q_D(const QOpenGLShaderProgram); |
1477 | if (d->linked && d->programGuard && d->programGuard->id()) { |
1478 | return d->glfuncs->glGetAttribLocation(d->programGuard->id(), name); |
1479 | } else { |
1480 | qWarning("QOpenGLShaderProgram::attributeLocation(%s): shader program is not linked" , name); |
1481 | return -1; |
1482 | } |
1483 | } |
1484 | |
1485 | /*! |
1486 | \overload |
1487 | |
1488 | Returns the location of the attribute \a name within this shader |
1489 | program's parameter list. Returns -1 if \a name is not a valid |
1490 | attribute for this shader program. |
1491 | |
1492 | \sa uniformLocation(), bindAttributeLocation() |
1493 | */ |
1494 | int QOpenGLShaderProgram::attributeLocation(const QByteArray& name) const |
1495 | { |
1496 | return attributeLocation(name.constData()); |
1497 | } |
1498 | |
1499 | /*! |
1500 | \overload |
1501 | |
1502 | Returns the location of the attribute \a name within this shader |
1503 | program's parameter list. Returns -1 if \a name is not a valid |
1504 | attribute for this shader program. |
1505 | |
1506 | \sa uniformLocation(), bindAttributeLocation() |
1507 | */ |
1508 | int QOpenGLShaderProgram::attributeLocation(const QString& name) const |
1509 | { |
1510 | return attributeLocation(name.toLatin1().constData()); |
1511 | } |
1512 | |
1513 | /*! |
1514 | Sets the attribute at \a location in the current context to \a value. |
1515 | |
1516 | \sa setUniformValue() |
1517 | */ |
1518 | void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat value) |
1519 | { |
1520 | Q_D(QOpenGLShaderProgram); |
1521 | if (location != -1) |
1522 | d->glfuncs->glVertexAttrib1fv(location, &value); |
1523 | } |
1524 | |
1525 | /*! |
1526 | \overload |
1527 | |
1528 | Sets the attribute called \a name in the current context to \a value. |
1529 | |
1530 | \sa setUniformValue() |
1531 | */ |
1532 | void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat value) |
1533 | { |
1534 | setAttributeValue(attributeLocation(name), value); |
1535 | } |
1536 | |
1537 | /*! |
1538 | Sets the attribute at \a location in the current context to |
1539 | the 2D vector (\a x, \a y). |
1540 | |
1541 | \sa setUniformValue() |
1542 | */ |
1543 | void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y) |
1544 | { |
1545 | Q_D(QOpenGLShaderProgram); |
1546 | if (location != -1) { |
1547 | GLfloat values[2] = {x, y}; |
1548 | d->glfuncs->glVertexAttrib2fv(location, values); |
1549 | } |
1550 | } |
1551 | |
1552 | /*! |
1553 | \overload |
1554 | |
1555 | Sets the attribute called \a name in the current context to |
1556 | the 2D vector (\a x, \a y). |
1557 | |
1558 | \sa setUniformValue() |
1559 | */ |
1560 | void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y) |
1561 | { |
1562 | setAttributeValue(attributeLocation(name), x, y); |
1563 | } |
1564 | |
1565 | /*! |
1566 | Sets the attribute at \a location in the current context to |
1567 | the 3D vector (\a x, \a y, \a z). |
1568 | |
1569 | \sa setUniformValue() |
1570 | */ |
1571 | void QOpenGLShaderProgram::setAttributeValue |
1572 | (int location, GLfloat x, GLfloat y, GLfloat z) |
1573 | { |
1574 | Q_D(QOpenGLShaderProgram); |
1575 | Q_UNUSED(d); |
1576 | if (location != -1) { |
1577 | GLfloat values[3] = {x, y, z}; |
1578 | d->glfuncs->glVertexAttrib3fv(location, values); |
1579 | } |
1580 | } |
1581 | |
1582 | /*! |
1583 | \overload |
1584 | |
1585 | Sets the attribute called \a name in the current context to |
1586 | the 3D vector (\a x, \a y, \a z). |
1587 | |
1588 | \sa setUniformValue() |
1589 | */ |
1590 | void QOpenGLShaderProgram::setAttributeValue |
1591 | (const char *name, GLfloat x, GLfloat y, GLfloat z) |
1592 | { |
1593 | setAttributeValue(attributeLocation(name), x, y, z); |
1594 | } |
1595 | |
1596 | /*! |
1597 | Sets the attribute at \a location in the current context to |
1598 | the 4D vector (\a x, \a y, \a z, \a w). |
1599 | |
1600 | \sa setUniformValue() |
1601 | */ |
1602 | void QOpenGLShaderProgram::setAttributeValue |
1603 | (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
1604 | { |
1605 | Q_D(QOpenGLShaderProgram); |
1606 | if (location != -1) { |
1607 | GLfloat values[4] = {x, y, z, w}; |
1608 | d->glfuncs->glVertexAttrib4fv(location, values); |
1609 | } |
1610 | } |
1611 | |
1612 | /*! |
1613 | \overload |
1614 | |
1615 | Sets the attribute called \a name in the current context to |
1616 | the 4D vector (\a x, \a y, \a z, \a w). |
1617 | |
1618 | \sa setUniformValue() |
1619 | */ |
1620 | void QOpenGLShaderProgram::setAttributeValue |
1621 | (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
1622 | { |
1623 | setAttributeValue(attributeLocation(name), x, y, z, w); |
1624 | } |
1625 | |
1626 | /*! |
1627 | Sets the attribute at \a location in the current context to \a value. |
1628 | |
1629 | \sa setUniformValue() |
1630 | */ |
1631 | void QOpenGLShaderProgram::setAttributeValue(int location, const QVector2D& value) |
1632 | { |
1633 | Q_D(QOpenGLShaderProgram); |
1634 | if (location != -1) |
1635 | d->glfuncs->glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value)); |
1636 | } |
1637 | |
1638 | /*! |
1639 | \overload |
1640 | |
1641 | Sets the attribute called \a name in the current context to \a value. |
1642 | |
1643 | \sa setUniformValue() |
1644 | */ |
1645 | void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value) |
1646 | { |
1647 | setAttributeValue(attributeLocation(name), value); |
1648 | } |
1649 | |
1650 | /*! |
1651 | Sets the attribute at \a location in the current context to \a value. |
1652 | |
1653 | \sa setUniformValue() |
1654 | */ |
1655 | void QOpenGLShaderProgram::setAttributeValue(int location, const QVector3D& value) |
1656 | { |
1657 | Q_D(QOpenGLShaderProgram); |
1658 | Q_UNUSED(d); |
1659 | if (location != -1) |
1660 | d->glfuncs->glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value)); |
1661 | } |
1662 | |
1663 | /*! |
1664 | \overload |
1665 | |
1666 | Sets the attribute called \a name in the current context to \a value. |
1667 | |
1668 | \sa setUniformValue() |
1669 | */ |
1670 | void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value) |
1671 | { |
1672 | setAttributeValue(attributeLocation(name), value); |
1673 | } |
1674 | |
1675 | /*! |
1676 | Sets the attribute at \a location in the current context to \a value. |
1677 | |
1678 | \sa setUniformValue() |
1679 | */ |
1680 | void QOpenGLShaderProgram::setAttributeValue(int location, const QVector4D& value) |
1681 | { |
1682 | Q_D(QOpenGLShaderProgram); |
1683 | Q_UNUSED(d); |
1684 | if (location != -1) |
1685 | d->glfuncs->glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value)); |
1686 | } |
1687 | |
1688 | /*! |
1689 | \overload |
1690 | |
1691 | Sets the attribute called \a name in the current context to \a value. |
1692 | |
1693 | \sa setUniformValue() |
1694 | */ |
1695 | void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value) |
1696 | { |
1697 | setAttributeValue(attributeLocation(name), value); |
1698 | } |
1699 | |
1700 | /*! |
1701 | Sets the attribute at \a location in the current context to \a value. |
1702 | |
1703 | \sa setUniformValue() |
1704 | */ |
1705 | void QOpenGLShaderProgram::setAttributeValue(int location, const QColor& value) |
1706 | { |
1707 | Q_D(QOpenGLShaderProgram); |
1708 | Q_UNUSED(d); |
1709 | if (location != -1) { |
1710 | GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()), |
1711 | GLfloat(value.blueF()), GLfloat(value.alphaF())}; |
1712 | d->glfuncs->glVertexAttrib4fv(location, values); |
1713 | } |
1714 | } |
1715 | |
1716 | /*! |
1717 | \overload |
1718 | |
1719 | Sets the attribute called \a name in the current context to \a value. |
1720 | |
1721 | \sa setUniformValue() |
1722 | */ |
1723 | void QOpenGLShaderProgram::setAttributeValue(const char *name, const QColor& value) |
1724 | { |
1725 | setAttributeValue(attributeLocation(name), value); |
1726 | } |
1727 | |
1728 | /*! |
1729 | Sets the attribute at \a location in the current context to the |
1730 | contents of \a values, which contains \a columns elements, each |
1731 | consisting of \a rows elements. The \a rows value should be |
1732 | 1, 2, 3, or 4. This function is typically used to set matrix |
1733 | values and column vectors. |
1734 | |
1735 | \sa setUniformValue() |
1736 | */ |
1737 | void QOpenGLShaderProgram::setAttributeValue |
1738 | (int location, const GLfloat *values, int columns, int rows) |
1739 | { |
1740 | Q_D(QOpenGLShaderProgram); |
1741 | Q_UNUSED(d); |
1742 | if (rows < 1 || rows > 4) { |
1743 | qWarning("QOpenGLShaderProgram::setAttributeValue: rows %d not supported" , rows); |
1744 | return; |
1745 | } |
1746 | if (location != -1) { |
1747 | while (columns-- > 0) { |
1748 | if (rows == 1) |
1749 | d->glfuncs->glVertexAttrib1fv(location, values); |
1750 | else if (rows == 2) |
1751 | d->glfuncs->glVertexAttrib2fv(location, values); |
1752 | else if (rows == 3) |
1753 | d->glfuncs->glVertexAttrib3fv(location, values); |
1754 | else |
1755 | d->glfuncs->glVertexAttrib4fv(location, values); |
1756 | values += rows; |
1757 | ++location; |
1758 | } |
1759 | } |
1760 | } |
1761 | |
1762 | /*! |
1763 | \overload |
1764 | |
1765 | Sets the attribute called \a name in the current context to the |
1766 | contents of \a values, which contains \a columns elements, each |
1767 | consisting of \a rows elements. The \a rows value should be |
1768 | 1, 2, 3, or 4. This function is typically used to set matrix |
1769 | values and column vectors. |
1770 | |
1771 | \sa setUniformValue() |
1772 | */ |
1773 | void QOpenGLShaderProgram::setAttributeValue |
1774 | (const char *name, const GLfloat *values, int columns, int rows) |
1775 | { |
1776 | setAttributeValue(attributeLocation(name), values, columns, rows); |
1777 | } |
1778 | |
1779 | /*! |
1780 | Sets an array of vertex \a values on the attribute at \a location |
1781 | in this shader program. The \a tupleSize indicates the number of |
1782 | components per vertex (1, 2, 3, or 4), and the \a stride indicates |
1783 | the number of bytes between vertices. A default \a stride value |
1784 | of zero indicates that the vertices are densely packed in \a values. |
1785 | |
1786 | The array will become active when enableAttributeArray() is called |
1787 | on the \a location. Otherwise the value specified with |
1788 | setAttributeValue() for \a location will be used. |
1789 | |
1790 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1791 | \sa disableAttributeArray() |
1792 | */ |
1793 | void QOpenGLShaderProgram::setAttributeArray |
1794 | (int location, const GLfloat *values, int tupleSize, int stride) |
1795 | { |
1796 | Q_D(QOpenGLShaderProgram); |
1797 | Q_UNUSED(d); |
1798 | if (location != -1) { |
1799 | d->glfuncs->glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE, |
1800 | stride, values); |
1801 | } |
1802 | } |
1803 | |
1804 | /*! |
1805 | Sets an array of 2D vertex \a values on the attribute at \a location |
1806 | in this shader program. The \a stride indicates the number of bytes |
1807 | between vertices. A default \a stride value of zero indicates that |
1808 | the vertices are densely packed in \a values. |
1809 | |
1810 | The array will become active when enableAttributeArray() is called |
1811 | on the \a location. Otherwise the value specified with |
1812 | setAttributeValue() for \a location will be used. |
1813 | |
1814 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1815 | \sa disableAttributeArray() |
1816 | */ |
1817 | void QOpenGLShaderProgram::setAttributeArray |
1818 | (int location, const QVector2D *values, int stride) |
1819 | { |
1820 | Q_D(QOpenGLShaderProgram); |
1821 | Q_UNUSED(d); |
1822 | if (location != -1) { |
1823 | d->glfuncs->glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, |
1824 | stride, values); |
1825 | } |
1826 | } |
1827 | |
1828 | /*! |
1829 | Sets an array of 3D vertex \a values on the attribute at \a location |
1830 | in this shader program. The \a stride indicates the number of bytes |
1831 | between vertices. A default \a stride value of zero indicates that |
1832 | the vertices are densely packed in \a values. |
1833 | |
1834 | The array will become active when enableAttributeArray() is called |
1835 | on the \a location. Otherwise the value specified with |
1836 | setAttributeValue() for \a location will be used. |
1837 | |
1838 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1839 | \sa disableAttributeArray() |
1840 | */ |
1841 | void QOpenGLShaderProgram::setAttributeArray |
1842 | (int location, const QVector3D *values, int stride) |
1843 | { |
1844 | Q_D(QOpenGLShaderProgram); |
1845 | Q_UNUSED(d); |
1846 | if (location != -1) { |
1847 | d->glfuncs->glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, |
1848 | stride, values); |
1849 | } |
1850 | } |
1851 | |
1852 | /*! |
1853 | Sets an array of 4D vertex \a values on the attribute at \a location |
1854 | in this shader program. The \a stride indicates the number of bytes |
1855 | between vertices. A default \a stride value of zero indicates that |
1856 | the vertices are densely packed in \a values. |
1857 | |
1858 | The array will become active when enableAttributeArray() is called |
1859 | on the \a location. Otherwise the value specified with |
1860 | setAttributeValue() for \a location will be used. |
1861 | |
1862 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1863 | \sa disableAttributeArray() |
1864 | */ |
1865 | void QOpenGLShaderProgram::setAttributeArray |
1866 | (int location, const QVector4D *values, int stride) |
1867 | { |
1868 | Q_D(QOpenGLShaderProgram); |
1869 | Q_UNUSED(d); |
1870 | if (location != -1) { |
1871 | d->glfuncs->glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, |
1872 | stride, values); |
1873 | } |
1874 | } |
1875 | |
1876 | /*! |
1877 | Sets an array of vertex \a values on the attribute at \a location |
1878 | in this shader program. The \a stride indicates the number of bytes |
1879 | between vertices. A default \a stride value of zero indicates that |
1880 | the vertices are densely packed in \a values. |
1881 | |
1882 | The \a type indicates the type of elements in the \a values array, |
1883 | usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize |
1884 | indicates the number of components per vertex: 1, 2, 3, or 4. |
1885 | |
1886 | The array will become active when enableAttributeArray() is called |
1887 | on the \a location. Otherwise the value specified with |
1888 | setAttributeValue() for \a location will be used. |
1889 | |
1890 | The setAttributeBuffer() function can be used to set the attribute |
1891 | array to an offset within a vertex buffer. |
1892 | |
1893 | \note Normalization will be enabled. If this is not desired, call |
1894 | glVertexAttribPointer directly through QOpenGLFunctions. |
1895 | |
1896 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1897 | \sa disableAttributeArray(), setAttributeBuffer() |
1898 | */ |
1899 | void QOpenGLShaderProgram::setAttributeArray |
1900 | (int location, GLenum type, const void *values, int tupleSize, int stride) |
1901 | { |
1902 | Q_D(QOpenGLShaderProgram); |
1903 | Q_UNUSED(d); |
1904 | if (location != -1) { |
1905 | d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, |
1906 | stride, values); |
1907 | } |
1908 | } |
1909 | |
1910 | /*! |
1911 | \overload |
1912 | |
1913 | Sets an array of vertex \a values on the attribute called \a name |
1914 | in this shader program. The \a tupleSize indicates the number of |
1915 | components per vertex (1, 2, 3, or 4), and the \a stride indicates |
1916 | the number of bytes between vertices. A default \a stride value |
1917 | of zero indicates that the vertices are densely packed in \a values. |
1918 | |
1919 | The array will become active when enableAttributeArray() is called |
1920 | on \a name. Otherwise the value specified with setAttributeValue() |
1921 | for \a name will be used. |
1922 | |
1923 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1924 | \sa disableAttributeArray() |
1925 | */ |
1926 | void QOpenGLShaderProgram::setAttributeArray |
1927 | (const char *name, const GLfloat *values, int tupleSize, int stride) |
1928 | { |
1929 | setAttributeArray(attributeLocation(name), values, tupleSize, stride); |
1930 | } |
1931 | |
1932 | /*! |
1933 | \overload |
1934 | |
1935 | Sets an array of 2D vertex \a values on the attribute called \a name |
1936 | in this shader program. The \a stride indicates the number of bytes |
1937 | between vertices. A default \a stride value of zero indicates that |
1938 | the vertices are densely packed in \a values. |
1939 | |
1940 | The array will become active when enableAttributeArray() is called |
1941 | on \a name. Otherwise the value specified with setAttributeValue() |
1942 | for \a name will be used. |
1943 | |
1944 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1945 | \sa disableAttributeArray() |
1946 | */ |
1947 | void QOpenGLShaderProgram::setAttributeArray |
1948 | (const char *name, const QVector2D *values, int stride) |
1949 | { |
1950 | setAttributeArray(attributeLocation(name), values, stride); |
1951 | } |
1952 | |
1953 | /*! |
1954 | \overload |
1955 | |
1956 | Sets an array of 3D vertex \a values on the attribute called \a name |
1957 | in this shader program. The \a stride indicates the number of bytes |
1958 | between vertices. A default \a stride value of zero indicates that |
1959 | the vertices are densely packed in \a values. |
1960 | |
1961 | The array will become active when enableAttributeArray() is called |
1962 | on \a name. Otherwise the value specified with setAttributeValue() |
1963 | for \a name will be used. |
1964 | |
1965 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1966 | \sa disableAttributeArray() |
1967 | */ |
1968 | void QOpenGLShaderProgram::setAttributeArray |
1969 | (const char *name, const QVector3D *values, int stride) |
1970 | { |
1971 | setAttributeArray(attributeLocation(name), values, stride); |
1972 | } |
1973 | |
1974 | /*! |
1975 | \overload |
1976 | |
1977 | Sets an array of 4D vertex \a values on the attribute called \a name |
1978 | in this shader program. The \a stride indicates the number of bytes |
1979 | between vertices. A default \a stride value of zero indicates that |
1980 | the vertices are densely packed in \a values. |
1981 | |
1982 | The array will become active when enableAttributeArray() is called |
1983 | on \a name. Otherwise the value specified with setAttributeValue() |
1984 | for \a name will be used. |
1985 | |
1986 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
1987 | \sa disableAttributeArray() |
1988 | */ |
1989 | void QOpenGLShaderProgram::setAttributeArray |
1990 | (const char *name, const QVector4D *values, int stride) |
1991 | { |
1992 | setAttributeArray(attributeLocation(name), values, stride); |
1993 | } |
1994 | |
1995 | /*! |
1996 | \overload |
1997 | |
1998 | Sets an array of vertex \a values on the attribute called \a name |
1999 | in this shader program. The \a stride indicates the number of bytes |
2000 | between vertices. A default \a stride value of zero indicates that |
2001 | the vertices are densely packed in \a values. |
2002 | |
2003 | The \a type indicates the type of elements in the \a values array, |
2004 | usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize |
2005 | indicates the number of components per vertex: 1, 2, 3, or 4. |
2006 | |
2007 | The array will become active when enableAttributeArray() is called |
2008 | on the \a name. Otherwise the value specified with |
2009 | setAttributeValue() for \a name will be used. |
2010 | |
2011 | The setAttributeBuffer() function can be used to set the attribute |
2012 | array to an offset within a vertex buffer. |
2013 | |
2014 | \sa setAttributeValue(), setUniformValue(), enableAttributeArray() |
2015 | \sa disableAttributeArray(), setAttributeBuffer() |
2016 | */ |
2017 | void QOpenGLShaderProgram::setAttributeArray |
2018 | (const char *name, GLenum type, const void *values, int tupleSize, int stride) |
2019 | { |
2020 | setAttributeArray(attributeLocation(name), type, values, tupleSize, stride); |
2021 | } |
2022 | |
2023 | /*! |
2024 | Sets an array of vertex values on the attribute at \a location in |
2025 | this shader program, starting at a specific \a offset in the |
2026 | currently bound vertex buffer. The \a stride indicates the number |
2027 | of bytes between vertices. A default \a stride value of zero |
2028 | indicates that the vertices are densely packed in the value array. |
2029 | |
2030 | The \a type indicates the type of elements in the vertex value |
2031 | array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a |
2032 | tupleSize indicates the number of components per vertex: 1, 2, 3, |
2033 | or 4. |
2034 | |
2035 | The array will become active when enableAttributeArray() is called |
2036 | on the \a location. Otherwise the value specified with |
2037 | setAttributeValue() for \a location will be used. |
2038 | |
2039 | \note Normalization will be enabled. If this is not desired, call |
2040 | glVertexAttribPointer directly through QOpenGLFunctions. |
2041 | |
2042 | \sa setAttributeArray() |
2043 | */ |
2044 | void QOpenGLShaderProgram::setAttributeBuffer |
2045 | (int location, GLenum type, int offset, int tupleSize, int stride) |
2046 | { |
2047 | Q_D(QOpenGLShaderProgram); |
2048 | Q_UNUSED(d); |
2049 | if (location != -1) { |
2050 | d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, stride, |
2051 | reinterpret_cast<const void *>(qintptr(offset))); |
2052 | } |
2053 | } |
2054 | |
2055 | /*! |
2056 | \overload |
2057 | |
2058 | Sets an array of vertex values on the attribute called \a name |
2059 | in this shader program, starting at a specific \a offset in the |
2060 | currently bound vertex buffer. The \a stride indicates the number |
2061 | of bytes between vertices. A default \a stride value of zero |
2062 | indicates that the vertices are densely packed in the value array. |
2063 | |
2064 | The \a type indicates the type of elements in the vertex value |
2065 | array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a |
2066 | tupleSize indicates the number of components per vertex: 1, 2, 3, |
2067 | or 4. |
2068 | |
2069 | The array will become active when enableAttributeArray() is called |
2070 | on the \a name. Otherwise the value specified with |
2071 | setAttributeValue() for \a name will be used. |
2072 | |
2073 | \sa setAttributeArray() |
2074 | */ |
2075 | void QOpenGLShaderProgram::setAttributeBuffer |
2076 | (const char *name, GLenum type, int offset, int tupleSize, int stride) |
2077 | { |
2078 | setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride); |
2079 | } |
2080 | |
2081 | /*! |
2082 | Enables the vertex array at \a location in this shader program |
2083 | so that the value set by setAttributeArray() on \a location |
2084 | will be used by the shader program. |
2085 | |
2086 | \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() |
2087 | \sa setUniformValue() |
2088 | */ |
2089 | void QOpenGLShaderProgram::enableAttributeArray(int location) |
2090 | { |
2091 | Q_D(QOpenGLShaderProgram); |
2092 | Q_UNUSED(d); |
2093 | if (location != -1) |
2094 | d->glfuncs->glEnableVertexAttribArray(location); |
2095 | } |
2096 | |
2097 | /*! |
2098 | \overload |
2099 | |
2100 | Enables the vertex array called \a name in this shader program |
2101 | so that the value set by setAttributeArray() on \a name |
2102 | will be used by the shader program. |
2103 | |
2104 | \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() |
2105 | \sa setUniformValue() |
2106 | */ |
2107 | void QOpenGLShaderProgram::enableAttributeArray(const char *name) |
2108 | { |
2109 | enableAttributeArray(attributeLocation(name)); |
2110 | } |
2111 | |
2112 | /*! |
2113 | Disables the vertex array at \a location in this shader program |
2114 | that was enabled by a previous call to enableAttributeArray(). |
2115 | |
2116 | \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() |
2117 | \sa setUniformValue() |
2118 | */ |
2119 | void QOpenGLShaderProgram::disableAttributeArray(int location) |
2120 | { |
2121 | Q_D(QOpenGLShaderProgram); |
2122 | Q_UNUSED(d); |
2123 | if (location != -1) |
2124 | d->glfuncs->glDisableVertexAttribArray(location); |
2125 | } |
2126 | |
2127 | /*! |
2128 | \overload |
2129 | |
2130 | Disables the vertex array called \a name in this shader program |
2131 | that was enabled by a previous call to enableAttributeArray(). |
2132 | |
2133 | \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() |
2134 | \sa setUniformValue() |
2135 | */ |
2136 | void QOpenGLShaderProgram::disableAttributeArray(const char *name) |
2137 | { |
2138 | disableAttributeArray(attributeLocation(name)); |
2139 | } |
2140 | |
2141 | /*! |
2142 | Returns the location of the uniform variable \a name within this shader |
2143 | program's parameter list. Returns -1 if \a name is not a valid |
2144 | uniform variable for this shader program. |
2145 | |
2146 | \sa attributeLocation() |
2147 | */ |
2148 | int QOpenGLShaderProgram::uniformLocation(const char *name) const |
2149 | { |
2150 | Q_D(const QOpenGLShaderProgram); |
2151 | Q_UNUSED(d); |
2152 | if (d->linked && d->programGuard && d->programGuard->id()) { |
2153 | return d->glfuncs->glGetUniformLocation(d->programGuard->id(), name); |
2154 | } else { |
2155 | qWarning("QOpenGLShaderProgram::uniformLocation(%s): shader program is not linked" , name); |
2156 | return -1; |
2157 | } |
2158 | } |
2159 | |
2160 | /*! |
2161 | \overload |
2162 | |
2163 | Returns the location of the uniform variable \a name within this shader |
2164 | program's parameter list. Returns -1 if \a name is not a valid |
2165 | uniform variable for this shader program. |
2166 | |
2167 | \sa attributeLocation() |
2168 | */ |
2169 | int QOpenGLShaderProgram::uniformLocation(const QByteArray& name) const |
2170 | { |
2171 | return uniformLocation(name.constData()); |
2172 | } |
2173 | |
2174 | /*! |
2175 | \overload |
2176 | |
2177 | Returns the location of the uniform variable \a name within this shader |
2178 | program's parameter list. Returns -1 if \a name is not a valid |
2179 | uniform variable for this shader program. |
2180 | |
2181 | \sa attributeLocation() |
2182 | */ |
2183 | int QOpenGLShaderProgram::uniformLocation(const QString& name) const |
2184 | { |
2185 | return uniformLocation(name.toLatin1().constData()); |
2186 | } |
2187 | |
2188 | /*! |
2189 | Sets the uniform variable at \a location in the current context to \a value. |
2190 | |
2191 | \sa setAttributeValue() |
2192 | */ |
2193 | void QOpenGLShaderProgram::setUniformValue(int location, GLfloat value) |
2194 | { |
2195 | Q_D(QOpenGLShaderProgram); |
2196 | Q_UNUSED(d); |
2197 | if (location != -1) |
2198 | d->glfuncs->glUniform1fv(location, 1, &value); |
2199 | } |
2200 | |
2201 | /*! |
2202 | \overload |
2203 | |
2204 | Sets the uniform variable called \a name in the current context |
2205 | to \a value. |
2206 | |
2207 | \sa setAttributeValue() |
2208 | */ |
2209 | void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat value) |
2210 | { |
2211 | setUniformValue(uniformLocation(name), value); |
2212 | } |
2213 | |
2214 | /*! |
2215 | Sets the uniform variable at \a location in the current context to \a value. |
2216 | |
2217 | \sa setAttributeValue() |
2218 | */ |
2219 | void QOpenGLShaderProgram::setUniformValue(int location, GLint value) |
2220 | { |
2221 | Q_D(QOpenGLShaderProgram); |
2222 | Q_UNUSED(d); |
2223 | if (location != -1) |
2224 | d->glfuncs->glUniform1i(location, value); |
2225 | } |
2226 | |
2227 | /*! |
2228 | \overload |
2229 | |
2230 | Sets the uniform variable called \a name in the current context |
2231 | to \a value. |
2232 | |
2233 | \sa setAttributeValue() |
2234 | */ |
2235 | void QOpenGLShaderProgram::setUniformValue(const char *name, GLint value) |
2236 | { |
2237 | setUniformValue(uniformLocation(name), value); |
2238 | } |
2239 | |
2240 | /*! |
2241 | Sets the uniform variable at \a location in the current context to \a value. |
2242 | This function should be used when setting sampler values. |
2243 | |
2244 | \note This function is not aware of unsigned int support in modern OpenGL |
2245 | versions and therefore treats \a value as a GLint and calls glUniform1i. |
2246 | |
2247 | \sa setAttributeValue() |
2248 | */ |
2249 | void QOpenGLShaderProgram::setUniformValue(int location, GLuint value) |
2250 | { |
2251 | Q_D(QOpenGLShaderProgram); |
2252 | Q_UNUSED(d); |
2253 | if (location != -1) |
2254 | d->glfuncs->glUniform1i(location, value); |
2255 | } |
2256 | |
2257 | /*! |
2258 | \overload |
2259 | |
2260 | Sets the uniform variable called \a name in the current context |
2261 | to \a value. This function should be used when setting sampler values. |
2262 | |
2263 | \note This function is not aware of unsigned int support in modern OpenGL |
2264 | versions and therefore treats \a value as a GLint and calls glUniform1i. |
2265 | |
2266 | \sa setAttributeValue() |
2267 | */ |
2268 | void QOpenGLShaderProgram::setUniformValue(const char *name, GLuint value) |
2269 | { |
2270 | setUniformValue(uniformLocation(name), value); |
2271 | } |
2272 | |
2273 | /*! |
2274 | Sets the uniform variable at \a location in the current context to |
2275 | the 2D vector (\a x, \a y). |
2276 | |
2277 | \sa setAttributeValue() |
2278 | */ |
2279 | void QOpenGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y) |
2280 | { |
2281 | Q_D(QOpenGLShaderProgram); |
2282 | Q_UNUSED(d); |
2283 | if (location != -1) { |
2284 | GLfloat values[2] = {x, y}; |
2285 | d->glfuncs->glUniform2fv(location, 1, values); |
2286 | } |
2287 | } |
2288 | |
2289 | /*! |
2290 | \overload |
2291 | |
2292 | Sets the uniform variable called \a name in the current context to |
2293 | the 2D vector (\a x, \a y). |
2294 | |
2295 | \sa setAttributeValue() |
2296 | */ |
2297 | void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y) |
2298 | { |
2299 | setUniformValue(uniformLocation(name), x, y); |
2300 | } |
2301 | |
2302 | /*! |
2303 | Sets the uniform variable at \a location in the current context to |
2304 | the 3D vector (\a x, \a y, \a z). |
2305 | |
2306 | \sa setAttributeValue() |
2307 | */ |
2308 | void QOpenGLShaderProgram::setUniformValue |
2309 | (int location, GLfloat x, GLfloat y, GLfloat z) |
2310 | { |
2311 | Q_D(QOpenGLShaderProgram); |
2312 | Q_UNUSED(d); |
2313 | if (location != -1) { |
2314 | GLfloat values[3] = {x, y, z}; |
2315 | d->glfuncs->glUniform3fv(location, 1, values); |
2316 | } |
2317 | } |
2318 | |
2319 | /*! |
2320 | \overload |
2321 | |
2322 | Sets the uniform variable called \a name in the current context to |
2323 | the 3D vector (\a x, \a y, \a z). |
2324 | |
2325 | \sa setAttributeValue() |
2326 | */ |
2327 | void QOpenGLShaderProgram::setUniformValue |
2328 | (const char *name, GLfloat x, GLfloat y, GLfloat z) |
2329 | { |
2330 | setUniformValue(uniformLocation(name), x, y, z); |
2331 | } |
2332 | |
2333 | /*! |
2334 | Sets the uniform variable at \a location in the current context to |
2335 | the 4D vector (\a x, \a y, \a z, \a w). |
2336 | |
2337 | \sa setAttributeValue() |
2338 | */ |
2339 | void QOpenGLShaderProgram::setUniformValue |
2340 | (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
2341 | { |
2342 | Q_D(QOpenGLShaderProgram); |
2343 | Q_UNUSED(d); |
2344 | if (location != -1) { |
2345 | GLfloat values[4] = {x, y, z, w}; |
2346 | d->glfuncs->glUniform4fv(location, 1, values); |
2347 | } |
2348 | } |
2349 | |
2350 | /*! |
2351 | \overload |
2352 | |
2353 | Sets the uniform variable called \a name in the current context to |
2354 | the 4D vector (\a x, \a y, \a z, \a w). |
2355 | |
2356 | \sa setAttributeValue() |
2357 | */ |
2358 | void QOpenGLShaderProgram::setUniformValue |
2359 | (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
2360 | { |
2361 | setUniformValue(uniformLocation(name), x, y, z, w); |
2362 | } |
2363 | |
2364 | /*! |
2365 | Sets the uniform variable at \a location in the current context to \a value. |
2366 | |
2367 | \sa setAttributeValue() |
2368 | */ |
2369 | void QOpenGLShaderProgram::setUniformValue(int location, const QVector2D& value) |
2370 | { |
2371 | Q_D(QOpenGLShaderProgram); |
2372 | Q_UNUSED(d); |
2373 | if (location != -1) |
2374 | d->glfuncs->glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); |
2375 | } |
2376 | |
2377 | /*! |
2378 | \overload |
2379 | |
2380 | Sets the uniform variable called \a name in the current context |
2381 | to \a value. |
2382 | |
2383 | \sa setAttributeValue() |
2384 | */ |
2385 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector2D& value) |
2386 | { |
2387 | setUniformValue(uniformLocation(name), value); |
2388 | } |
2389 | |
2390 | /*! |
2391 | Sets the uniform variable at \a location in the current context to \a value. |
2392 | |
2393 | \sa setAttributeValue() |
2394 | */ |
2395 | void QOpenGLShaderProgram::setUniformValue(int location, const QVector3D& value) |
2396 | { |
2397 | Q_D(QOpenGLShaderProgram); |
2398 | Q_UNUSED(d); |
2399 | if (location != -1) |
2400 | d->glfuncs->glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); |
2401 | } |
2402 | |
2403 | /*! |
2404 | \overload |
2405 | |
2406 | Sets the uniform variable called \a name in the current context |
2407 | to \a value. |
2408 | |
2409 | \sa setAttributeValue() |
2410 | */ |
2411 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector3D& value) |
2412 | { |
2413 | setUniformValue(uniformLocation(name), value); |
2414 | } |
2415 | |
2416 | /*! |
2417 | Sets the uniform variable at \a location in the current context to \a value. |
2418 | |
2419 | \sa setAttributeValue() |
2420 | */ |
2421 | void QOpenGLShaderProgram::setUniformValue(int location, const QVector4D& value) |
2422 | { |
2423 | Q_D(QOpenGLShaderProgram); |
2424 | Q_UNUSED(d); |
2425 | if (location != -1) |
2426 | d->glfuncs->glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); |
2427 | } |
2428 | |
2429 | /*! |
2430 | \overload |
2431 | |
2432 | Sets the uniform variable called \a name in the current context |
2433 | to \a value. |
2434 | |
2435 | \sa setAttributeValue() |
2436 | */ |
2437 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector4D& value) |
2438 | { |
2439 | setUniformValue(uniformLocation(name), value); |
2440 | } |
2441 | |
2442 | /*! |
2443 | Sets the uniform variable at \a location in the current context to |
2444 | the red, green, blue, and alpha components of \a color. |
2445 | |
2446 | \sa setAttributeValue() |
2447 | */ |
2448 | void QOpenGLShaderProgram::setUniformValue(int location, const QColor& color) |
2449 | { |
2450 | Q_D(QOpenGLShaderProgram); |
2451 | Q_UNUSED(d); |
2452 | if (location != -1) { |
2453 | GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()), |
2454 | GLfloat(color.blueF()), GLfloat(color.alphaF())}; |
2455 | d->glfuncs->glUniform4fv(location, 1, values); |
2456 | } |
2457 | } |
2458 | |
2459 | /*! |
2460 | \overload |
2461 | |
2462 | Sets the uniform variable called \a name in the current context to |
2463 | the red, green, blue, and alpha components of \a color. |
2464 | |
2465 | \sa setAttributeValue() |
2466 | */ |
2467 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QColor& color) |
2468 | { |
2469 | setUniformValue(uniformLocation(name), color); |
2470 | } |
2471 | |
2472 | /*! |
2473 | Sets the uniform variable at \a location in the current context to |
2474 | the x and y coordinates of \a point. |
2475 | |
2476 | \sa setAttributeValue() |
2477 | */ |
2478 | void QOpenGLShaderProgram::setUniformValue(int location, const QPoint& point) |
2479 | { |
2480 | Q_D(QOpenGLShaderProgram); |
2481 | Q_UNUSED(d); |
2482 | if (location != -1) { |
2483 | GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; |
2484 | d->glfuncs->glUniform2fv(location, 1, values); |
2485 | } |
2486 | } |
2487 | |
2488 | /*! |
2489 | \overload |
2490 | |
2491 | Sets the uniform variable associated with \a name in the current |
2492 | context to the x and y coordinates of \a point. |
2493 | |
2494 | \sa setAttributeValue() |
2495 | */ |
2496 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QPoint& point) |
2497 | { |
2498 | setUniformValue(uniformLocation(name), point); |
2499 | } |
2500 | |
2501 | /*! |
2502 | Sets the uniform variable at \a location in the current context to |
2503 | the x and y coordinates of \a point. |
2504 | |
2505 | \sa setAttributeValue() |
2506 | */ |
2507 | void QOpenGLShaderProgram::setUniformValue(int location, const QPointF& point) |
2508 | { |
2509 | Q_D(QOpenGLShaderProgram); |
2510 | Q_UNUSED(d); |
2511 | if (location != -1) { |
2512 | GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; |
2513 | d->glfuncs->glUniform2fv(location, 1, values); |
2514 | } |
2515 | } |
2516 | |
2517 | /*! |
2518 | \overload |
2519 | |
2520 | Sets the uniform variable associated with \a name in the current |
2521 | context to the x and y coordinates of \a point. |
2522 | |
2523 | \sa setAttributeValue() |
2524 | */ |
2525 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QPointF& point) |
2526 | { |
2527 | setUniformValue(uniformLocation(name), point); |
2528 | } |
2529 | |
2530 | /*! |
2531 | Sets the uniform variable at \a location in the current context to |
2532 | the width and height of the given \a size. |
2533 | |
2534 | \sa setAttributeValue() |
2535 | */ |
2536 | void QOpenGLShaderProgram::setUniformValue(int location, const QSize& size) |
2537 | { |
2538 | Q_D(QOpenGLShaderProgram); |
2539 | Q_UNUSED(d); |
2540 | if (location != -1) { |
2541 | GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; |
2542 | d->glfuncs->glUniform2fv(location, 1, values); |
2543 | } |
2544 | } |
2545 | |
2546 | /*! |
2547 | \overload |
2548 | |
2549 | Sets the uniform variable associated with \a name in the current |
2550 | context to the width and height of the given \a size. |
2551 | |
2552 | \sa setAttributeValue() |
2553 | */ |
2554 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QSize& size) |
2555 | { |
2556 | setUniformValue(uniformLocation(name), size); |
2557 | } |
2558 | |
2559 | /*! |
2560 | Sets the uniform variable at \a location in the current context to |
2561 | the width and height of the given \a size. |
2562 | |
2563 | \sa setAttributeValue() |
2564 | */ |
2565 | void QOpenGLShaderProgram::setUniformValue(int location, const QSizeF& size) |
2566 | { |
2567 | Q_D(QOpenGLShaderProgram); |
2568 | Q_UNUSED(d); |
2569 | if (location != -1) { |
2570 | GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; |
2571 | d->glfuncs->glUniform2fv(location, 1, values); |
2572 | } |
2573 | } |
2574 | |
2575 | /*! |
2576 | \overload |
2577 | |
2578 | Sets the uniform variable associated with \a name in the current |
2579 | context to the width and height of the given \a size. |
2580 | |
2581 | \sa setAttributeValue() |
2582 | */ |
2583 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QSizeF& size) |
2584 | { |
2585 | setUniformValue(uniformLocation(name), size); |
2586 | } |
2587 | |
2588 | /*! |
2589 | Sets the uniform variable at \a location in the current context |
2590 | to a 2x2 matrix \a value. |
2591 | |
2592 | \sa setAttributeValue() |
2593 | */ |
2594 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value) |
2595 | { |
2596 | Q_D(QOpenGLShaderProgram); |
2597 | Q_UNUSED(d); |
2598 | d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value.constData()); |
2599 | } |
2600 | |
2601 | /*! |
2602 | \overload |
2603 | |
2604 | Sets the uniform variable called \a name in the current context |
2605 | to a 2x2 matrix \a value. |
2606 | |
2607 | \sa setAttributeValue() |
2608 | */ |
2609 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value) |
2610 | { |
2611 | setUniformValue(uniformLocation(name), value); |
2612 | } |
2613 | |
2614 | /*! |
2615 | Sets the uniform variable at \a location in the current context |
2616 | to a 2x3 matrix \a value. |
2617 | |
2618 | \note This function is not aware of non square matrix support, |
2619 | that is, GLSL types like mat2x3, that is present in modern OpenGL |
2620 | versions. Instead, it treats the uniform as an array of vec3. |
2621 | |
2622 | \sa setAttributeValue() |
2623 | */ |
2624 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) |
2625 | { |
2626 | Q_D(QOpenGLShaderProgram); |
2627 | Q_UNUSED(d); |
2628 | d->glfuncs->glUniform3fv(location, 2, value.constData()); |
2629 | } |
2630 | |
2631 | /*! |
2632 | \overload |
2633 | |
2634 | Sets the uniform variable called \a name in the current context |
2635 | to a 2x3 matrix \a value. |
2636 | |
2637 | \note This function is not aware of non square matrix support, |
2638 | that is, GLSL types like mat2x3, that is present in modern OpenGL |
2639 | versions. Instead, it treats the uniform as an array of vec3. |
2640 | |
2641 | \sa setAttributeValue() |
2642 | */ |
2643 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) |
2644 | { |
2645 | setUniformValue(uniformLocation(name), value); |
2646 | } |
2647 | |
2648 | /*! |
2649 | Sets the uniform variable at \a location in the current context |
2650 | to a 2x4 matrix \a value. |
2651 | |
2652 | \note This function is not aware of non square matrix support, |
2653 | that is, GLSL types like mat2x4, that is present in modern OpenGL |
2654 | versions. Instead, it treats the uniform as an array of vec4. |
2655 | |
2656 | \sa setAttributeValue() |
2657 | */ |
2658 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) |
2659 | { |
2660 | Q_D(QOpenGLShaderProgram); |
2661 | Q_UNUSED(d); |
2662 | d->glfuncs->glUniform4fv(location, 2, value.constData()); |
2663 | } |
2664 | |
2665 | /*! |
2666 | \overload |
2667 | |
2668 | Sets the uniform variable called \a name in the current context |
2669 | to a 2x4 matrix \a value. |
2670 | |
2671 | \note This function is not aware of non square matrix support, |
2672 | that is, GLSL types like mat2x4, that is present in modern OpenGL |
2673 | versions. Instead, it treats the uniform as an array of vec4. |
2674 | |
2675 | \sa setAttributeValue() |
2676 | */ |
2677 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) |
2678 | { |
2679 | setUniformValue(uniformLocation(name), value); |
2680 | } |
2681 | |
2682 | /*! |
2683 | Sets the uniform variable at \a location in the current context |
2684 | to a 3x2 matrix \a value. |
2685 | |
2686 | \note This function is not aware of non square matrix support, |
2687 | that is, GLSL types like mat3x2, that is present in modern OpenGL |
2688 | versions. Instead, it treats the uniform as an array of vec2. |
2689 | |
2690 | \sa setAttributeValue() |
2691 | */ |
2692 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) |
2693 | { |
2694 | Q_D(QOpenGLShaderProgram); |
2695 | Q_UNUSED(d); |
2696 | d->glfuncs->glUniform2fv(location, 3, value.constData()); |
2697 | } |
2698 | |
2699 | /*! |
2700 | \overload |
2701 | |
2702 | Sets the uniform variable called \a name in the current context |
2703 | to a 3x2 matrix \a value. |
2704 | |
2705 | \note This function is not aware of non square matrix support, |
2706 | that is, GLSL types like mat3x2, that is present in modern OpenGL |
2707 | versions. Instead, it treats the uniform as an array of vec2. |
2708 | |
2709 | \sa setAttributeValue() |
2710 | */ |
2711 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) |
2712 | { |
2713 | setUniformValue(uniformLocation(name), value); |
2714 | } |
2715 | |
2716 | /*! |
2717 | Sets the uniform variable at \a location in the current context |
2718 | to a 3x3 matrix \a value. |
2719 | |
2720 | \sa setAttributeValue() |
2721 | */ |
2722 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value) |
2723 | { |
2724 | Q_D(QOpenGLShaderProgram); |
2725 | Q_UNUSED(d); |
2726 | d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value.constData()); |
2727 | } |
2728 | |
2729 | /*! |
2730 | \overload |
2731 | |
2732 | Sets the uniform variable called \a name in the current context |
2733 | to a 3x3 matrix \a value. |
2734 | |
2735 | \sa setAttributeValue() |
2736 | */ |
2737 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value) |
2738 | { |
2739 | setUniformValue(uniformLocation(name), value); |
2740 | } |
2741 | |
2742 | /*! |
2743 | Sets the uniform variable at \a location in the current context |
2744 | to a 3x4 matrix \a value. |
2745 | |
2746 | \note This function is not aware of non square matrix support, |
2747 | that is, GLSL types like mat3x4, that is present in modern OpenGL |
2748 | versions. Instead, it treats the uniform as an array of vec4. |
2749 | |
2750 | \sa setAttributeValue() |
2751 | */ |
2752 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) |
2753 | { |
2754 | Q_D(QOpenGLShaderProgram); |
2755 | Q_UNUSED(d); |
2756 | d->glfuncs->glUniform4fv(location, 3, value.constData()); |
2757 | } |
2758 | |
2759 | /*! |
2760 | \overload |
2761 | |
2762 | Sets the uniform variable called \a name in the current context |
2763 | to a 3x4 matrix \a value. |
2764 | |
2765 | \note This function is not aware of non square matrix support, |
2766 | that is, GLSL types like mat3x4, that is present in modern OpenGL |
2767 | versions. Instead, it treats the uniform as an array of vec4. |
2768 | |
2769 | \sa setAttributeValue() |
2770 | */ |
2771 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) |
2772 | { |
2773 | setUniformValue(uniformLocation(name), value); |
2774 | } |
2775 | |
2776 | /*! |
2777 | Sets the uniform variable at \a location in the current context |
2778 | to a 4x2 matrix \a value. |
2779 | |
2780 | \note This function is not aware of non square matrix support, |
2781 | that is, GLSL types like mat4x2, that is present in modern OpenGL |
2782 | versions. Instead, it treats the uniform as an array of vec2. |
2783 | |
2784 | \sa setAttributeValue() |
2785 | */ |
2786 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) |
2787 | { |
2788 | Q_D(QOpenGLShaderProgram); |
2789 | Q_UNUSED(d); |
2790 | d->glfuncs->glUniform2fv(location, 4, value.constData()); |
2791 | } |
2792 | |
2793 | /*! |
2794 | \overload |
2795 | |
2796 | Sets the uniform variable called \a name in the current context |
2797 | to a 4x2 matrix \a value. |
2798 | |
2799 | \note This function is not aware of non square matrix support, |
2800 | that is, GLSL types like mat4x2, that is present in modern OpenGL |
2801 | versions. Instead, it treats the uniform as an array of vec2. |
2802 | |
2803 | \sa setAttributeValue() |
2804 | */ |
2805 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) |
2806 | { |
2807 | setUniformValue(uniformLocation(name), value); |
2808 | } |
2809 | |
2810 | /*! |
2811 | Sets the uniform variable at \a location in the current context |
2812 | to a 4x3 matrix \a value. |
2813 | |
2814 | \note This function is not aware of non square matrix support, |
2815 | that is, GLSL types like mat4x3, that is present in modern OpenGL |
2816 | versions. Instead, it treats the uniform as an array of vec3. |
2817 | |
2818 | \sa setAttributeValue() |
2819 | */ |
2820 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) |
2821 | { |
2822 | Q_D(QOpenGLShaderProgram); |
2823 | Q_UNUSED(d); |
2824 | d->glfuncs->glUniform3fv(location, 4, value.constData()); |
2825 | } |
2826 | |
2827 | /*! |
2828 | \overload |
2829 | |
2830 | Sets the uniform variable called \a name in the current context |
2831 | to a 4x3 matrix \a value. |
2832 | |
2833 | \note This function is not aware of non square matrix support, |
2834 | that is, GLSL types like mat4x3, that is present in modern OpenGL |
2835 | versions. Instead, it treats the uniform as an array of vec3. |
2836 | |
2837 | \sa setAttributeValue() |
2838 | */ |
2839 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) |
2840 | { |
2841 | setUniformValue(uniformLocation(name), value); |
2842 | } |
2843 | |
2844 | /*! |
2845 | Sets the uniform variable at \a location in the current context |
2846 | to a 4x4 matrix \a value. |
2847 | |
2848 | \sa setAttributeValue() |
2849 | */ |
2850 | void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value) |
2851 | { |
2852 | Q_D(QOpenGLShaderProgram); |
2853 | Q_UNUSED(d); |
2854 | d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value.constData()); |
2855 | } |
2856 | |
2857 | /*! |
2858 | \overload |
2859 | |
2860 | Sets the uniform variable called \a name in the current context |
2861 | to a 4x4 matrix \a value. |
2862 | |
2863 | \sa setAttributeValue() |
2864 | */ |
2865 | void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value) |
2866 | { |
2867 | setUniformValue(uniformLocation(name), value); |
2868 | } |
2869 | |
2870 | /*! |
2871 | \overload |
2872 | |
2873 | Sets the uniform variable at \a location in the current context |
2874 | to a 2x2 matrix \a value. The matrix elements must be specified |
2875 | in column-major order. |
2876 | |
2877 | \sa setAttributeValue() |
2878 | */ |
2879 | void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2]) |
2880 | { |
2881 | Q_D(QOpenGLShaderProgram); |
2882 | Q_UNUSED(d); |
2883 | if (location != -1) |
2884 | d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value[0]); |
2885 | } |
2886 | |
2887 | /*! |
2888 | \overload |
2889 | |
2890 | Sets the uniform variable at \a location in the current context |
2891 | to a 3x3 matrix \a value. The matrix elements must be specified |
2892 | in column-major order. |
2893 | |
2894 | \sa setAttributeValue() |
2895 | */ |
2896 | void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3]) |
2897 | { |
2898 | Q_D(QOpenGLShaderProgram); |
2899 | Q_UNUSED(d); |
2900 | if (location != -1) |
2901 | d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value[0]); |
2902 | } |
2903 | |
2904 | /*! |
2905 | \overload |
2906 | |
2907 | Sets the uniform variable at \a location in the current context |
2908 | to a 4x4 matrix \a value. The matrix elements must be specified |
2909 | in column-major order. |
2910 | |
2911 | \sa setAttributeValue() |
2912 | */ |
2913 | void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) |
2914 | { |
2915 | Q_D(QOpenGLShaderProgram); |
2916 | Q_UNUSED(d); |
2917 | if (location != -1) |
2918 | d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); |
2919 | } |
2920 | |
2921 | |
2922 | /*! |
2923 | \overload |
2924 | |
2925 | Sets the uniform variable called \a name in the current context |
2926 | to a 2x2 matrix \a value. The matrix elements must be specified |
2927 | in column-major order. |
2928 | |
2929 | \sa setAttributeValue() |
2930 | */ |
2931 | void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2]) |
2932 | { |
2933 | setUniformValue(uniformLocation(name), value); |
2934 | } |
2935 | |
2936 | /*! |
2937 | \overload |
2938 | |
2939 | Sets the uniform variable called \a name in the current context |
2940 | to a 3x3 matrix \a value. The matrix elements must be specified |
2941 | in column-major order. |
2942 | |
2943 | \sa setAttributeValue() |
2944 | */ |
2945 | void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3]) |
2946 | { |
2947 | setUniformValue(uniformLocation(name), value); |
2948 | } |
2949 | |
2950 | /*! |
2951 | \overload |
2952 | |
2953 | Sets the uniform variable called \a name in the current context |
2954 | to a 4x4 matrix \a value. The matrix elements must be specified |
2955 | in column-major order. |
2956 | |
2957 | \sa setAttributeValue() |
2958 | */ |
2959 | void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4]) |
2960 | { |
2961 | setUniformValue(uniformLocation(name), value); |
2962 | } |
2963 | |
2964 | /*! |
2965 | Sets the uniform variable at \a location in the current context to a |
2966 | 3x3 transformation matrix \a value that is specified as a QTransform value. |
2967 | |
2968 | To set a QTransform value as a 4x4 matrix in a shader, use |
2969 | \c{setUniformValue(location, QMatrix4x4(value))}. |
2970 | */ |
2971 | void QOpenGLShaderProgram::setUniformValue(int location, const QTransform& value) |
2972 | { |
2973 | Q_D(QOpenGLShaderProgram); |
2974 | Q_UNUSED(d); |
2975 | if (location != -1) { |
2976 | GLfloat mat[3][3] = { |
2977 | {GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())}, |
2978 | {GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())}, |
2979 | {GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())} |
2980 | }; |
2981 | d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); |
2982 | } |
2983 | } |
2984 | |
2985 | /*! |
2986 | \overload |
2987 | |
2988 | Sets the uniform variable called \a name in the current context to a |
2989 | 3x3 transformation matrix \a value that is specified as a QTransform value. |
2990 | |
2991 | To set a QTransform value as a 4x4 matrix in a shader, use |
2992 | \c{setUniformValue(name, QMatrix4x4(value))}. |
2993 | */ |
2994 | void QOpenGLShaderProgram::setUniformValue |
2995 | (const char *name, const QTransform& value) |
2996 | { |
2997 | setUniformValue(uniformLocation(name), value); |
2998 | } |
2999 | |
3000 | /*! |
3001 | Sets the uniform variable array at \a location in the current |
3002 | context to the \a count elements of \a values. |
3003 | |
3004 | \sa setAttributeValue() |
3005 | */ |
3006 | void QOpenGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count) |
3007 | { |
3008 | Q_D(QOpenGLShaderProgram); |
3009 | Q_UNUSED(d); |
3010 | if (location != -1) |
3011 | d->glfuncs->glUniform1iv(location, count, values); |
3012 | } |
3013 | |
3014 | /*! |
3015 | \overload |
3016 | |
3017 | Sets the uniform variable array called \a name in the current |
3018 | context to the \a count elements of \a values. |
3019 | |
3020 | \sa setAttributeValue() |
3021 | */ |
3022 | void QOpenGLShaderProgram::setUniformValueArray |
3023 | (const char *name, const GLint *values, int count) |
3024 | { |
3025 | setUniformValueArray(uniformLocation(name), values, count); |
3026 | } |
3027 | |
3028 | /*! |
3029 | Sets the uniform variable array at \a location in the current |
3030 | context to the \a count elements of \a values. This overload |
3031 | should be used when setting an array of sampler values. |
3032 | |
3033 | \note This function is not aware of unsigned int support in modern OpenGL |
3034 | versions and therefore treats \a values as a GLint and calls glUniform1iv. |
3035 | |
3036 | \sa setAttributeValue() |
3037 | */ |
3038 | void QOpenGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count) |
3039 | { |
3040 | Q_D(QOpenGLShaderProgram); |
3041 | Q_UNUSED(d); |
3042 | if (location != -1) |
3043 | d->glfuncs->glUniform1iv(location, count, reinterpret_cast<const GLint *>(values)); |
3044 | } |
3045 | |
3046 | /*! |
3047 | \overload |
3048 | |
3049 | Sets the uniform variable array called \a name in the current |
3050 | context to the \a count elements of \a values. This overload |
3051 | should be used when setting an array of sampler values. |
3052 | |
3053 | \sa setAttributeValue() |
3054 | */ |
3055 | void QOpenGLShaderProgram::setUniformValueArray |
3056 | (const char *name, const GLuint *values, int count) |
3057 | { |
3058 | setUniformValueArray(uniformLocation(name), values, count); |
3059 | } |
3060 | |
3061 | /*! |
3062 | Sets the uniform variable array at \a location in the current |
3063 | context to the \a count elements of \a values. Each element |
3064 | has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. |
3065 | |
3066 | \sa setAttributeValue() |
3067 | */ |
3068 | void QOpenGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize) |
3069 | { |
3070 | Q_D(QOpenGLShaderProgram); |
3071 | Q_UNUSED(d); |
3072 | if (location != -1) { |
3073 | if (tupleSize == 1) |
3074 | d->glfuncs->glUniform1fv(location, count, values); |
3075 | else if (tupleSize == 2) |
3076 | d->glfuncs->glUniform2fv(location, count, values); |
3077 | else if (tupleSize == 3) |
3078 | d->glfuncs->glUniform3fv(location, count, values); |
3079 | else if (tupleSize == 4) |
3080 | d->glfuncs->glUniform4fv(location, count, values); |
3081 | else |
3082 | qWarning("QOpenGLShaderProgram::setUniformValue: size %d not supported" , tupleSize); |
3083 | } |
3084 | } |
3085 | |
3086 | /*! |
3087 | \overload |
3088 | |
3089 | Sets the uniform variable array called \a name in the current |
3090 | context to the \a count elements of \a values. Each element |
3091 | has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. |
3092 | |
3093 | \sa setAttributeValue() |
3094 | */ |
3095 | void QOpenGLShaderProgram::setUniformValueArray |
3096 | (const char *name, const GLfloat *values, int count, int tupleSize) |
3097 | { |
3098 | setUniformValueArray(uniformLocation(name), values, count, tupleSize); |
3099 | } |
3100 | |
3101 | /*! |
3102 | Sets the uniform variable array at \a location in the current |
3103 | context to the \a count 2D vector elements of \a values. |
3104 | |
3105 | \sa setAttributeValue() |
3106 | */ |
3107 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count) |
3108 | { |
3109 | Q_D(QOpenGLShaderProgram); |
3110 | Q_UNUSED(d); |
3111 | if (location != -1) |
3112 | d->glfuncs->glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values)); |
3113 | } |
3114 | |
3115 | /*! |
3116 | \overload |
3117 | |
3118 | Sets the uniform variable array called \a name in the current |
3119 | context to the \a count 2D vector elements of \a values. |
3120 | |
3121 | \sa setAttributeValue() |
3122 | */ |
3123 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count) |
3124 | { |
3125 | setUniformValueArray(uniformLocation(name), values, count); |
3126 | } |
3127 | |
3128 | /*! |
3129 | Sets the uniform variable array at \a location in the current |
3130 | context to the \a count 3D vector elements of \a values. |
3131 | |
3132 | \sa setAttributeValue() |
3133 | */ |
3134 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count) |
3135 | { |
3136 | Q_D(QOpenGLShaderProgram); |
3137 | Q_UNUSED(d); |
3138 | if (location != -1) |
3139 | d->glfuncs->glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values)); |
3140 | } |
3141 | |
3142 | /*! |
3143 | \overload |
3144 | |
3145 | Sets the uniform variable array called \a name in the current |
3146 | context to the \a count 3D vector elements of \a values. |
3147 | |
3148 | \sa setAttributeValue() |
3149 | */ |
3150 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count) |
3151 | { |
3152 | setUniformValueArray(uniformLocation(name), values, count); |
3153 | } |
3154 | |
3155 | /*! |
3156 | Sets the uniform variable array at \a location in the current |
3157 | context to the \a count 4D vector elements of \a values. |
3158 | |
3159 | \sa setAttributeValue() |
3160 | */ |
3161 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count) |
3162 | { |
3163 | Q_D(QOpenGLShaderProgram); |
3164 | Q_UNUSED(d); |
3165 | if (location != -1) |
3166 | d->glfuncs->glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values)); |
3167 | } |
3168 | |
3169 | /*! |
3170 | \overload |
3171 | |
3172 | Sets the uniform variable array called \a name in the current |
3173 | context to the \a count 4D vector elements of \a values. |
3174 | |
3175 | \sa setAttributeValue() |
3176 | */ |
3177 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count) |
3178 | { |
3179 | setUniformValueArray(uniformLocation(name), values, count); |
3180 | } |
3181 | |
3182 | // We have to repack matrix arrays from qreal to GLfloat. |
3183 | #define setUniformMatrixArray(func,location,values,count,type,cols,rows) \ |
3184 | if (location == -1 || count <= 0) \ |
3185 | return; \ |
3186 | if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ |
3187 | func(location, count, GL_FALSE, \ |
3188 | reinterpret_cast<const GLfloat *>(values[0].constData())); \ |
3189 | } else { \ |
3190 | QVarLengthArray<GLfloat> temp(cols * rows * count); \ |
3191 | for (int index = 0; index < count; ++index) { \ |
3192 | for (int index2 = 0; index2 < (cols * rows); ++index2) { \ |
3193 | temp.data()[cols * rows * index + index2] = \ |
3194 | values[index].constData()[index2]; \ |
3195 | } \ |
3196 | } \ |
3197 | func(location, count, GL_FALSE, temp.constData()); \ |
3198 | } |
3199 | #define setUniformGenericMatrixArray(colfunc,location,values,count,type,cols,rows) \ |
3200 | if (location == -1 || count <= 0) \ |
3201 | return; \ |
3202 | if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ |
3203 | const GLfloat *data = reinterpret_cast<const GLfloat *> \ |
3204 | (values[0].constData()); \ |
3205 | colfunc(location, count * cols, data); \ |
3206 | } else { \ |
3207 | QVarLengthArray<GLfloat> temp(cols * rows * count); \ |
3208 | for (int index = 0; index < count; ++index) { \ |
3209 | for (int index2 = 0; index2 < (cols * rows); ++index2) { \ |
3210 | temp.data()[cols * rows * index + index2] = \ |
3211 | values[index].constData()[index2]; \ |
3212 | } \ |
3213 | } \ |
3214 | colfunc(location, count * cols, temp.constData()); \ |
3215 | } |
3216 | |
3217 | /*! |
3218 | Sets the uniform variable array at \a location in the current |
3219 | context to the \a count 2x2 matrix elements of \a values. |
3220 | |
3221 | \sa setAttributeValue() |
3222 | */ |
3223 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count) |
3224 | { |
3225 | Q_D(QOpenGLShaderProgram); |
3226 | Q_UNUSED(d); |
3227 | setUniformMatrixArray |
3228 | (d->glfuncs->glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2); |
3229 | } |
3230 | |
3231 | /*! |
3232 | \overload |
3233 | |
3234 | Sets the uniform variable array called \a name in the current |
3235 | context to the \a count 2x2 matrix elements of \a values. |
3236 | |
3237 | \sa setAttributeValue() |
3238 | */ |
3239 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count) |
3240 | { |
3241 | setUniformValueArray(uniformLocation(name), values, count); |
3242 | } |
3243 | |
3244 | /*! |
3245 | Sets the uniform variable array at \a location in the current |
3246 | context to the \a count 2x3 matrix elements of \a values. |
3247 | |
3248 | \sa setAttributeValue() |
3249 | */ |
3250 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count) |
3251 | { |
3252 | Q_D(QOpenGLShaderProgram); |
3253 | Q_UNUSED(d); |
3254 | setUniformGenericMatrixArray |
3255 | (d->glfuncs->glUniform3fv, location, values, count, |
3256 | QMatrix2x3, 2, 3); |
3257 | } |
3258 | |
3259 | /*! |
3260 | \overload |
3261 | |
3262 | Sets the uniform variable array called \a name in the current |
3263 | context to the \a count 2x3 matrix elements of \a values. |
3264 | |
3265 | \sa setAttributeValue() |
3266 | */ |
3267 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count) |
3268 | { |
3269 | setUniformValueArray(uniformLocation(name), values, count); |
3270 | } |
3271 | |
3272 | /*! |
3273 | Sets the uniform variable array at \a location in the current |
3274 | context to the \a count 2x4 matrix elements of \a values. |
3275 | |
3276 | \sa setAttributeValue() |
3277 | */ |
3278 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count) |
3279 | { |
3280 | Q_D(QOpenGLShaderProgram); |
3281 | Q_UNUSED(d); |
3282 | setUniformGenericMatrixArray |
3283 | (d->glfuncs->glUniform4fv, location, values, count, |
3284 | QMatrix2x4, 2, 4); |
3285 | } |
3286 | |
3287 | /*! |
3288 | \overload |
3289 | |
3290 | Sets the uniform variable array called \a name in the current |
3291 | context to the \a count 2x4 matrix elements of \a values. |
3292 | |
3293 | \sa setAttributeValue() |
3294 | */ |
3295 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count) |
3296 | { |
3297 | setUniformValueArray(uniformLocation(name), values, count); |
3298 | } |
3299 | |
3300 | /*! |
3301 | Sets the uniform variable array at \a location in the current |
3302 | context to the \a count 3x2 matrix elements of \a values. |
3303 | |
3304 | \sa setAttributeValue() |
3305 | */ |
3306 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count) |
3307 | { |
3308 | Q_D(QOpenGLShaderProgram); |
3309 | Q_UNUSED(d); |
3310 | setUniformGenericMatrixArray |
3311 | (d->glfuncs->glUniform2fv, location, values, count, |
3312 | QMatrix3x2, 3, 2); |
3313 | } |
3314 | |
3315 | /*! |
3316 | \overload |
3317 | |
3318 | Sets the uniform variable array called \a name in the current |
3319 | context to the \a count 3x2 matrix elements of \a values. |
3320 | |
3321 | \sa setAttributeValue() |
3322 | */ |
3323 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count) |
3324 | { |
3325 | setUniformValueArray(uniformLocation(name), values, count); |
3326 | } |
3327 | |
3328 | /*! |
3329 | Sets the uniform variable array at \a location in the current |
3330 | context to the \a count 3x3 matrix elements of \a values. |
3331 | |
3332 | \sa setAttributeValue() |
3333 | */ |
3334 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count) |
3335 | { |
3336 | Q_D(QOpenGLShaderProgram); |
3337 | Q_UNUSED(d); |
3338 | setUniformMatrixArray |
3339 | (d->glfuncs->glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3); |
3340 | } |
3341 | |
3342 | /*! |
3343 | \overload |
3344 | |
3345 | Sets the uniform variable array called \a name in the current |
3346 | context to the \a count 3x3 matrix elements of \a values. |
3347 | |
3348 | \sa setAttributeValue() |
3349 | */ |
3350 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count) |
3351 | { |
3352 | setUniformValueArray(uniformLocation(name), values, count); |
3353 | } |
3354 | |
3355 | /*! |
3356 | Sets the uniform variable array at \a location in the current |
3357 | context to the \a count 3x4 matrix elements of \a values. |
3358 | |
3359 | \sa setAttributeValue() |
3360 | */ |
3361 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count) |
3362 | { |
3363 | Q_D(QOpenGLShaderProgram); |
3364 | Q_UNUSED(d); |
3365 | setUniformGenericMatrixArray |
3366 | (d->glfuncs->glUniform4fv, location, values, count, |
3367 | QMatrix3x4, 3, 4); |
3368 | } |
3369 | |
3370 | /*! |
3371 | \overload |
3372 | |
3373 | Sets the uniform variable array called \a name in the current |
3374 | context to the \a count 3x4 matrix elements of \a values. |
3375 | |
3376 | \sa setAttributeValue() |
3377 | */ |
3378 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count) |
3379 | { |
3380 | setUniformValueArray(uniformLocation(name), values, count); |
3381 | } |
3382 | |
3383 | /*! |
3384 | Sets the uniform variable array at \a location in the current |
3385 | context to the \a count 4x2 matrix elements of \a values. |
3386 | |
3387 | \sa setAttributeValue() |
3388 | */ |
3389 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count) |
3390 | { |
3391 | Q_D(QOpenGLShaderProgram); |
3392 | Q_UNUSED(d); |
3393 | setUniformGenericMatrixArray |
3394 | (d->glfuncs->glUniform2fv, location, values, count, |
3395 | QMatrix4x2, 4, 2); |
3396 | } |
3397 | |
3398 | /*! |
3399 | \overload |
3400 | |
3401 | Sets the uniform variable array called \a name in the current |
3402 | context to the \a count 4x2 matrix elements of \a values. |
3403 | |
3404 | \sa setAttributeValue() |
3405 | */ |
3406 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count) |
3407 | { |
3408 | setUniformValueArray(uniformLocation(name), values, count); |
3409 | } |
3410 | |
3411 | /*! |
3412 | Sets the uniform variable array at \a location in the current |
3413 | context to the \a count 4x3 matrix elements of \a values. |
3414 | |
3415 | \sa setAttributeValue() |
3416 | */ |
3417 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count) |
3418 | { |
3419 | Q_D(QOpenGLShaderProgram); |
3420 | Q_UNUSED(d); |
3421 | setUniformGenericMatrixArray |
3422 | (d->glfuncs->glUniform3fv, location, values, count, |
3423 | QMatrix4x3, 4, 3); |
3424 | } |
3425 | |
3426 | /*! |
3427 | \overload |
3428 | |
3429 | Sets the uniform variable array called \a name in the current |
3430 | context to the \a count 4x3 matrix elements of \a values. |
3431 | |
3432 | \sa setAttributeValue() |
3433 | */ |
3434 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count) |
3435 | { |
3436 | setUniformValueArray(uniformLocation(name), values, count); |
3437 | } |
3438 | |
3439 | /*! |
3440 | Sets the uniform variable array at \a location in the current |
3441 | context to the \a count 4x4 matrix elements of \a values. |
3442 | |
3443 | \sa setAttributeValue() |
3444 | */ |
3445 | void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count) |
3446 | { |
3447 | Q_D(QOpenGLShaderProgram); |
3448 | Q_UNUSED(d); |
3449 | setUniformMatrixArray |
3450 | (d->glfuncs->glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4); |
3451 | } |
3452 | |
3453 | /*! |
3454 | \overload |
3455 | |
3456 | Sets the uniform variable array called \a name in the current |
3457 | context to the \a count 4x4 matrix elements of \a values. |
3458 | |
3459 | \sa setAttributeValue() |
3460 | */ |
3461 | void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count) |
3462 | { |
3463 | setUniformValueArray(uniformLocation(name), values, count); |
3464 | } |
3465 | |
3466 | /*! |
3467 | Returns the hardware limit for how many vertices a geometry shader |
3468 | can output. |
3469 | */ |
3470 | int QOpenGLShaderProgram::maxGeometryOutputVertices() const |
3471 | { |
3472 | GLint n = 0; |
3473 | Q_D(const QOpenGLShaderProgram); |
3474 | d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); |
3475 | return n; |
3476 | } |
3477 | |
3478 | /*! |
3479 | Use this function to specify to OpenGL the number of vertices in |
3480 | a patch to \a count. A patch is a custom OpenGL primitive whose interpretation |
3481 | is entirely defined by the tessellation shader stages. Therefore, calling |
3482 | this function only makes sense when using a QOpenGLShaderProgram |
3483 | containing tessellation stage shaders. When using OpenGL tessellation, |
3484 | the only primitive that can be rendered with \c{glDraw*()} functions is |
3485 | \c{GL_PATCHES}. |
3486 | |
3487 | This is equivalent to calling glPatchParameteri(GL_PATCH_VERTICES, count). |
3488 | |
3489 | \note This modifies global OpenGL state and is not specific to this |
3490 | QOpenGLShaderProgram instance. You should call this in your render |
3491 | function when needed, as QOpenGLShaderProgram will not apply this for |
3492 | you. This is purely a convenience function. |
3493 | |
3494 | \sa patchVertexCount() |
3495 | */ |
3496 | void QOpenGLShaderProgram::setPatchVertexCount(int count) |
3497 | { |
3498 | Q_D(QOpenGLShaderProgram); |
3499 | d->glfuncs->glPatchParameteri(GL_PATCH_VERTICES, count); |
3500 | } |
3501 | |
3502 | /*! |
3503 | Returns the number of vertices per-patch to be used when rendering. |
3504 | |
3505 | \note This returns the global OpenGL state value. It is not specific to |
3506 | this QOpenGLShaderProgram instance. |
3507 | |
3508 | \sa setPatchVertexCount() |
3509 | */ |
3510 | int QOpenGLShaderProgram::patchVertexCount() const |
3511 | { |
3512 | int patchVertices = 0; |
3513 | Q_D(const QOpenGLShaderProgram); |
3514 | d->glfuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices); |
3515 | return patchVertices; |
3516 | } |
3517 | |
3518 | /*! |
3519 | Sets the default outer tessellation levels to be used by the tessellation |
3520 | primitive generator in the event that the tessellation control shader |
3521 | does not output them to \a levels. For more details on OpenGL and Tessellation |
3522 | shaders see \l{OpenGL Tessellation Shaders}. |
3523 | |
3524 | The \a levels argument should be a QVector consisting of 4 floats. Not all |
3525 | of the values make sense for all tessellation modes. If you specify a vector with |
3526 | fewer than 4 elements, the remaining elements will be given a default value of 1. |
3527 | |
3528 | \note This modifies global OpenGL state and is not specific to this |
3529 | QOpenGLShaderProgram instance. You should call this in your render |
3530 | function when needed, as QOpenGLShaderProgram will not apply this for |
3531 | you. This is purely a convenience function. |
3532 | |
3533 | \note This function is only available with OpenGL >= 4.0 and is not supported |
3534 | with OpenGL ES 3.2. |
3535 | |
3536 | \sa defaultOuterTessellationLevels(), setDefaultInnerTessellationLevels() |
3537 | */ |
3538 | void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels) |
3539 | { |
3540 | #ifndef QT_OPENGL_ES_2 |
3541 | Q_D(QOpenGLShaderProgram); |
3542 | if (d->tessellationFuncs) { |
3543 | QVector<float> tessLevels = levels; |
3544 | |
3545 | // Ensure we have the required 4 outer tessellation levels |
3546 | // Use default of 1 for missing entries (same as spec) |
3547 | const int argCount = 4; |
3548 | if (tessLevels.size() < argCount) { |
3549 | tessLevels.reserve(argCount); |
3550 | for (int i = tessLevels.size(); i < argCount; ++i) |
3551 | tessLevels.append(1.0f); |
3552 | } |
3553 | d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); |
3554 | } |
3555 | #else |
3556 | Q_UNUSED(levels); |
3557 | #endif |
3558 | } |
3559 | |
3560 | /*! |
3561 | Returns the default outer tessellation levels to be used by the tessellation |
3562 | primitive generator in the event that the tessellation control shader |
3563 | does not output them. For more details on OpenGL and Tessellation shaders see |
3564 | \l{OpenGL Tessellation Shaders}. |
3565 | |
3566 | Returns a QVector of floats describing the outer tessellation levels. The vector |
3567 | will always have four elements but not all of them make sense for every mode |
3568 | of tessellation. |
3569 | |
3570 | \note This returns the global OpenGL state value. It is not specific to |
3571 | this QOpenGLShaderProgram instance. |
3572 | |
3573 | \note This function is only supported with OpenGL >= 4.0 and will not |
3574 | return valid results with OpenGL ES 3.2. |
3575 | |
3576 | \sa setDefaultOuterTessellationLevels(), defaultInnerTessellationLevels() |
3577 | */ |
3578 | QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const |
3579 | { |
3580 | #ifndef QT_OPENGL_ES_2 |
3581 | QVector<float> tessLevels(4, 1.0f); |
3582 | Q_D(const QOpenGLShaderProgram); |
3583 | if (d->tessellationFuncs) |
3584 | d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); |
3585 | return tessLevels; |
3586 | #else |
3587 | return QVector<float>(); |
3588 | #endif |
3589 | } |
3590 | |
3591 | /*! |
3592 | Sets the default outer tessellation levels to be used by the tessellation |
3593 | primitive generator in the event that the tessellation control shader |
3594 | does not output them to \a levels. For more details on OpenGL and Tessellation shaders see |
3595 | \l{OpenGL Tessellation Shaders}. |
3596 | |
3597 | The \a levels argument should be a QVector consisting of 2 floats. Not all |
3598 | of the values make sense for all tessellation modes. If you specify a vector with |
3599 | fewer than 2 elements, the remaining elements will be given a default value of 1. |
3600 | |
3601 | \note This modifies global OpenGL state and is not specific to this |
3602 | QOpenGLShaderProgram instance. You should call this in your render |
3603 | function when needed, as QOpenGLShaderProgram will not apply this for |
3604 | you. This is purely a convenience function. |
3605 | |
3606 | \note This function is only available with OpenGL >= 4.0 and is not supported |
3607 | with OpenGL ES 3.2. |
3608 | |
3609 | \sa defaultInnerTessellationLevels(), setDefaultOuterTessellationLevels() |
3610 | */ |
3611 | void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels) |
3612 | { |
3613 | #ifndef QT_OPENGL_ES_2 |
3614 | Q_D(QOpenGLShaderProgram); |
3615 | if (d->tessellationFuncs) { |
3616 | QVector<float> tessLevels = levels; |
3617 | |
3618 | // Ensure we have the required 2 inner tessellation levels |
3619 | // Use default of 1 for missing entries (same as spec) |
3620 | const int argCount = 2; |
3621 | if (tessLevels.size() < argCount) { |
3622 | tessLevels.reserve(argCount); |
3623 | for (int i = tessLevels.size(); i < argCount; ++i) |
3624 | tessLevels.append(1.0f); |
3625 | } |
3626 | d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); |
3627 | } |
3628 | #else |
3629 | Q_UNUSED(levels); |
3630 | #endif |
3631 | } |
3632 | |
3633 | /*! |
3634 | Returns the default inner tessellation levels to be used by the tessellation |
3635 | primitive generator in the event that the tessellation control shader |
3636 | does not output them. For more details on OpenGL and Tessellation shaders see |
3637 | \l{OpenGL Tessellation Shaders}. |
3638 | |
3639 | Returns a QVector of floats describing the inner tessellation levels. The vector |
3640 | will always have two elements but not all of them make sense for every mode |
3641 | of tessellation. |
3642 | |
3643 | \note This returns the global OpenGL state value. It is not specific to |
3644 | this QOpenGLShaderProgram instance. |
3645 | |
3646 | \note This function is only supported with OpenGL >= 4.0 and will not |
3647 | return valid results with OpenGL ES 3.2. |
3648 | |
3649 | \sa setDefaultInnerTessellationLevels(), defaultOuterTessellationLevels() |
3650 | */ |
3651 | QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const |
3652 | { |
3653 | #ifndef QT_OPENGL_ES_2 |
3654 | QVector<float> tessLevels(2, 1.0f); |
3655 | Q_D(const QOpenGLShaderProgram); |
3656 | if (d->tessellationFuncs) |
3657 | d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); |
3658 | return tessLevels; |
3659 | #else |
3660 | return QVector<float>(); |
3661 | #endif |
3662 | } |
3663 | |
3664 | |
3665 | /*! |
3666 | Returns \c true if shader programs written in the OpenGL Shading |
3667 | Language (GLSL) are supported on this system; false otherwise. |
3668 | |
3669 | The \a context is used to resolve the GLSL extensions. |
3670 | If \a context is \nullptr, then QOpenGLContext::currentContext() |
3671 | is used. |
3672 | */ |
3673 | bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) |
3674 | { |
3675 | if (!context) |
3676 | context = QOpenGLContext::currentContext(); |
3677 | if (!context) |
3678 | return false; |
3679 | return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); |
3680 | } |
3681 | |
3682 | /*! |
3683 | \internal |
3684 | */ |
3685 | void QOpenGLShaderProgram::shaderDestroyed() |
3686 | { |
3687 | Q_D(QOpenGLShaderProgram); |
3688 | QOpenGLShader *shader = qobject_cast<QOpenGLShader *>(sender()); |
3689 | if (shader && !d->removingShaders) |
3690 | removeShader(shader); |
3691 | } |
3692 | |
3693 | /*! |
3694 | Returns \c true if shader programs of type \a type are supported on |
3695 | this system; false otherwise. |
3696 | |
3697 | The \a context is used to resolve the GLSL extensions. |
3698 | If \a context is \nullptr, then QOpenGLContext::currentContext() |
3699 | is used. |
3700 | */ |
3701 | bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) |
3702 | { |
3703 | if (!context) |
3704 | context = QOpenGLContext::currentContext(); |
3705 | if (!context) |
3706 | return false; |
3707 | |
3708 | if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0) |
3709 | return false; |
3710 | |
3711 | if (type & QOpenGLShader::Geometry) |
3712 | return supportsGeometry(context->format()); |
3713 | else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) |
3714 | return supportsTessellation(context->format()); |
3715 | else if (type & QOpenGLShader::Compute) |
3716 | return supportsCompute(context->format()); |
3717 | |
3718 | // Unconditional support of vertex and fragment shaders implicitly assumes |
3719 | // a minimum OpenGL version of 2.0 |
3720 | return true; |
3721 | } |
3722 | |
3723 | // While unlikely, one application can in theory use contexts with different versions |
3724 | // or profiles. Therefore any version- or extension-specific checks must be done on a |
3725 | // per-context basis, not just once per process. QOpenGLSharedResource enables this, |
3726 | // although it's once-per-sharing-context-group, not per-context. Still, this should |
3727 | // be good enough in practice. |
3728 | class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource |
3729 | { |
3730 | public: |
3731 | QOpenGLProgramBinarySupportCheck(QOpenGLContext *context); |
3732 | void invalidateResource() override { } |
3733 | void freeResource(QOpenGLContext *) override { } |
3734 | |
3735 | bool isSupported() const { return m_supported; } |
3736 | |
3737 | private: |
3738 | bool m_supported; |
3739 | }; |
3740 | |
3741 | QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context) |
3742 | : QOpenGLSharedResource(context->shareGroup()), |
3743 | m_supported(false) |
3744 | { |
3745 | if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) { |
3746 | qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute" ); |
3747 | return; |
3748 | } |
3749 | if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE" )) { |
3750 | qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var" ); |
3751 | return; |
3752 | } |
3753 | |
3754 | QOpenGLContext *ctx = QOpenGLContext::currentContext(); |
3755 | if (ctx) { |
3756 | if (ctx->isOpenGLES()) { |
3757 | qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context" , ctx->format().majorVersion()); |
3758 | if (ctx->format().majorVersion() >= 3) { |
3759 | m_supported = true; |
3760 | } else { |
3761 | const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary" ); |
3762 | qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d" , hasExt); |
3763 | if (hasExt) |
3764 | m_supported = true; |
3765 | } |
3766 | } else { |
3767 | const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary" ); |
3768 | qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d" , hasExt); |
3769 | if (hasExt) |
3770 | m_supported = true; |
3771 | } |
3772 | if (m_supported) { |
3773 | GLint fmtCount = 0; |
3774 | ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount); |
3775 | qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d" , fmtCount); |
3776 | m_supported = fmtCount > 0; |
3777 | } |
3778 | } |
3779 | qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d" , m_supported); |
3780 | } |
3781 | |
3782 | class QOpenGLProgramBinarySupportCheckWrapper |
3783 | { |
3784 | public: |
3785 | QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context) |
3786 | { |
3787 | return m_resource.value<QOpenGLProgramBinarySupportCheck>(context); |
3788 | } |
3789 | |
3790 | private: |
3791 | QOpenGLMultiGroupSharedResource m_resource; |
3792 | }; |
3793 | |
3794 | bool QOpenGLShaderProgramPrivate::isCacheDisabled() const |
3795 | { |
3796 | static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck; |
3797 | return !binSupportCheck.get(QOpenGLContext::currentContext())->isSupported(); |
3798 | } |
3799 | |
3800 | bool QOpenGLShaderProgramPrivate::compileCacheable() |
3801 | { |
3802 | Q_Q(QOpenGLShaderProgram); |
3803 | for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) { |
3804 | QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q)); |
3805 | if (!s->compileSourceCode(shader.source)) { |
3806 | log = s->log(); |
3807 | return false; |
3808 | } |
3809 | anonShaders.append(s.take()); |
3810 | if (!q->addShader(anonShaders.last())) |
3811 | return false; |
3812 | } |
3813 | return true; |
3814 | } |
3815 | |
3816 | bool QOpenGLShaderProgramPrivate::linkBinary() |
3817 | { |
3818 | static QOpenGLProgramBinaryCache binCache; |
3819 | |
3820 | Q_Q(QOpenGLShaderProgram); |
3821 | |
3822 | QCryptographicHash keyBuilder(QCryptographicHash::Sha1); |
3823 | for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) |
3824 | keyBuilder.addData(shader.source); |
3825 | |
3826 | const QByteArray cacheKey = keyBuilder.result().toHex(); |
3827 | if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg)) |
3828 | qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s" , |
3829 | binaryProgram.shaders.count(), cacheKey.constData()); |
3830 | |
3831 | bool needsCompile = true; |
3832 | if (binCache.load(cacheKey, q->programId())) { |
3833 | qCDebug(DBG_SHADER_CACHE, "Program binary received from cache" ); |
3834 | needsCompile = false; |
3835 | } |
3836 | |
3837 | bool needsSave = false; |
3838 | if (needsCompile) { |
3839 | qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling" ); |
3840 | if (compileCacheable()) |
3841 | needsSave = true; |
3842 | else |
3843 | return false; |
3844 | } |
3845 | |
3846 | linkBinaryRecursion = true; |
3847 | bool ok = q->link(); |
3848 | linkBinaryRecursion = false; |
3849 | if (ok && needsSave) |
3850 | binCache.save(cacheKey, q->programId()); |
3851 | |
3852 | return ok; |
3853 | } |
3854 | |
3855 | QT_END_NAMESPACE |
3856 | |