source: trunk/src/opengl/qglshaderprogram.cpp@ 729

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

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 82.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qglshaderprogram.h"
43#include "qglextensions_p.h"
44#include "qgl_p.h"
45#include <QtCore/private/qobject_p.h>
46#include <QtCore/qdebug.h>
47#include <QtCore/qfile.h>
48#include <QtCore/qvarlengtharray.h>
49#include <QtCore/qvector.h>
50
51QT_BEGIN_NAMESPACE
52
53#if !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
54
55/*!
56 \class QGLShaderProgram
57 \brief The QGLShaderProgram class allows OpenGL shader programs to be linked and used.
58 \since 4.6
59 \ingroup painting-3D
60
61 \section1 Introduction
62
63 This class supports shader programs written in the OpenGL Shading
64 Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES).
65
66 QGLShader and QGLShaderProgram shelter the programmer from the details of
67 compiling and linking vertex and fragment shaders.
68
69 The following example creates a vertex shader program using the
70 supplied source \c{code}. Once compiled and linked, the shader
71 program is activated in the current QGLContext by calling
72 QGLShaderProgram::bind():
73
74 \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 0
75
76 \section1 Writing portable shaders
77
78 Shader programs can be difficult to reuse across OpenGL implementations
79 because of varying levels of support for standard vertex attributes and
80 uniform variables. In particular, GLSL/ES lacks all of the
81 standard variables that are present on desktop OpenGL systems:
82 \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL
83 lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}.
84
85 The QGLShaderProgram class makes the process of writing portable shaders
86 easier by prefixing all shader programs with the following lines on
87 desktop OpenGL:
88
89 \code
90 #define highp
91 #define mediump
92 #define lowp
93 \endcode
94
95 This makes it possible to run most GLSL/ES shader programs
96 on desktop systems. The programmer should restrict themselves
97 to just features that are present in GLSL/ES, and avoid
98 standard variable names that only work on the desktop.
99
100 \section1 Simple shader example
101
102 \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 1
103
104 With the above shader program active, we can draw a green triangle
105 as follows:
106
107 \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 2
108
109 \section1 Binary shaders and programs
110
111 Binary shaders may be specified using \c{glShaderBinary()} on
112 the return value from QGLShader::shaderId(). The QGLShader instance
113 containing the binary can then be added to the shader program with
114 addShader() and linked in the usual fashion with link().
115
116 Binary programs may be specified using \c{glProgramBinaryOES()}
117 on the return value from programId(). Then the application should
118 call link(), which will notice that the program has already been
119 specified and linked, allowing other operations to be performed
120 on the shader program.
121
122 \sa QGLShader
123*/
124
125/*!
126 \class QGLShader
127 \brief The QGLShader class allows OpenGL shaders to be compiled.
128 \since 4.6
129 \ingroup painting-3D
130
131 This class supports shaders written in the OpenGL Shading Language (GLSL)
132 and in the OpenGL/ES Shading Language (GLSL/ES).
133
134 QGLShader and QGLShaderProgram shelter the programmer from the details of
135 compiling and linking vertex and fragment shaders.
136
137 \sa QGLShaderProgram
138*/
139
140/*!
141 \enum QGLShader::ShaderTypeBit
142 This enum specifies the type of QGLShader that is being created.
143
144 \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
145 \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
146*/
147
148#ifndef GL_FRAGMENT_SHADER
149#define GL_FRAGMENT_SHADER 0x8B30
150#endif
151#ifndef GL_VERTEX_SHADER
152#define GL_VERTEX_SHADER 0x8B31
153#endif
154#ifndef GL_COMPILE_STATUS
155#define GL_COMPILE_STATUS 0x8B81
156#endif
157#ifndef GL_LINK_STATUS
158#define GL_LINK_STATUS 0x8B82
159#endif
160#ifndef GL_INFO_LOG_LENGTH
161#define GL_INFO_LOG_LENGTH 0x8B84
162#endif
163#ifndef GL_ACTIVE_UNIFORMS
164#define GL_ACTIVE_UNIFORMS 0x8B86
165#endif
166#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH
167#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
168#endif
169#ifndef GL_ACTIVE_ATTRIBUTES
170#define GL_ACTIVE_ATTRIBUTES 0x8B89
171#endif
172#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
173#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
174#endif
175#ifndef GL_CURRENT_VERTEX_ATTRIB
176#define GL_CURRENT_VERTEX_ATTRIB 0x8626
177#endif
178#ifndef GL_SHADER_SOURCE_LENGTH
179#define GL_SHADER_SOURCE_LENGTH 0x8B88
180#endif
181#ifndef GL_SHADER_BINARY_FORMATS
182#define GL_SHADER_BINARY_FORMATS 0x8DF8
183#endif
184#ifndef GL_NUM_SHADER_BINARY_FORMATS
185#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
186#endif
187
188class QGLShaderPrivate : public QObjectPrivate
189{
190 Q_DECLARE_PUBLIC(QGLShader)
191public:
192 QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
193 : shaderGuard(context)
194 , shaderType(type)
195 , compiled(false)
196 {
197 }
198 ~QGLShaderPrivate();
199
200 QGLSharedResourceGuard shaderGuard;
201 QGLShader::ShaderType shaderType;
202 bool compiled;
203 QString log;
204
205 bool create();
206 bool compile(QGLShader *q);
207 void deleteShader();
208};
209
210#define ctx shaderGuard.context()
211
212QGLShaderPrivate::~QGLShaderPrivate()
213{
214 if (shaderGuard.id()) {
215 QGLShareContextScope scope(shaderGuard.context());
216 glDeleteShader(shaderGuard.id());
217 }
218}
219
220bool QGLShaderPrivate::create()
221{
222 const QGLContext *context = shaderGuard.context();
223 if (!context)
224 return false;
225 if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
226 GLuint shader;
227 if (shaderType == QGLShader::Vertex)
228 shader = glCreateShader(GL_VERTEX_SHADER);
229 else
230 shader = glCreateShader(GL_FRAGMENT_SHADER);
231 if (!shader) {
232 qWarning() << "QGLShader: could not create shader";
233 return false;
234 }
235 shaderGuard.setId(shader);
236 return true;
237 } else {
238 return false;
239 }
240}
241
242bool QGLShaderPrivate::compile(QGLShader *q)
243{
244 GLuint shader = shaderGuard.id();
245 if (!shader)
246 return false;
247 glCompileShader(shader);
248 GLint value = 0;
249 glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
250 compiled = (value != 0);
251 value = 0;
252 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value);
253 if (!compiled && value > 1) {
254 char *logbuf = new char [value];
255 GLint len;
256 glGetShaderInfoLog(shader, value, &len, logbuf);
257 log = QString::fromLatin1(logbuf);
258 QString name = q->objectName();
259 if (name.isEmpty())
260 qWarning() << "QGLShader::compile:" << log;
261 else
262 qWarning() << "QGLShader::compile[" << name << "]:" << log;
263 delete [] logbuf;
264 }
265 return compiled;
266}
267
268void QGLShaderPrivate::deleteShader()
269{
270 if (shaderGuard.id()) {
271 glDeleteShader(shaderGuard.id());
272 shaderGuard.setId(0);
273 }
274}
275
276#undef ctx
277#define ctx d->shaderGuard.context()
278
279/*!
280 Constructs a new QGLShader object of the specified \a type
281 and attaches it to \a parent. If shader programs are not supported,
282 QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
283
284 This constructor is normally followed by a call to compileSourceCode()
285 or compileSourceFile().
286
287 The shader will be associated with the current QGLContext.
288
289 \sa compileSourceCode(), compileSourceFile()
290*/
291QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent)
292 : QObject(*new QGLShaderPrivate(QGLContext::currentContext(), type), parent)
293{
294 Q_D(QGLShader);
295 d->create();
296}
297
298/*!
299 Constructs a new QGLShader object of the specified \a type
300 and attaches it to \a parent. If shader programs are not supported,
301 then QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
302
303 This constructor is normally followed by a call to compileSourceCode()
304 or compileSourceFile().
305
306 The shader will be associated with \a context.
307
308 \sa compileSourceCode(), compileSourceFile()
309*/
310QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent)
311 : QObject(*new QGLShaderPrivate(context ? context : QGLContext::currentContext(), type), parent)
312{
313 Q_D(QGLShader);
314#ifndef QT_NO_DEBUG
315 if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) {
316 qWarning("QGLShader::QGLShader: \'context\' must be the current context or sharing with it.");
317 return;
318 }
319#endif
320 d->create();
321}
322
323/*!
324 Deletes this shader. If the shader has been attached to a
325 QGLShaderProgram object, then the actual shader will stay around
326 until the QGLShaderProgram is destroyed.
327*/
328QGLShader::~QGLShader()
329{
330}
331
332/*!
333 Returns the type of this shader.
334*/
335QGLShader::ShaderType QGLShader::shaderType() const
336{
337 Q_D(const QGLShader);
338 return d->shaderType;
339}
340
341// The precision qualifiers are useful on OpenGL/ES systems,
342// but usually not present on desktop systems. Define the
343// keywords to empty strings on desktop systems.
344#ifndef QT_OPENGL_ES
345#define QGL_DEFINE_QUALIFIERS 1
346static const char qualifierDefines[] =
347 "#define lowp\n"
348 "#define mediump\n"
349 "#define highp\n";
350#endif
351
352// The "highp" qualifier doesn't exist in fragment shaders
353// on all ES platforms. When it doesn't exist, use "mediump".
354#ifdef QT_OPENGL_ES
355#define QGL_REDEFINE_HIGHP 1
356static const char redefineHighp[] =
357 "#ifndef GL_FRAGMENT_PRECISION_HIGH\n"
358 "#define highp mediump\n"
359 "#endif\n";
360#endif
361
362/*!
363 Sets the \a source code for this shader and compiles it.
364 Returns true if the source was successfully compiled, false otherwise.
365
366 \sa compileSourceFile()
367*/
368bool QGLShader::compileSourceCode(const char *source)
369{
370 Q_D(QGLShader);
371 if (d->shaderGuard.id()) {
372 QVarLengthArray<const char *, 4> src;
373 QVarLengthArray<GLint, 4> srclen;
374 int headerLen = 0;
375 while (source && source[headerLen] == '#') {
376 // Skip #version and #extension directives at the start of
377 // the shader code. We need to insert the qualifierDefines
378 // and redefineHighp just after them.
379 if (qstrncmp(source + headerLen, "#version", 8) != 0 &&
380 qstrncmp(source + headerLen, "#extension", 10) != 0) {
381 break;
382 }
383 while (source[headerLen] != '\0' && source[headerLen] != '\n')
384 ++headerLen;
385 if (source[headerLen] == '\n')
386 ++headerLen;
387 }
388 if (headerLen > 0) {
389 src.append(source);
390 srclen.append(GLint(headerLen));
391 }
392#ifdef QGL_DEFINE_QUALIFIERS
393 src.append(qualifierDefines);
394 srclen.append(GLint(sizeof(qualifierDefines) - 1));
395#endif
396#ifdef QGL_REDEFINE_HIGHP
397 if (d->shaderType == Fragment) {
398 src.append(redefineHighp);
399 srclen.append(GLint(sizeof(redefineHighp) - 1));
400 }
401#endif
402 src.append(source + headerLen);
403 srclen.append(GLint(qstrlen(source + headerLen)));
404 glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
405 return d->compile(this);
406 } else {
407 return false;
408 }
409}
410
411/*!
412 \overload
413
414 Sets the \a source code for this shader and compiles it.
415 Returns true if the source was successfully compiled, false otherwise.
416
417 \sa compileSourceFile()
418*/
419bool QGLShader::compileSourceCode(const QByteArray& source)
420{
421 return compileSourceCode(source.constData());
422}
423
424/*!
425 \overload
426
427 Sets the \a source code for this shader and compiles it.
428 Returns true if the source was successfully compiled, false otherwise.
429
430 \sa compileSourceFile()
431*/
432bool QGLShader::compileSourceCode(const QString& source)
433{
434 return compileSourceCode(source.toLatin1().constData());
435}
436
437/*!
438 Sets the source code for this shader to the contents of \a fileName
439 and compiles it. Returns true if the file could be opened and the
440 source compiled, false otherwise.
441
442 \sa compileSourceCode()
443*/
444bool QGLShader::compileSourceFile(const QString& fileName)
445{
446 QFile file(fileName);
447 if (!file.open(QFile::ReadOnly)) {
448 qWarning() << "QGLShader: Unable to open file" << fileName;
449 return false;
450 }
451
452 QByteArray contents = file.readAll();
453 return compileSourceCode(contents.constData());
454}
455
456/*!
457 Returns the source code for this shader.
458
459 \sa compileSourceCode()
460*/
461QByteArray QGLShader::sourceCode() const
462{
463 Q_D(const QGLShader);
464 GLuint shader = d->shaderGuard.id();
465 if (!shader)
466 return QByteArray();
467 GLint size = 0;
468 glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size);
469 if (size <= 0)
470 return QByteArray();
471 GLint len = 0;
472 char *source = new char [size];
473 glGetShaderSource(shader, size, &len, source);
474 QByteArray src(source);
475 delete [] source;
476 return src;
477}
478
479/*!
480 Returns true if this shader has been compiled; false otherwise.
481
482 \sa compileSourceCode(), compileSourceFile()
483*/
484bool QGLShader::isCompiled() const
485{
486 Q_D(const QGLShader);
487 return d->compiled;
488}
489
490/*!
491 Returns the errors and warnings that occurred during the last compile.
492
493 \sa compileSourceCode(), compileSourceFile()
494*/
495QString QGLShader::log() const
496{
497 Q_D(const QGLShader);
498 return d->log;
499}
500
501/*!
502 Returns the OpenGL identifier associated with this shader.
503
504 \sa QGLShaderProgram::programId()
505*/
506GLuint QGLShader::shaderId() const
507{
508 Q_D(const QGLShader);
509 return d->shaderGuard.id();
510}
511
512#undef ctx
513#define ctx programGuard.context()
514
515class QGLShaderProgramPrivate : public QObjectPrivate
516{
517 Q_DECLARE_PUBLIC(QGLShaderProgram)
518public:
519 QGLShaderProgramPrivate(const QGLContext *context)
520 : programGuard(context)
521 , linked(false)
522 , inited(false)
523 , removingShaders(false)
524 , vertexShader(0)
525 , fragmentShader(0)
526 {
527 }
528 ~QGLShaderProgramPrivate();
529
530 QGLSharedResourceGuard programGuard;
531 bool linked;
532 bool inited;
533 bool removingShaders;
534 QString log;
535 QList<QGLShader *> shaders;
536 QList<QGLShader *> anonShaders;
537 QGLShader *vertexShader;
538 QGLShader *fragmentShader;
539
540 bool hasShader(QGLShader::ShaderType type) const;
541};
542
543QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
544{
545 if (programGuard.id()) {
546 QGLShareContextScope scope(programGuard.context());
547 glDeleteProgram(programGuard.id());
548 }
549}
550
551bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
552{
553 foreach (QGLShader *shader, shaders) {
554 if (shader->shaderType() == type)
555 return true;
556 }
557 return false;
558}
559
560#undef ctx
561#define ctx d->programGuard.context()
562
563/*!
564 Constructs a new shader program and attaches it to \a parent.
565 The program will be invalid until addShader() is called.
566
567 The shader program will be associated with the current QGLContext.
568
569 \sa addShader()
570*/
571QGLShaderProgram::QGLShaderProgram(QObject *parent)
572 : QObject(*new QGLShaderProgramPrivate(QGLContext::currentContext()), parent)
573{
574}
575
576/*!
577 Constructs a new shader program and attaches it to \a parent.
578 The program will be invalid until addShader() is called.
579
580 The shader program will be associated with \a context.
581
582 \sa addShader()
583*/
584QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent)
585 : QObject(*new QGLShaderProgramPrivate(context), parent)
586{
587}
588
589/*!
590 Deletes this shader program.
591*/
592QGLShaderProgram::~QGLShaderProgram()
593{
594}
595
596bool QGLShaderProgram::init()
597{
598 Q_D(QGLShaderProgram);
599 if (d->programGuard.id() || d->inited)
600 return true;
601 d->inited = true;
602 const QGLContext *context = d->programGuard.context();
603 if (!context) {
604 context = QGLContext::currentContext();
605 d->programGuard.setContext(context);
606 }
607 if (!context)
608 return false;
609 if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
610 GLuint program = glCreateProgram();
611 if (!program) {
612 qWarning() << "QGLShaderProgram: could not create shader program";
613 return false;
614 }
615 d->programGuard.setId(program);
616 return true;
617 } else {
618 qWarning() << "QGLShaderProgram: shader programs are not supported";
619 return false;
620 }
621}
622
623/*!
624 Adds a compiled \a shader to this shader program. Returns true
625 if the shader could be added, or false otherwise.
626
627 Ownership of the \a shader object remains with the caller.
628 It will not be deleted when this QGLShaderProgram instance
629 is deleted. This allows the caller to add the same shader
630 to multiple shader programs.
631
632 \sa addShaderFromSourceCode(), addShaderFromSourceFile()
633 \sa removeShader(), link(), removeAllShaders()
634*/
635bool QGLShaderProgram::addShader(QGLShader *shader)
636{
637 Q_D(QGLShaderProgram);
638 if (!init())
639 return false;
640 if (d->shaders.contains(shader))
641 return true; // Already added to this shader program.
642 if (d->programGuard.id() && shader) {
643 if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
644 d->programGuard.context())) {
645 qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
646 return false;
647 }
648 if (!shader->d_func()->shaderGuard.id())
649 return false;
650 glAttachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
651 d->linked = false; // Program needs to be relinked.
652 d->shaders.append(shader);
653 connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
654 return true;
655 } else {
656 return false;
657 }
658}
659
660/*!
661 Compiles \a source as a shader of the specified \a type and
662 adds it to this shader program. Returns true if compilation
663 was successful, false otherwise. The compilation errors
664 and warnings will be made available via log().
665
666 This function is intended to be a short-cut for quickly
667 adding vertex and fragment shaders to a shader program without
668 creating an instance of QGLShader first.
669
670 \sa addShader(), addShaderFromSourceFile()
671 \sa removeShader(), link(), log(), removeAllShaders()
672*/
673bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const char *source)
674{
675 Q_D(QGLShaderProgram);
676 if (!init())
677 return false;
678 QGLShader *shader = new QGLShader(type, this);
679 if (!shader->compileSourceCode(source)) {
680 d->log = shader->log();
681 delete shader;
682 return false;
683 }
684 d->anonShaders.append(shader);
685 return addShader(shader);
686}
687
688/*!
689 \overload
690
691 Compiles \a source as a shader of the specified \a type and
692 adds it to this shader program. Returns true if compilation
693 was successful, false otherwise. The compilation errors
694 and warnings will be made available via log().
695
696 This function is intended to be a short-cut for quickly
697 adding vertex and fragment shaders to a shader program without
698 creating an instance of QGLShader first.
699
700 \sa addShader(), addShaderFromSourceFile()
701 \sa removeShader(), link(), log(), removeAllShaders()
702*/
703bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source)
704{
705 return addShaderFromSourceCode(type, source.constData());
706}
707
708/*!
709 \overload
710
711 Compiles \a source as a shader of the specified \a type and
712 adds it to this shader program. Returns true if compilation
713 was successful, false otherwise. The compilation errors
714 and warnings will be made available via log().
715
716 This function is intended to be a short-cut for quickly
717 adding vertex and fragment shaders to a shader program without
718 creating an instance of QGLShader first.
719
720 \sa addShader(), addShaderFromSourceFile()
721 \sa removeShader(), link(), log(), removeAllShaders()
722*/
723bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source)
724{
725 return addShaderFromSourceCode(type, source.toLatin1().constData());
726}
727
728/*!
729 Compiles the contents of \a fileName as a shader of the specified
730 \a type and adds it to this shader program. Returns true if
731 compilation was successful, false otherwise. The compilation errors
732 and warnings will be made available via log().
733
734 This function is intended to be a short-cut for quickly
735 adding vertex and fragment shaders to a shader program without
736 creating an instance of QGLShader first.
737
738 \sa addShader(), addShaderFromSourceCode()
739*/
740bool QGLShaderProgram::addShaderFromSourceFile
741 (QGLShader::ShaderType type, const QString& fileName)
742{
743 Q_D(QGLShaderProgram);
744 if (!init())
745 return false;
746 QGLShader *shader = new QGLShader(type, this);
747 if (!shader->compileSourceFile(fileName)) {
748 d->log = shader->log();
749 delete shader;
750 return false;
751 }
752 d->anonShaders.append(shader);
753 return addShader(shader);
754}
755
756/*!
757 Removes \a shader from this shader program. The object is not deleted.
758
759 \sa addShader(), link(), removeAllShaders()
760*/
761void QGLShaderProgram::removeShader(QGLShader *shader)
762{
763 Q_D(QGLShaderProgram);
764 if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
765 QGLShareContextScope scope(d->programGuard.context());
766 glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
767 }
768 d->linked = false; // Program needs to be relinked.
769 if (shader) {
770 d->shaders.removeAll(shader);
771 d->anonShaders.removeAll(shader);
772 disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
773 }
774}
775
776/*!
777 Returns a list of all shaders that have been added to this shader
778 program using addShader().
779
780 \sa addShader(), removeShader()
781*/
782QList<QGLShader *> QGLShaderProgram::shaders() const
783{
784 Q_D(const QGLShaderProgram);
785 return d->shaders;
786}
787
788/*!
789 Removes all of the shaders that were added to this program previously.
790 The QGLShader objects for the shaders will not be deleted if they
791 were constructed externally. QGLShader objects that are constructed
792 internally by QGLShaderProgram will be deleted.
793
794 \sa addShader(), removeShader()
795*/
796void QGLShaderProgram::removeAllShaders()
797{
798 Q_D(QGLShaderProgram);
799 d->removingShaders = true;
800 foreach (QGLShader *shader, d->shaders) {
801 if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
802 glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
803 }
804 foreach (QGLShader *shader, d->anonShaders) {
805 // Delete shader objects that were created anonymously.
806 delete shader;
807 }
808 d->shaders.clear();
809 d->anonShaders.clear();
810 d->linked = false; // Program needs to be relinked.
811 d->removingShaders = false;
812}
813
814/*!
815 Links together the shaders that were added to this program with
816 addShader(). Returns true if the link was successful or
817 false otherwise. If the link failed, the error messages can
818 be retrieved with log().
819
820 Subclasses can override this function to initialize attributes
821 and uniform variables for use in specific shader programs.
822
823 If the shader program was already linked, calling this
824 function again will force it to be re-linked.
825
826 \sa addShader(), log()
827*/
828bool QGLShaderProgram::link()
829{
830 Q_D(QGLShaderProgram);
831 GLuint program = d->programGuard.id();
832 if (!program)
833 return false;
834 GLint value;
835 if (d->shaders.isEmpty()) {
836 // If there are no explicit shaders, then it is possible that the
837 // application added a program binary with glProgramBinaryOES(),
838 // or otherwise populated the shaders itself. Check to see if the
839 // program is already linked and bail out if so.
840 value = 0;
841 glGetProgramiv(program, GL_LINK_STATUS, &value);
842 d->linked = (value != 0);
843 if (d->linked)
844 return true;
845 }
846 glLinkProgram(program);
847 value = 0;
848 glGetProgramiv(program, GL_LINK_STATUS, &value);
849 d->linked = (value != 0);
850 value = 0;
851 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value);
852 d->log = QString();
853 if (value > 1) {
854 char *logbuf = new char [value];
855 GLint len;
856 glGetProgramInfoLog(program, value, &len, logbuf);
857 d->log = QString::fromLatin1(logbuf);
858 QString name = objectName();
859 if (name.isEmpty())
860 qWarning() << "QGLShader::link:" << d->log;
861 else
862 qWarning() << "QGLShader::link[" << name << "]:" << d->log;
863 delete [] logbuf;
864 }
865 return d->linked;
866}
867
868/*!
869 Returns true if this shader program has been linked; false otherwise.
870
871 \sa link()
872*/
873bool QGLShaderProgram::isLinked() const
874{
875 Q_D(const QGLShaderProgram);
876 return d->linked;
877}
878
879/*!
880 Returns the errors and warnings that occurred during the last link()
881 or addShader() with explicitly specified source code.
882
883 \sa link()
884*/
885QString QGLShaderProgram::log() const
886{
887 Q_D(const QGLShaderProgram);
888 return d->log;
889}
890
891/*!
892 Binds this shader program to the active QGLContext and makes
893 it the current shader program. Any previously bound shader program
894 is released. This is equivalent to calling \c{glUseProgram()} on
895 programId(). Returns true if the program was successfully bound;
896 false otherwise. If the shader program has not yet been linked,
897 or it needs to be re-linked, this function will call link().
898
899 \sa link(), release()
900*/
901bool QGLShaderProgram::bind()
902{
903 Q_D(QGLShaderProgram);
904 GLuint program = d->programGuard.id();
905 if (!program)
906 return false;
907 if (!d->linked && !link())
908 return false;
909#ifndef QT_NO_DEBUG
910 if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) {
911 qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
912 return false;
913 }
914#endif
915 glUseProgram(program);
916 return true;
917}