blob: 7e89d9c8d4cdd46046d82852eb42d29ac22aa64b [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopenglshaderprogram.h"
#include "qopenglprogrambinarycache_p.h"
#include "qopenglextrafunctions.h"
#include "private/qopenglcontext_p.h"
#include <QtCore/private/qobject_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qloggingcategory.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
#if !defined(QT_OPENGL_ES_2)
#include <QtGui/qopenglfunctions_4_0_core.h>
#endif
#include <algorithm>
QT_BEGIN_NAMESPACE
/*!
\class QOpenGLShaderProgram
\brief The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used.
\since 5.0
\ingroup painting-3D
\inmodule QtGui
\section1 Introduction
This class supports shader programs written in the OpenGL Shading
Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES).
QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of
compiling and linking vertex and fragment shaders.
The following example creates a vertex shader program using the
supplied source \c{code}. Once compiled and linked, the shader
program is activated in the current QOpenGLContext by calling
QOpenGLShaderProgram::bind():
\snippet code/src_gui_qopenglshaderprogram.cpp 0
\section1 Writing Portable Shaders
Shader programs can be difficult to reuse across OpenGL implementations
because of varying levels of support for standard vertex attributes and
uniform variables. In particular, GLSL/ES lacks all of the
standard variables that are present on desktop OpenGL systems:
\c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL
lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}.
The QOpenGLShaderProgram class makes the process of writing portable shaders
easier by prefixing all shader programs with the following lines on
desktop OpenGL:
\code
#define highp
#define mediump
#define lowp
\endcode
This makes it possible to run most GLSL/ES shader programs
on desktop systems. The programmer should restrict themselves
to just features that are present in GLSL/ES, and avoid
standard variable names that only work on the desktop.
\section1 Simple Shader Example
\snippet code/src_gui_qopenglshaderprogram.cpp 1
With the above shader program active, we can draw a green triangle
as follows:
\snippet code/src_gui_qopenglshaderprogram.cpp 2
\section1 Binary Shaders and Programs
Binary shaders may be specified using \c{glShaderBinary()} on
the return value from QOpenGLShader::shaderId(). The QOpenGLShader instance
containing the binary can then be added to the shader program with
addShader() and linked in the usual fashion with link().
Binary programs may be specified using \c{glProgramBinaryOES()}
on the return value from programId(). Then the application should
call link(), which will notice that the program has already been
specified and linked, allowing other operations to be performed
on the shader program. The shader program's id can be explicitly
created using the create() function.
\section2 Caching Program Binaries
As of Qt 5.9, support for caching program binaries on disk is built in. To
enable this, switch to using addCacheableShaderFromSourceCode() and
addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support
for \c{GL_ARB_get_program_binary}, this will transparently cache program
binaries under QStandardPaths::GenericCacheLocation or
QStandardPaths::CacheLocation. When support is not available, calling the
cacheable function variants is equivalent to the normal ones.
\note Some drivers do not have any binary formats available, even though
they advertise the extension or offer OpenGL ES 3.0. In this case program
binary support will be disabled.
\sa QOpenGLShader
*/
/*!
\class QOpenGLShader
\brief The QOpenGLShader class allows OpenGL shaders to be compiled.
\since 5.0
\ingroup painting-3D
\inmodule QtGui
This class supports shaders written in the OpenGL Shading Language (GLSL)
and in the OpenGL/ES Shading Language (GLSL/ES).
QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of
compiling and linking vertex and fragment shaders.
\sa QOpenGLShaderProgram
*/
/*!
\enum QOpenGLShader::ShaderTypeBit
This enum specifies the type of QOpenGLShader that is being created.
\value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
\value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
\value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL)
(requires OpenGL >= 3.2 or OpenGL ES >= 3.2).
\value TessellationControl Tessellation control shaders written in the OpenGL
shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2).
\value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL
shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2).
\value Compute Compute shaders written in the OpenGL shading language (GLSL)
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
// For GLES 3.1/3.2
#ifndef GL_GEOMETRY_SHADER
#define GL_GEOMETRY_SHADER 0x8DD9
#endif
#ifndef GL_TESS_CONTROL_SHADER
#define GL_TESS_CONTROL_SHADER 0x8E88
#endif
#ifndef GL_TESS_EVALUATION_SHADER
#define GL_TESS_EVALUATION_SHADER 0x8E87
#endif
#ifndef GL_COMPUTE_SHADER
#define GL_COMPUTE_SHADER 0x91B9
#endif
#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES
#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
#endif
#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS
#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
#endif
#ifndef GL_PATCH_VERTICES
#define GL_PATCH_VERTICES 0x8E72
#endif
#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL
#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
#endif
#ifndef GL_PATCH_DEFAULT_INNER_LEVEL
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#endif
#ifndef QT_OPENGL_ES_2
static inline bool isFormatGLES(const QSurfaceFormat &f)
{
return (f.renderableType() == QSurfaceFormat::OpenGLES);
}
#endif
static inline bool supportsGeometry(const QSurfaceFormat &f)
{
return f.version() >= qMakePair(3, 2);
}
static inline bool supportsCompute(const QSurfaceFormat &f)
{
#ifndef QT_OPENGL_ES_2
if (!isFormatGLES(f))
return f.version() >= qMakePair(4, 3);
else
return f.version() >= qMakePair(3, 1);
#else
return f.version() >= qMakePair(3, 1);
#endif
}
static inline bool supportsTessellation(const QSurfaceFormat &f)
{
#ifndef QT_OPENGL_ES_2
if (!isFormatGLES(f))
return f.version() >= qMakePair(4, 0);
else
return f.version() >= qMakePair(3, 2);
#else
return f.version() >= qMakePair(3, 2);
#endif
}
class QOpenGLShaderPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOpenGLShader)
public:
QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type)
: shaderGuard(nullptr)
, shaderType(type)
, compiled(false)
, glfuncs(new QOpenGLExtraFunctions(ctx))
, supportsGeometryShaders(false)
, supportsTessellationShaders(false)
, supportsComputeShaders(false)
{
if (shaderType & QOpenGLShader::Geometry)
supportsGeometryShaders = supportsGeometry(ctx->format());
else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation))
supportsTessellationShaders = supportsTessellation(ctx->format());
else if (shaderType & QOpenGLShader::Compute)
supportsComputeShaders = supportsCompute(ctx->format());
}
~QOpenGLShaderPrivate();
QOpenGLSharedResourceGuard *shaderGuard;
QOpenGLShader::ShaderType shaderType;
bool compiled;
QString log;
QOpenGLExtraFunctions *glfuncs;
// Support for geometry shaders
bool supportsGeometryShaders;
// Support for tessellation shaders
bool supportsTessellationShaders;
// Support for compute shaders
bool supportsComputeShaders;
bool create();
bool compile(QOpenGLShader *q);
void deleteShader();
};
namespace {
void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id)
{
funcs->glDeleteShader(id);
}
}
QOpenGLShaderPrivate::~QOpenGLShaderPrivate()
{
delete glfuncs;
if (shaderGuard)
shaderGuard->free();
}
bool QOpenGLShaderPrivate::create()
{
QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (!context)
return false;
GLuint shader = 0;
if (shaderType == QOpenGLShader::Vertex) {
shader = glfuncs->glCreateShader(GL_VERTEX_SHADER);
} else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) {
shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER);
} else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) {
shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER);
} else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) {
shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER);
} else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) {
shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER);
} else if (shaderType == QOpenGLShader::Fragment) {
shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER);
}
if (!shader) {
qWarning("QOpenGLShader: could not create shader");
return false;
}
shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc);
return true;
}
bool QOpenGLShaderPrivate::compile(QOpenGLShader *q)
{
GLuint shader = shaderGuard ? shaderGuard->id() : 0;
if (!shader)
return false;
// Try to compile shader
glfuncs->glCompileShader(shader);
GLint value = 0;
// Get compilation status
glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
compiled = (value != 0);
if (!compiled) {
// Compilation failed, try to provide some information about the failure
QString name = q->objectName();
const char *types[] = {
"Fragment",
"Vertex",
"Geometry",
"Tessellation Control",
"Tessellation Evaluation",
"Compute",
""
};
const char *type = types[6];
switch (shaderType) {
case QOpenGLShader::Fragment:
type = types[0]; break;
case QOpenGLShader::Vertex:
type = types[1]; break;
case QOpenGLShader::Geometry:
type = types[2]; break;
case QOpenGLShader::TessellationControl:
type = types[3]; break;
case QOpenGLShader::TessellationEvaluation:
type = types[4]; break;
case QOpenGLShader::Compute:
type = types[5]; break;
}
// Get info and source code lengths
GLint infoLogLength = 0;
GLint sourceCodeLength = 0;
char *logBuffer = nullptr;
char *sourceCodeBuffer = nullptr;
// Get the compilation info log
glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) {
GLint temp;
logBuffer = new char [infoLogLength];
glfuncs->glGetShaderInfoLog(shader, infoLogLength, &temp, logBuffer);
}
// Get the source code
glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceCodeLength);
if (sourceCodeLength > 1) {
GLint temp;
sourceCodeBuffer = new char [sourceCodeLength];
glfuncs->glGetShaderSource(shader, sourceCodeLength, &temp, sourceCodeBuffer);
}
if (logBuffer)
log = QString::fromLatin1(logBuffer);
else
log = QLatin1String("failed");
if (name.isEmpty())
qWarning("QOpenGLShader::compile(%s): %s", type, qPrintable(log));
else
qWarning("QOpenGLShader::compile(%s)[%s]: %s", type, qPrintable(name), qPrintable(log));
// Dump the source code if we got it
if (sourceCodeBuffer) {
qWarning("*** Problematic %s shader source code ***\n"
"%ls\n"
"***",
type, qUtf16Printable(QString::fromLatin1(sourceCodeBuffer)));
}
// Cleanup
delete [] logBuffer;
delete [] sourceCodeBuffer;
}
return compiled;
}
void QOpenGLShaderPrivate::deleteShader()
{
if (shaderGuard) {
shaderGuard->free();
shaderGuard = nullptr;
}
}
/*!
Constructs a new QOpenGLShader object of the specified \a type
and attaches it to \a parent. If shader programs are not supported,
QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false.
This constructor is normally followed by a call to compileSourceCode()
or compileSourceFile().
The shader will be associated with the current QOpenGLContext.
\sa compileSourceCode(), compileSourceFile()
*/
QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent)
: QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent)
{
Q_D(QOpenGLShader);
d->create();
}
/*!
Deletes this shader. If the shader has been attached to a
QOpenGLShaderProgram object, then the actual shader will stay around
until the QOpenGLShaderProgram is destroyed.
*/
QOpenGLShader::~QOpenGLShader()
{
}
/*!
Returns the type of this shader.
*/
QOpenGLShader::ShaderType QOpenGLShader::shaderType() const
{
Q_D(const QOpenGLShader);
return d->shaderType;
}
static const char qualifierDefines[] =
"#define lowp\n"
"#define mediump\n"
"#define highp\n";
#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES)
// The "highp" qualifier doesn't exist in fragment shaders
// on all ES platforms. When it doesn't exist, use "mediump".
#define QOpenGL_REDEFINE_HIGHP 1
static const char redefineHighp[] =
"#ifndef GL_FRAGMENT_PRECISION_HIGH\n"
"#define highp mediump\n"
"#endif\n";
#endif
// Boiler-plate header to have the layout attributes available we need later
static const char blendEquationAdvancedHeader[] =
"#ifdef GL_KHR_blend_equation_advanced\n"
"#extension GL_ARB_fragment_coord_conventions : enable\n"
"#extension GL_KHR_blend_equation_advanced : enable\n"
"#endif\n";
struct QVersionDirectivePosition
{
Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1)
: position(position)
, line(line)
{
}
Q_DECL_CONSTEXPR bool hasPosition() const
{
return position > 0;
}
const int position;
const int line;
};
static QVersionDirectivePosition findVersionDirectivePosition(const char *source)
{
Q_ASSERT(source);
// According to the GLSL spec the #version directive must not be
// preceded by anything but whitespace and comments.
// In order to not get confused by #version directives within a
// multiline comment, we need to do some minimal comment parsing
// while searching for the directive.
enum {
Normal,
StartOfLine,
PreprocessorDirective,
CommentStarting,
MultiLineComment,
SingleLineComment,
CommentEnding
} state = StartOfLine;
const char *c = source;
while (*c) {
switch (state) {
case PreprocessorDirective:
if (*c == ' ' || *c == '\t')
break;
if (!strncmp(c, "version", strlen("version"))) {
// Found version directive
c += strlen("version");
while (*c && *c != '\n')
++c;
int splitPosition = c - source + 1;
int linePosition = int(std::count(source, c, '\n')) + 1;
return QVersionDirectivePosition(splitPosition, linePosition);
} else if (*c == '/')
state = CommentStarting;
else if (*c == '\n')
state = StartOfLine;
else
state = Normal;
break;
case StartOfLine:
if (*c == ' ' || *c == '\t')
break;
else if (*c == '#') {
state = PreprocessorDirective;
break;
}
state = Normal;
Q_FALLTHROUGH();
case Normal:
if (*c == '/')
state = CommentStarting;
else if (*c == '\n')
state = StartOfLine;
break;
case CommentStarting:
if (*c == '*')
state = MultiLineComment;
else if (*c == '/')
state = SingleLineComment;
else
state = Normal;
break;
case MultiLineComment:
if (*c == '*')
state = CommentEnding;
break;
case SingleLineComment:
if (*c == '\n')
state = Normal;
break;
case CommentEnding:
if (*c == '/')
state = Normal;
else if (*c != QLatin1Char('*'))
state = MultiLineComment;
break;
}
++c;
}
return QVersionDirectivePosition(0, 1);
}
/*!
Sets the \a source code for this shader and compiles it.
Returns \c true if the source was successfully compiled, false otherwise.
\sa compileSourceFile()
*/
bool QOpenGLShader::compileSourceCode(const char *source)
{
Q_D(QOpenGLShader);
// This method breaks the shader code into two parts:
// 1. Up to and including an optional #version directive.
// 2. The rest.
// If a #version directive exists, qualifierDefines and redefineHighp
// are inserted after. Otherwise they are inserted right at the start.
// In both cases a #line directive is appended in order to compensate
// for line number changes in case of compiler errors.
if (d->shaderGuard && d->shaderGuard->id() && source) {
const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source);
QVarLengthArray<const char *, 5> sourceChunks;
QVarLengthArray<GLint, 5> sourceChunkLengths;
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (versionDirectivePosition.hasPosition()) {
// Append source up to and including the #version directive
sourceChunks.append(source);
sourceChunkLengths.append(GLint(versionDirectivePosition.position));
} else {
// QTBUG-55733: Intel on Windows with Compatibility profile requires a #version always
if (ctx->format().profile() == QSurfaceFormat::CompatibilityProfile) {
const char *vendor = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VENDOR));
if (vendor && !strcmp(vendor, "Intel")) {
static const char version110[] = "#version 110\n";
sourceChunks.append(version110);
sourceChunkLengths.append(GLint(sizeof(version110)) - 1);
}
}
}
if (d->shaderType == Fragment) {
sourceChunks.append(blendEquationAdvancedHeader);
sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1));
}
// The precision qualifiers are useful on OpenGL/ES systems,
// but usually not present on desktop systems.
const QSurfaceFormat currentSurfaceFormat = ctx->format();
QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(QOpenGLContext::currentContext());
if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL
|| ctx_d->workaround_missingPrecisionQualifiers
#ifdef QT_OPENGL_FORCE_SHADER_DEFINES
|| true
#endif
) {
sourceChunks.append(qualifierDefines);
sourceChunkLengths.append(GLint(sizeof(qualifierDefines) - 1));
}
#ifdef QOpenGL_REDEFINE_HIGHP
if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers
&& QOpenGLContext::currentContext()->isOpenGLES()) {
sourceChunks.append(redefineHighp);
sourceChunkLengths.append(GLint(sizeof(redefineHighp) - 1));
}
#endif
QByteArray lineDirective;
// #line is rejected by some drivers:
// "2.1 Mesa 8.1-devel (git-48a3d4e)" or "MESA 2.1 Mesa 8.1-devel"
const char *version = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VERSION));
if (!version || !strstr(version, "2.1 Mesa 8")) {
// Append #line directive in order to compensate for text insertion
lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8();
sourceChunks.append(lineDirective.constData());
sourceChunkLengths.append(GLint(lineDirective.length()));
}
// Append rest of shader code
sourceChunks.append(source + versionDirectivePosition.position);
sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position)));
d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data());
return d->compile(this);
} else {
return false;
}
}
/*!
\overload
Sets the \a source code for this shader and compiles it.
Returns \c true if the source was successfully compiled, false otherwise.
\sa compileSourceFile()
*/
bool QOpenGLShader::compileSourceCode(const QByteArray& source)
{
return compileSourceCode(source.constData());
}
/*!
\overload
Sets the \a source code for this shader and compiles it.
Returns \c true if the source was successfully compiled, false otherwise.
\sa compileSourceFile()
*/
bool QOpenGLShader::compileSourceCode(const QString& source)
{
return compileSourceCode(source.toLatin1().constData());
}
/*!
Sets the source code for this shader to the contents of \a fileName
and compiles it. Returns \c true if the file could be opened and the
source compiled, false otherwise.
\sa compileSourceCode()
*/
bool QOpenGLShader::compileSourceFile(const QString& fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly)) {
qWarning() << "QOpenGLShader: Unable to open file" << fileName;
return false;
}
QByteArray contents = file.readAll();
return compileSourceCode(contents.constData());
}
/*!
Returns the source code for this shader.
\sa compileSourceCode()
*/
QByteArray QOpenGLShader::sourceCode() const
{
Q_D(const QOpenGLShader);
GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0;
if (!shader)
return QByteArray();
GLint size = 0;
d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size);
if (size <= 0)
return QByteArray();
GLint len = 0;
char *source = new char [size];
d->glfuncs->glGetShaderSource(shader, size, &len, source);
QByteArray src(source);
delete [] source;
return src;
}
/*!
Returns \c true if this shader has been compiled; false otherwise.
\sa compileSourceCode(), compileSourceFile()
*/
bool QOpenGLShader::isCompiled() const
{
Q_D(const QOpenGLShader);
return d->compiled;
}
/*!
Returns the errors and warnings that occurred during the last compile.
\sa compileSourceCode(), compileSourceFile()
*/
QString QOpenGLShader::log() const
{
Q_D(const QOpenGLShader);
return d->log;
}
/*!
Returns the OpenGL identifier associated with this shader.
\sa QOpenGLShaderProgram::programId()
*/
GLuint QOpenGLShader::shaderId() const
{
Q_D(const QOpenGLShader);
return d->shaderGuard ? d->shaderGuard->id() : 0;
}
class QOpenGLShaderProgramPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOpenGLShaderProgram)
public:
QOpenGLShaderProgramPrivate()
: programGuard(nullptr)
, linked(false)
, inited(false)
, removingShaders(false)
, glfuncs(new QOpenGLExtraFunctions)
#ifndef QT_OPENGL_ES_2
, tessellationFuncs(nullptr)
#endif
, linkBinaryRecursion(false)
{
}
~QOpenGLShaderProgramPrivate();
QOpenGLSharedResourceGuard *programGuard;
bool linked;
bool inited;
bool removingShaders;
QString log;
QList<QOpenGLShader *> shaders;
QList<QOpenGLShader *> anonShaders;
QOpenGLExtraFunctions *glfuncs;
#ifndef QT_OPENGL_ES_2
// for tessellation features not in GLES 3.2
QOpenGLFunctions_4_0_Core *tessellationFuncs;
#endif
bool hasShader(QOpenGLShader::ShaderType type) const;
QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
bool isCacheDisabled() const;
bool compileCacheable();
bool linkBinary();
bool linkBinaryRecursion;
};
namespace {
void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id)
{
funcs->glDeleteProgram(id);
}
}
QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate()
{
delete glfuncs;
if (programGuard)
programGuard->free();
}
bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const
{
for (QOpenGLShader *shader : shaders) {
if (shader->shaderType() == type)
return true;
}
return false;
}
/*!
Constructs a new shader program and attaches it to \a parent.
The program will be invalid until addShader() is called.
The shader program will be associated with the current QOpenGLContext.
\sa addShader()
*/
QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent)
: QObject(*new QOpenGLShaderProgramPrivate, parent)
{
}
/*!
Deletes this shader program.
*/
QOpenGLShaderProgram::~QOpenGLShaderProgram()
{
}
/*!
Requests the shader program's id to be created immediately. Returns \c true
if successful; \c false otherwise.
This function is primarily useful when combining QOpenGLShaderProgram
with other OpenGL functions that operate directly on the shader
program id, like \c {GL_OES_get_program_binary}.
When the shader program is used normally, the shader program's id will
be created on demand.
\sa programId()
\since 5.3
*/
bool QOpenGLShaderProgram::create()
{
return init();
}
bool QOpenGLShaderProgram::init()
{
Q_D(QOpenGLShaderProgram);
if ((d->programGuard && d->programGuard->id()) || d->inited)
return true;
d->inited = true;
QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (!context)
return false;
d->glfuncs->initializeOpenGLFunctions();
#ifndef QT_OPENGL_ES_2
if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) {
d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>();
d->tessellationFuncs->initializeOpenGLFunctions();
}
#endif
GLuint program = d->glfuncs->glCreateProgram();
if (!program) {
qWarning("QOpenGLShaderProgram: could not create shader program");
return false;
}
if (d->programGuard)
delete d->programGuard;
d->programGuard = new QOpenGLSharedResourceGuard(context, program, freeProgramFunc);
return true;
}
/*!
Adds a compiled \a shader to this shader program. Returns \c true
if the shader could be added, or false otherwise.
Ownership of the \a shader object remains with the caller.
It will not be deleted when this QOpenGLShaderProgram instance
is deleted. This allows the caller to add the same shader
to multiple shader programs.
\sa addShaderFromSourceCode(), addShaderFromSourceFile()
\sa removeShader(), link(), removeAllShaders()
*/
bool QOpenGLShaderProgram::addShader(QOpenGLShader *shader)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
if (d->shaders.contains(shader))
return true; // Already added to this shader program.
if (d->programGuard && d->programGuard->id() && shader) {
if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id())
return false;
if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) {
qWarning("QOpenGLShaderProgram::addShader: Program and shader are not associated with same context.");
return false;
}
d->glfuncs->glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
d->linked = false; // Program needs to be relinked.
d->shaders.append(shader);
connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
return true;
} else {
return false;
}
}
/*!
Compiles \a source as a shader of the specified \a type and
adds it to this shader program. Returns \c true if compilation
was successful, false otherwise. The compilation errors
and warnings will be made available via log().
This function is intended to be a short-cut for quickly
adding vertex and fragment shaders to a shader program without
creating an instance of QOpenGLShader first.
\sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
QOpenGLShader *shader = new QOpenGLShader(type, this);
if (!shader->compileSourceCode(source)) {
d->log = shader->log();
delete shader;
return false;
}
d->anonShaders.append(shader);
return addShader(shader);
}
/*!
\overload
Compiles \a source as a shader of the specified \a type and
adds it to this shader program. Returns \c true if compilation
was successful, false otherwise. The compilation errors
and warnings will be made available via log().
This function is intended to be a short-cut for quickly
adding vertex and fragment shaders to a shader program without
creating an instance of QOpenGLShader first.
\sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source)
{
return addShaderFromSourceCode(type, source.constData());
}
/*!
\overload
Compiles \a source as a shader of the specified \a type and
adds it to this shader program. Returns \c true if compilation
was successful, false otherwise. The compilation errors
and warnings will be made available via log().
This function is intended to be a short-cut for quickly
adding vertex and fragment shaders to a shader program without
creating an instance of QOpenGLShader first.
\sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source)
{
return addShaderFromSourceCode(type, source.toLatin1().constData());
}
/*!
Compiles the contents of \a fileName as a shader of the specified
\a type and adds it to this shader program. Returns \c true if
compilation was successful, false otherwise. The compilation errors
and warnings will be made available via log().
This function is intended to be a short-cut for quickly
adding vertex and fragment shaders to a shader program without
creating an instance of QOpenGLShader first.
\sa addShader(), addShaderFromSourceCode()
*/
bool QOpenGLShaderProgram::addShaderFromSourceFile
(QOpenGLShader::ShaderType type, const QString& fileName)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
QOpenGLShader *shader = new QOpenGLShader(type, this);
if (!shader->compileSourceFile(fileName)) {
d->log = shader->log();
delete shader;
return false;
}
d->anonShaders.append(shader);
return addShader(shader);
}
/*!
Registers the shader of the specified \a type and \a source to this
program. Unlike addShaderFromSourceCode(), this function does not perform
compilation. Compilation is deferred to link(), and may not happen at all,
because link() may potentially use a program binary from Qt's shader disk
cache. This will typically lead to a significant increase in performance.
\return true if the shader has been registered or, in the non-cached case,
compiled successfully; false if there was an error. The compilation error
messages can be retrieved via log().
When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
example, or the OpenGL context has no support for context binaries, calling
this function is equivalent to addShaderFromSourceCode().
\since 5.9
\sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
*/
bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
return addCacheableShaderFromSourceCode(type, QByteArray(source));
}
static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
{
switch (type) {
case QOpenGLShader::Vertex:
return QShader::VertexStage;
case QOpenGLShader::Fragment:
return QShader::FragmentStage;
case QOpenGLShader::Geometry:
return QShader::GeometryStage;
case QOpenGLShader::TessellationControl:
return QShader::TessellationControlStage;
case QOpenGLShader::TessellationEvaluation:
return QShader::TessellationEvaluationStage;
case QOpenGLShader::Compute:
return QShader::ComputeStage;
}
return QShader::VertexStage;
}
static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
{
switch (stage) {
case QShader::VertexStage:
return QOpenGLShader::Vertex;
case QShader::TessellationControlStage:
return QOpenGLShader::TessellationControl;
case QShader::TessellationEvaluationStage:
return QOpenGLShader::TessellationEvaluation;
case QShader::GeometryStage:
return QOpenGLShader::Geometry;
case QShader::FragmentStage:
return QOpenGLShader::Fragment;
case QShader::ComputeStage:
return QOpenGLShader::Compute;
}
return QOpenGLShader::Vertex;
}
/*!
\overload
Registers the shader of the specified \a type and \a source to this
program. Unlike addShaderFromSourceCode(), this function does not perform
compilation. Compilation is deferred to link(), and may not happen at all,
because link() may potentially use a program binary from Qt's shader disk
cache. This will typically lead to a significant increase in performance.
\return true if the shader has been registered or, in the non-cached case,
compiled successfully; false if there was an error. The compilation error
messages can be retrieved via log().
When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
example, or the OpenGL context has no support for context binaries, calling
this function is equivalent to addShaderFromSourceCode().
\since 5.9
\sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
*/
bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
return true;
}
/*!
\overload
Registers the shader of the specified \a type and \a source to this
program. Unlike addShaderFromSourceCode(), this function does not perform
compilation. Compilation is deferred to link(), and may not happen at all,
because link() may potentially use a program binary from Qt's shader disk
cache. This will typically lead to a significant increase in performance.
When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
example, or the OpenGL context has no support for context binaries, calling
this function is equivalent to addShaderFromSourceCode().
\since 5.9
\sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
*/
bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
return addCacheableShaderFromSourceCode(type, source.toUtf8().constData());
}
/*!
Registers the shader of the specified \a type and \a fileName to this
program. Unlike addShaderFromSourceFile(), this function does not perform
compilation. Compilation is deferred to link(), and may not happen at all,
because link() may potentially use a program binary from Qt's shader disk
cache. This will typically lead to a significant increase in performance.
\return true if the file has been read successfully, false if the file could
not be opened or the normal, non-cached compilation of the shader has
failed. The compilation error messages can be retrieved via log().
When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
example, or the OpenGL context has no support for context binaries, calling
this function is equivalent to addShaderFromSourceFile().
\since 5.9
\sa addShaderFromSourceFile(), addCacheableShaderFromSourceCode()
*/
bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName)
{
Q_D(QOpenGLShaderProgram);
if (!init())
return false;
if (d->isCacheDisabled())
return addShaderFromSourceFile(type, fileName);
QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
// NB! It could be tempting to defer reading the file contents and just
// hash the filename as the cache key, perhaps combined with last-modified
// timestamp checks. However, this would raise a number of issues (no
// timestamps for files in the resource system; preference for global, not
// per-application cache items (where filenames may clash); resource-based
// shaders from libraries like Qt Quick; etc.), so just avoid it.
QFile f(fileName);
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
shader.source = f.readAll();
f.close();
} else {
qWarning("QOpenGLShaderProgram: Unable to open file %s", qPrintable(fileName));
return false;
}
d->binaryProgram.shaders.append(shader);
return true;
}
/*!
Removes \a shader from this shader program. The object is not deleted.
The shader program must be valid in the current QOpenGLContext.
\sa addShader(), link(), removeAllShaders()
*/
void QOpenGLShaderProgram::removeShader(QOpenGLShader *shader)
{
Q_D(QOpenGLShaderProgram);
if (d->programGuard && d->programGuard->id()
&& shader && shader->d_func()->shaderGuard)
{
d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
}
d->linked = false; // Program needs to be relinked.
if (shader) {
d->shaders.removeAll(shader);
d->anonShaders.removeAll(shader);
disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed()));
}
}
/*!
Returns a list of all shaders that have been added to this shader
program using addShader().
\sa addShader(), removeShader()
*/
QList<QOpenGLShader *> QOpenGLShaderProgram::shaders() const
{
Q_D(const QOpenGLShaderProgram);
return d->shaders;
}
/*!
Removes all of the shaders that were added to this program previously.
The QOpenGLShader objects for the shaders will not be deleted if they
were constructed externally. QOpenGLShader objects that are constructed
internally by QOpenGLShaderProgram will be deleted.
\sa addShader(), removeShader()
*/
void QOpenGLShaderProgram::removeAllShaders()
{
Q_D(QOpenGLShaderProgram);
d->removingShaders = true;
for (QOpenGLShader *shader : qAsConst(d->shaders)) {
if (d->programGuard && d->programGuard->id()
&& shader && shader->d_func()->shaderGuard)
{
d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id());
}
}
// Delete shader objects that were created anonymously.
qDeleteAll(d->anonShaders);
d->shaders.clear();
d->anonShaders.clear();
d->binaryProgram = QOpenGLProgramBinaryCache::ProgramDesc();
d->linked = false; // Program needs to be relinked.
d->removingShaders = false;
}
/*!
Links together the shaders that were added to this program with
addShader(). Returns \c true if the link was successful or
false otherwise. If the link failed, the error messages can
be retrieved with log().
Subclasses can override this function to initialize attributes
and uniform variables for use in specific shader programs.
If the shader program was already linked, calling this
function again will force it to be re-linked.
When shaders were added to this program via
addCacheableShaderFromSourceCode() or addCacheableShaderFromSourceFile(),
program binaries are supported, and a cached binary is available on disk,
actual compilation and linking are skipped. Instead, link() will initialize
the program with the binary blob via glProgramBinary(). If there is no
cached version of the program or it was generated with a different driver
version, the shaders will be compiled from source and the program will get
linked normally. This allows seamless upgrading of the graphics drivers,
without having to worry about potentially incompatible binary formats.
\sa addShader(), log()
*/
bool QOpenGLShaderProgram::link()
{
Q_D(QOpenGLShaderProgram);
GLuint program = d->programGuard ? d->programGuard->id() : 0;
if (!program)
return false;
if (!d->linkBinaryRecursion && d->shaders.isEmpty() && !d->binaryProgram.shaders.isEmpty())
return d->linkBinary();
GLint value;
if (d->shaders.isEmpty()) {
// If there are no explicit shaders, then it is possible that the
// application added a program binary with glProgramBinaryOES(), or
// otherwise populated the shaders itself. This is also the case when
// we are recursively called back from linkBinary() after a successful
// glProgramBinary(). Check to see if the program is already linked and
// bail out if so.
value = 0;
d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value);
d->linked = (value != 0);
if (d->linked)
return true;
}
d->glfuncs->glLinkProgram(program);
value = 0;
d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value);
d->linked = (value != 0);
value = 0;
d->glfuncs->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value);
d->log = QString();
if (value > 1) {
char *logbuf = new char [value];
GLint len;
d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf);
d->log = QString::fromLatin1(logbuf);
if (!d->linked && !d->linkBinaryRecursion) {
QString name = objectName();
if (name.isEmpty())
qWarning("QOpenGLShader::link: %ls", qUtf16Printable(d->log));
else
qWarning("QOpenGLShader::link[%ls]: %ls", qUtf16Printable(name), qUtf16Printable(d->log));
}
delete [] logbuf;
}
return d->linked;
}
/*!
Returns \c true if this shader program has been linked; false otherwise.
\sa link()
*/
bool QOpenGLShaderProgram::isLinked() const
{
Q_D(const QOpenGLShaderProgram);
return d->linked;
}
/*!
Returns the errors and warnings that occurred during the last link()
or addShader() with explicitly specified source code.
\sa link()
*/
QString QOpenGLShaderProgram::log() const
{
Q_D(const QOpenGLShaderProgram);
return d->log;
}
/*!
Binds this shader program to the active QOpenGLContext and makes
it the current shader program. Any previously bound shader program
is released. This is equivalent to calling \c{glUseProgram()} on
programId(). Returns \c true if the program was successfully bound;
false otherwise. If the shader program has not yet been linked,
or it needs to be re-linked, this function will call link().
\sa link(), release()
*/
bool QOpenGLShaderProgram::bind()
{
Q_D(QOpenGLShaderProgram);
GLuint program = d->programGuard ? d->programGuard->id() : 0;
if (!program)
return false;
if (!d->linked && !link())
return false;
#ifndef QT_NO_DEBUG
if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) {
qWarning("QOpenGLShaderProgram::bind: program is not valid in the current context.");
return false;
}
#endif
d->glfuncs->glUseProgram(program);
return true;
}
/*!
Releases the active shader program from the current QOpenGLContext.
This is equivalent to calling \c{glUseProgram(0)}.
\sa bind()
*/
void QOpenGLShaderProgram::release()
{
Q_D(QOpenGLShaderProgram);
#ifndef QT_NO_DEBUG
if (d->programGuard && d->programGuard->group() != QOpenGLContextGroup::currentContextGroup())
qWarning("QOpenGLShaderProgram::release: program is not valid in the current context.");
#endif
d->glfuncs->glUseProgram(0);
}
/*!
Returns the OpenGL identifier associated with this shader program.
\sa QOpenGLShader::shaderId()
*/
GLuint QOpenGLShaderProgram::programId() const
{
Q_D(const QOpenGLShaderProgram);
GLuint id = d->programGuard ? d->programGuard->id() : 0;
if (id)
return id;
// Create the identifier if we don't have one yet. This is for
// applications that want to create the attached shader configuration
// themselves, particularly those using program binaries.
if (!const_cast<QOpenGLShaderProgram *>(this)->init())
return 0;
return d->programGuard ? d->programGuard->id() : 0;
}
/*!
Binds the attribute \a name to the specified \a location. This
function can be called before or after the program has been linked.
Any attributes that have not been explicitly bound when the program
is linked will be assigned locations automatically.
When this function is called after the program has been linked,
the program will need to be relinked for the change to take effect.
\sa attributeLocation()
*/
void QOpenGLShaderProgram::bindAttributeLocation(const char *name, int location)
{
Q_D(QOpenGLShaderProgram);
if (!init() || !d->programGuard || !d->programGuard->id())
return;
d->glfuncs->glBindAttribLocation(d->programGuard->id(), location, name);
d->linked = false; // Program needs to be relinked.
}
/*!
\overload
Binds the attribute \a name to the specified \a location. This
function can be called before or after the program has been linked.
Any attributes that have not been explicitly bound when the program
is linked will be assigned locations automatically.
When this function is called after the program has been linked,
the program will need to be relinked for the change to take effect.
\sa attributeLocation()
*/
void QOpenGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location)
{
bindAttributeLocation(name.constData(), location);
}
/*!
\overload
Binds the attribute \a name to the specified \a location. This
function can be called before or after the program has been linked.
Any attributes that have not been explicitly bound when the program
is linked will be assigned locations automatically.
When this function is called after the program has been linked,
the program will need to be relinked for the change to take effect.
\sa attributeLocation()
*/
void QOpenGLShaderProgram::bindAttributeLocation(const QString& name, int location)
{
bindAttributeLocation(name.toLatin1().constData(), location);
}
/*!
Returns the location of the attribute \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
attribute for this shader program.
\sa uniformLocation(), bindAttributeLocation()
*/
int QOpenGLShaderProgram::attributeLocation(const char *name) const
{
Q_D(const QOpenGLShaderProgram);
if (d->linked && d->programGuard && d->programGuard->id()) {
return d->glfuncs->glGetAttribLocation(d->programGuard->id(), name);
} else {
qWarning("QOpenGLShaderProgram::attributeLocation(%s): shader program is not linked", name);
return -1;
}
}
/*!
\overload
Returns the location of the attribute \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
attribute for this shader program.
\sa uniformLocation(), bindAttributeLocation()
*/
int QOpenGLShaderProgram::attributeLocation(const QByteArray& name) const
{
return attributeLocation(name.constData());
}
/*!
\overload
Returns the location of the attribute \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
attribute for this shader program.
\sa uniformLocation(), bindAttributeLocation()
*/
int QOpenGLShaderProgram::attributeLocation(const QString& name) const
{
return attributeLocation(name.toLatin1().constData());
}
/*!
Sets the attribute at \a location in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat value)
{
Q_D(QOpenGLShaderProgram);
if (location != -1)
d->glfuncs->glVertexAttrib1fv(location, &value);
}
/*!
\overload
Sets the attribute called \a name in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat value)
{
setAttributeValue(attributeLocation(name), value);
}
/*!
Sets the attribute at \a location in the current context to
the 2D vector (\a x, \a y).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y)
{
Q_D(QOpenGLShaderProgram);
if (location != -1) {
GLfloat values[2] = {x, y};
d->glfuncs->glVertexAttrib2fv(location, values);
}
}
/*!
\overload
Sets the attribute called \a name in the current context to
the 2D vector (\a x, \a y).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y)
{
setAttributeValue(attributeLocation(name), x, y);
}
/*!
Sets the attribute at \a location in the current context to
the 3D vector (\a x, \a y, \a z).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(int location, GLfloat x, GLfloat y, GLfloat z)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[3] = {x, y, z};
d->glfuncs->glVertexAttrib3fv(location, values);
}
}
/*!
\overload
Sets the attribute called \a name in the current context to
the 3D vector (\a x, \a y, \a z).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(const char *name, GLfloat x, GLfloat y, GLfloat z)
{
setAttributeValue(attributeLocation(name), x, y, z);
}
/*!
Sets the attribute at \a location in the current context to
the 4D vector (\a x, \a y, \a z, \a w).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
Q_D(QOpenGLShaderProgram);
if (location != -1) {
GLfloat values[4] = {x, y, z, w};
d->glfuncs->glVertexAttrib4fv(location, values);
}
}
/*!
\overload
Sets the attribute called \a name in the current context to
the 4D vector (\a x, \a y, \a z, \a w).
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
setAttributeValue(attributeLocation(name), x, y, z, w);
}
/*!
Sets the attribute at \a location in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, const QVector2D& value)
{
Q_D(QOpenGLShaderProgram);
if (location != -1)
d->glfuncs->glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the attribute called \a name in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value)
{
setAttributeValue(attributeLocation(name), value);
}
/*!
Sets the attribute at \a location in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, const QVector3D& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the attribute called \a name in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value)
{
setAttributeValue(attributeLocation(name), value);
}
/*!
Sets the attribute at \a location in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, const QVector4D& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the attribute called \a name in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value)
{
setAttributeValue(attributeLocation(name), value);
}
/*!
Sets the attribute at \a location in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(int location, const QColor& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()),
GLfloat(value.blueF()), GLfloat(value.alphaF())};
d->glfuncs->glVertexAttrib4fv(location, values);
}
}
/*!
\overload
Sets the attribute called \a name in the current context to \a value.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue(const char *name, const QColor& value)
{
setAttributeValue(attributeLocation(name), value);
}
/*!
Sets the attribute at \a location in the current context to the
contents of \a values, which contains \a columns elements, each
consisting of \a rows elements. The \a rows value should be
1, 2, 3, or 4. This function is typically used to set matrix
values and column vectors.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(int location, const GLfloat *values, int columns, int rows)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (rows < 1 || rows > 4) {
qWarning("QOpenGLShaderProgram::setAttributeValue: rows %d not supported", rows);
return;
}
if (location != -1) {
while (columns-- > 0) {
if (rows == 1)
d->glfuncs->glVertexAttrib1fv(location, values);
else if (rows == 2)
d->glfuncs->glVertexAttrib2fv(location, values);
else if (rows == 3)
d->glfuncs->glVertexAttrib3fv(location, values);
else
d->glfuncs->glVertexAttrib4fv(location, values);
values += rows;
++location;
}
}
}
/*!
\overload
Sets the attribute called \a name in the current context to the
contents of \a values, which contains \a columns elements, each
consisting of \a rows elements. The \a rows value should be
1, 2, 3, or 4. This function is typically used to set matrix
values and column vectors.
\sa setUniformValue()
*/
void QOpenGLShaderProgram::setAttributeValue
(const char *name, const GLfloat *values, int columns, int rows)
{
setAttributeValue(attributeLocation(name), values, columns, rows);
}
/*!
Sets an array of vertex \a values on the attribute at \a location
in this shader program. The \a tupleSize indicates the number of
components per vertex (1, 2, 3, or 4), and the \a stride indicates
the number of bytes between vertices. A default \a stride value
of zero indicates that the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(int location, const GLfloat *values, int tupleSize, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE,
stride, values);
}
}
/*!
Sets an array of 2D vertex \a values on the attribute at \a location
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(int location, const QVector2D *values, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE,
stride, values);
}
}
/*!
Sets an array of 3D vertex \a values on the attribute at \a location
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(int location, const QVector3D *values, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE,
stride, values);
}
}
/*!
Sets an array of 4D vertex \a values on the attribute at \a location
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(int location, const QVector4D *values, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE,
stride, values);
}
}
/*!
Sets an array of vertex \a values on the attribute at \a location
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The \a type indicates the type of elements in the \a values array,
usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize
indicates the number of components per vertex: 1, 2, 3, or 4.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
The setAttributeBuffer() function can be used to set the attribute
array to an offset within a vertex buffer.
\note Normalization will be enabled. If this is not desired, call
glVertexAttribPointer directly through QOpenGLFunctions.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray(), setAttributeBuffer()
*/
void QOpenGLShaderProgram::setAttributeArray
(int location, GLenum type, const void *values, int tupleSize, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE,
stride, values);
}
}
/*!
\overload
Sets an array of vertex \a values on the attribute called \a name
in this shader program. The \a tupleSize indicates the number of
components per vertex (1, 2, 3, or 4), and the \a stride indicates
the number of bytes between vertices. A default \a stride value
of zero indicates that the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on \a name. Otherwise the value specified with setAttributeValue()
for \a name will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(const char *name, const GLfloat *values, int tupleSize, int stride)
{
setAttributeArray(attributeLocation(name), values, tupleSize, stride);
}
/*!
\overload
Sets an array of 2D vertex \a values on the attribute called \a name
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on \a name. Otherwise the value specified with setAttributeValue()
for \a name will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(const char *name, const QVector2D *values, int stride)
{
setAttributeArray(attributeLocation(name), values, stride);
}
/*!
\overload
Sets an array of 3D vertex \a values on the attribute called \a name
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on \a name. Otherwise the value specified with setAttributeValue()
for \a name will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(const char *name, const QVector3D *values, int stride)
{
setAttributeArray(attributeLocation(name), values, stride);
}
/*!
\overload
Sets an array of 4D vertex \a values on the attribute called \a name
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The array will become active when enableAttributeArray() is called
on \a name. Otherwise the value specified with setAttributeValue()
for \a name will be used.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeArray
(const char *name, const QVector4D *values, int stride)
{
setAttributeArray(attributeLocation(name), values, stride);
}
/*!
\overload
Sets an array of vertex \a values on the attribute called \a name
in this shader program. The \a stride indicates the number of bytes
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
The \a type indicates the type of elements in the \a values array,
usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize
indicates the number of components per vertex: 1, 2, 3, or 4.
The array will become active when enableAttributeArray() is called
on the \a name. Otherwise the value specified with
setAttributeValue() for \a name will be used.
The setAttributeBuffer() function can be used to set the attribute
array to an offset within a vertex buffer.
\sa setAttributeValue(), setUniformValue(), enableAttributeArray()
\sa disableAttributeArray(), setAttributeBuffer()
*/
void QOpenGLShaderProgram::setAttributeArray
(const char *name, GLenum type, const void *values, int tupleSize, int stride)
{
setAttributeArray(attributeLocation(name), type, values, tupleSize, stride);
}
/*!
Sets an array of vertex values on the attribute at \a location in
this shader program, starting at a specific \a offset in the
currently bound vertex buffer. The \a stride indicates the number
of bytes between vertices. A default \a stride value of zero
indicates that the vertices are densely packed in the value array.
The \a type indicates the type of elements in the vertex value
array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a
tupleSize indicates the number of components per vertex: 1, 2, 3,
or 4.
The array will become active when enableAttributeArray() is called
on the \a location. Otherwise the value specified with
setAttributeValue() for \a location will be used.
\note Normalization will be enabled. If this is not desired, call
glVertexAttribPointer directly through QOpenGLFunctions.
\sa setAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeBuffer
(int location, GLenum type, int offset, int tupleSize, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, stride,
reinterpret_cast<const void *>(qintptr(offset)));
}
}
/*!
\overload
Sets an array of vertex values on the attribute called \a name
in this shader program, starting at a specific \a offset in the
currently bound vertex buffer. The \a stride indicates the number
of bytes between vertices. A default \a stride value of zero
indicates that the vertices are densely packed in the value array.
The \a type indicates the type of elements in the vertex value
array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a
tupleSize indicates the number of components per vertex: 1, 2, 3,
or 4.
The array will become active when enableAttributeArray() is called
on the \a name. Otherwise the value specified with
setAttributeValue() for \a name will be used.
\sa setAttributeArray()
*/
void QOpenGLShaderProgram::setAttributeBuffer
(const char *name, GLenum type, int offset, int tupleSize, int stride)
{
setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride);
}
/*!
Enables the vertex array at \a location in this shader program
so that the value set by setAttributeArray() on \a location
will be used by the shader program.
\sa disableAttributeArray(), setAttributeArray(), setAttributeValue()
\sa setUniformValue()
*/
void QOpenGLShaderProgram::enableAttributeArray(int location)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glEnableVertexAttribArray(location);
}
/*!
\overload
Enables the vertex array called \a name in this shader program
so that the value set by setAttributeArray() on \a name
will be used by the shader program.
\sa disableAttributeArray(), setAttributeArray(), setAttributeValue()
\sa setUniformValue()
*/
void QOpenGLShaderProgram::enableAttributeArray(const char *name)
{
enableAttributeArray(attributeLocation(name));
}
/*!
Disables the vertex array at \a location in this shader program
that was enabled by a previous call to enableAttributeArray().
\sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
\sa setUniformValue()
*/
void QOpenGLShaderProgram::disableAttributeArray(int location)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glDisableVertexAttribArray(location);
}
/*!
\overload
Disables the vertex array called \a name in this shader program
that was enabled by a previous call to enableAttributeArray().
\sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
\sa setUniformValue()
*/
void QOpenGLShaderProgram::disableAttributeArray(const char *name)
{
disableAttributeArray(attributeLocation(name));
}
/*!
Returns the location of the uniform variable \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
uniform variable for this shader program.
\sa attributeLocation()
*/
int QOpenGLShaderProgram::uniformLocation(const char *name) const
{
Q_D(const QOpenGLShaderProgram);
Q_UNUSED(d);
if (d->linked && d->programGuard && d->programGuard->id()) {
return d->glfuncs->glGetUniformLocation(d->programGuard->id(), name);
} else {
qWarning("QOpenGLShaderProgram::uniformLocation(%s): shader program is not linked", name);
return -1;
}
}
/*!
\overload
Returns the location of the uniform variable \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
uniform variable for this shader program.
\sa attributeLocation()
*/
int QOpenGLShaderProgram::uniformLocation(const QByteArray& name) const
{
return uniformLocation(name.constData());
}
/*!
\overload
Returns the location of the uniform variable \a name within this shader
program's parameter list. Returns -1 if \a name is not a valid
uniform variable for this shader program.
\sa attributeLocation()
*/
int QOpenGLShaderProgram::uniformLocation(const QString& name) const
{
return uniformLocation(name.toLatin1().constData());
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, GLfloat value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform1fv(location, 1, &value);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, GLint value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform1i(location, value);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, GLint value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
This function should be used when setting sampler values.
\note This function is not aware of unsigned int support in modern OpenGL
versions and therefore treats \a value as a GLint and calls glUniform1i.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, GLuint value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform1i(location, value);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value. This function should be used when setting sampler values.
\note This function is not aware of unsigned int support in modern OpenGL
versions and therefore treats \a value as a GLint and calls glUniform1i.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, GLuint value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to
the 2D vector (\a x, \a y).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[2] = {x, y};
d->glfuncs->glUniform2fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable called \a name in the current context to
the 2D vector (\a x, \a y).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y)
{
setUniformValue(uniformLocation(name), x, y);
}
/*!
Sets the uniform variable at \a location in the current context to
the 3D vector (\a x, \a y, \a z).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue
(int location, GLfloat x, GLfloat y, GLfloat z)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[3] = {x, y, z};
d->glfuncs->glUniform3fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable called \a name in the current context to
the 3D vector (\a x, \a y, \a z).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue
(const char *name, GLfloat x, GLfloat y, GLfloat z)
{
setUniformValue(uniformLocation(name), x, y, z);
}
/*!
Sets the uniform variable at \a location in the current context to
the 4D vector (\a x, \a y, \a z, \a w).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue
(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {x, y, z, w};
d->glfuncs->glUniform4fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable called \a name in the current context to
the 4D vector (\a x, \a y, \a z, \a w).
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue
(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
setUniformValue(uniformLocation(name), x, y, z, w);
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QVector2D& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector2D& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QVector3D& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector3D& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QVector4D& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector4D& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to
the red, green, blue, and alpha components of \a color.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QColor& color)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()),
GLfloat(color.blueF()), GLfloat(color.alphaF())};
d->glfuncs->glUniform4fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable called \a name in the current context to
the red, green, blue, and alpha components of \a color.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QColor& color)
{
setUniformValue(uniformLocation(name), color);
}
/*!
Sets the uniform variable at \a location in the current context to
the x and y coordinates of \a point.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QPoint& point)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())};
d->glfuncs->glUniform2fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable associated with \a name in the current
context to the x and y coordinates of \a point.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QPoint& point)
{
setUniformValue(uniformLocation(name), point);
}
/*!
Sets the uniform variable at \a location in the current context to
the x and y coordinates of \a point.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QPointF& point)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())};
d->glfuncs->glUniform2fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable associated with \a name in the current
context to the x and y coordinates of \a point.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QPointF& point)
{
setUniformValue(uniformLocation(name), point);
}
/*!
Sets the uniform variable at \a location in the current context to
the width and height of the given \a size.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QSize& size)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())};
d->glfuncs->glUniform2fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable associated with \a name in the current
context to the width and height of the given \a size.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QSize& size)
{
setUniformValue(uniformLocation(name), size);
}
/*!
Sets the uniform variable at \a location in the current context to
the width and height of the given \a size.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QSizeF& size)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())};
d->glfuncs->glUniform2fv(location, 1, values);
}
}
/*!
\overload
Sets the uniform variable associated with \a name in the current
context to the width and height of the given \a size.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QSizeF& size)
{
setUniformValue(uniformLocation(name), size);
}
/*!
Sets the uniform variable at \a location in the current context
to a 2x2 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 2x2 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 2x3 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat2x3, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec3.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform3fv(location, 2, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 2x3 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat2x3, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec3.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 2x4 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat2x4, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform4fv(location, 2, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 2x4 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat2x4, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 3x2 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat3x2, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec2.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform2fv(location, 3, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 3x2 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat3x2, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec2.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 3x3 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 3x3 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 3x4 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat3x4, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform4fv(location, 3, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 3x4 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat3x4, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 4x2 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat4x2, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec2.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform2fv(location, 4, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 4x2 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat4x2, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec2.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 4x3 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat4x3, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec3.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniform3fv(location, 4, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 4x3 matrix \a value.
\note This function is not aware of non square matrix support,
that is, GLSL types like mat4x3, that is present in modern OpenGL
versions. Instead, it treats the uniform as an array of vec3.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context
to a 4x4 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value.constData());
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 4x4 matrix \a value.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
\overload
Sets the uniform variable at \a location in the current context
to a 2x2 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2])
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value[0]);
}
/*!
\overload
Sets the uniform variable at \a location in the current context
to a 3x3 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3])
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value[0]);
}
/*!
\overload
Sets the uniform variable at \a location in the current context
to a 4x4 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4])
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value[0]);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 2x2 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2])
{
setUniformValue(uniformLocation(name), value);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 3x3 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3])
{
setUniformValue(uniformLocation(name), value);
}
/*!
\overload
Sets the uniform variable called \a name in the current context
to a 4x4 matrix \a value. The matrix elements must be specified
in column-major order.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4])
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable at \a location in the current context to a
3x3 transformation matrix \a value that is specified as a QTransform value.
To set a QTransform value as a 4x4 matrix in a shader, use
\c{setUniformValue(location, QMatrix4x4(value))}.
*/
void QOpenGLShaderProgram::setUniformValue(int location, const QTransform& value)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
GLfloat mat[3][3] = {
{GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())},
{GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())},
{GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())}
};
d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]);
}
}
/*!
\overload
Sets the uniform variable called \a name in the current context to a
3x3 transformation matrix \a value that is specified as a QTransform value.
To set a QTransform value as a 4x4 matrix in a shader, use
\c{setUniformValue(name, QMatrix4x4(value))}.
*/
void QOpenGLShaderProgram::setUniformValue
(const char *name, const QTransform& value)
{
setUniformValue(uniformLocation(name), value);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform1iv(location, count, values);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray
(const char *name, const GLint *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count elements of \a values. This overload
should be used when setting an array of sampler values.
\note This function is not aware of unsigned int support in modern OpenGL
versions and therefore treats \a values as a GLint and calls glUniform1iv.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform1iv(location, count, reinterpret_cast<const GLint *>(values));
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count elements of \a values. This overload
should be used when setting an array of sampler values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray
(const char *name, const GLuint *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count elements of \a values. Each element
has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
if (tupleSize == 1)
d->glfuncs->glUniform1fv(location, count, values);
else if (tupleSize == 2)
d->glfuncs->glUniform2fv(location, count, values);
else if (tupleSize == 3)
d->glfuncs->glUniform3fv(location, count, values);
else if (tupleSize == 4)
d->glfuncs->glUniform4fv(location, count, values);
else
qWarning("QOpenGLShaderProgram::setUniformValue: size %d not supported", tupleSize);
}
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count elements of \a values. Each element
has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray
(const char *name, const GLfloat *values, int count, int tupleSize)
{
setUniformValueArray(uniformLocation(name), values, count, tupleSize);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 2D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 2D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 3D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 3D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 4D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1)
d->glfuncs->glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 4D vector elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
// We have to repack matrix arrays from qreal to GLfloat.
#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \
if (location == -1 || count <= 0) \
return; \
if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
func(location, count, GL_FALSE, \
reinterpret_cast<const GLfloat *>(values[0].constData())); \
} else { \
QVarLengthArray<GLfloat> temp(cols * rows * count); \
for (int index = 0; index < count; ++index) { \
for (int index2 = 0; index2 < (cols * rows); ++index2) { \
temp.data()[cols * rows * index + index2] = \
values[index].constData()[index2]; \
} \
} \
func(location, count, GL_FALSE, temp.constData()); \
}
#define setUniformGenericMatrixArray(colfunc,location,values,count,type,cols,rows) \
if (location == -1 || count <= 0) \
return; \
if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
const GLfloat *data = reinterpret_cast<const GLfloat *> \
(values[0].constData()); \
colfunc(location, count * cols, data); \
} else { \
QVarLengthArray<GLfloat> temp(cols * rows * count); \
for (int index = 0; index < count; ++index) { \
for (int index2 = 0; index2 < (cols * rows); ++index2) { \
temp.data()[cols * rows * index + index2] = \
values[index].constData()[index2]; \
} \
} \
colfunc(location, count * cols, temp.constData()); \
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 2x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformMatrixArray
(d->glfuncs->glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 2x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 2x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform3fv, location, values, count,
QMatrix2x3, 2, 3);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 2x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 2x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform4fv, location, values, count,
QMatrix2x4, 2, 4);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 2x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 3x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform2fv, location, values, count,
QMatrix3x2, 3, 2);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 3x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 3x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformMatrixArray
(d->glfuncs->glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 3x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 3x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform4fv, location, values, count,
QMatrix3x4, 3, 4);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 3x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 4x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform2fv, location, values, count,
QMatrix4x2, 4, 2);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 4x2 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 4x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformGenericMatrixArray
(d->glfuncs->glUniform3fv, location, values, count,
QMatrix4x3, 4, 3);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 4x3 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Sets the uniform variable array at \a location in the current
context to the \a count 4x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
setUniformMatrixArray
(d->glfuncs->glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4);
}
/*!
\overload
Sets the uniform variable array called \a name in the current
context to the \a count 4x4 matrix elements of \a values.
\sa setAttributeValue()
*/
void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count)
{
setUniformValueArray(uniformLocation(name), values, count);
}
/*!
Returns the hardware limit for how many vertices a geometry shader
can output.
*/
int QOpenGLShaderProgram::maxGeometryOutputVertices() const
{
GLint n = 0;
Q_D(const QOpenGLShaderProgram);
d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n);
return n;
}
/*!
Use this function to specify to OpenGL the number of vertices in
a patch to \a count. A patch is a custom OpenGL primitive whose interpretation
is entirely defined by the tessellation shader stages. Therefore, calling
this function only makes sense when using a QOpenGLShaderProgram
containing tessellation stage shaders. When using OpenGL tessellation,
the only primitive that can be rendered with \c{glDraw*()} functions is
\c{GL_PATCHES}.
This is equivalent to calling glPatchParameteri(GL_PATCH_VERTICES, count).
\note This modifies global OpenGL state and is not specific to this
QOpenGLShaderProgram instance. You should call this in your render
function when needed, as QOpenGLShaderProgram will not apply this for
you. This is purely a convenience function.
\sa patchVertexCount()
*/
void QOpenGLShaderProgram::setPatchVertexCount(int count)
{
Q_D(QOpenGLShaderProgram);
d->glfuncs->glPatchParameteri(GL_PATCH_VERTICES, count);
}
/*!
Returns the number of vertices per-patch to be used when rendering.
\note This returns the global OpenGL state value. It is not specific to
this QOpenGLShaderProgram instance.
\sa setPatchVertexCount()
*/
int QOpenGLShaderProgram::patchVertexCount() const
{
int patchVertices = 0;
Q_D(const QOpenGLShaderProgram);
d->glfuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices);
return patchVertices;
}
/*!
Sets the default outer tessellation levels to be used by the tessellation
primitive generator in the event that the tessellation control shader
does not output them to \a levels. For more details on OpenGL and Tessellation
shaders see \l{OpenGL Tessellation Shaders}.
The \a levels argument should be a QVector consisting of 4 floats. Not all
of the values make sense for all tessellation modes. If you specify a vector with
fewer than 4 elements, the remaining elements will be given a default value of 1.
\note This modifies global OpenGL state and is not specific to this
QOpenGLShaderProgram instance. You should call this in your render
function when needed, as QOpenGLShaderProgram will not apply this for
you. This is purely a convenience function.
\note This function is only available with OpenGL >= 4.0 and is not supported
with OpenGL ES 3.2.
\sa defaultOuterTessellationLevels(), setDefaultInnerTessellationLevels()
*/
void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels)
{
#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
if (d->tessellationFuncs) {
QVector<float> tessLevels = levels;
// Ensure we have the required 4 outer tessellation levels
// Use default of 1 for missing entries (same as spec)
const int argCount = 4;
if (tessLevels.size() < argCount) {
tessLevels.reserve(argCount);
for (int i = tessLevels.size(); i < argCount; ++i)
tessLevels.append(1.0f);
}
d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data());
}
#else
Q_UNUSED(levels);
#endif
}
/*!
Returns the default outer tessellation levels to be used by the tessellation
primitive generator in the event that the tessellation control shader
does not output them. For more details on OpenGL and Tessellation shaders see
\l{OpenGL Tessellation Shaders}.
Returns a QVector of floats describing the outer tessellation levels. The vector
will always have four elements but not all of them make sense for every mode
of tessellation.
\note This returns the global OpenGL state value. It is not specific to
this QOpenGLShaderProgram instance.
\note This function is only supported with OpenGL >= 4.0 and will not
return valid results with OpenGL ES 3.2.
\sa setDefaultOuterTessellationLevels(), defaultInnerTessellationLevels()
*/
QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const
{
#ifndef QT_OPENGL_ES_2
QVector<float> tessLevels(4, 1.0f);
Q_D(const QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data());
return tessLevels;
#else
return QVector<float>();
#endif
}
/*!
Sets the default outer tessellation levels to be used by the tessellation
primitive generator in the event that the tessellation control shader
does not output them to \a levels. For more details on OpenGL and Tessellation shaders see
\l{OpenGL Tessellation Shaders}.
The \a levels argument should be a QVector consisting of 2 floats. Not all
of the values make sense for all tessellation modes. If you specify a vector with
fewer than 2 elements, the remaining elements will be given a default value of 1.
\note This modifies global OpenGL state and is not specific to this
QOpenGLShaderProgram instance. You should call this in your render
function when needed, as QOpenGLShaderProgram will not apply this for
you. This is purely a convenience function.
\note This function is only available with OpenGL >= 4.0 and is not supported
with OpenGL ES 3.2.
\sa defaultInnerTessellationLevels(), setDefaultOuterTessellationLevels()
*/
void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels)
{
#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
if (d->tessellationFuncs) {
QVector<float> tessLevels = levels;
// Ensure we have the required 2 inner tessellation levels
// Use default of 1 for missing entries (same as spec)
const int argCount = 2;
if (tessLevels.size() < argCount) {
tessLevels.reserve(argCount);
for (int i = tessLevels.size(); i < argCount; ++i)
tessLevels.append(1.0f);
}
d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data());
}
#else
Q_UNUSED(levels);
#endif
}
/*!
Returns the default inner tessellation levels to be used by the tessellation
primitive generator in the event that the tessellation control shader
does not output them. For more details on OpenGL and Tessellation shaders see
\l{OpenGL Tessellation Shaders}.
Returns a QVector of floats describing the inner tessellation levels. The vector
will always have two elements but not all of them make sense for every mode
of tessellation.
\note This returns the global OpenGL state value. It is not specific to
this QOpenGLShaderProgram instance.
\note This function is only supported with OpenGL >= 4.0 and will not
return valid results with OpenGL ES 3.2.
\sa setDefaultInnerTessellationLevels(), defaultOuterTessellationLevels()
*/
QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const
{
#ifndef QT_OPENGL_ES_2
QVector<float> tessLevels(2, 1.0f);
Q_D(const QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data());
return tessLevels;
#else
return QVector<float>();
#endif
}
/*!
Returns \c true if shader programs written in the OpenGL Shading
Language (GLSL) are supported on this system; false otherwise.
The \a context is used to resolve the GLSL extensions.
If \a context is \nullptr, then QOpenGLContext::currentContext()
is used.
*/
bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context)
{
if (!context)
context = QOpenGLContext::currentContext();
if (!context)
return false;
return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders);
}
/*!
\internal
*/
void QOpenGLShaderProgram::shaderDestroyed()
{
Q_D(QOpenGLShaderProgram);
QOpenGLShader *shader = qobject_cast<QOpenGLShader *>(sender());
if (shader && !d->removingShaders)
removeShader(shader);
}
/*!
Returns \c true if shader programs of type \a type are supported on
this system; false otherwise.
The \a context is used to resolve the GLSL extensions.
If \a context is \nullptr, then QOpenGLContext::currentContext()
is used.
*/
bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
{
if (!context)
context = QOpenGLContext::currentContext();
if (!context)
return false;
if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0)
return false;
if (type & QOpenGLShader::Geometry)
return supportsGeometry(context->format());
else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation))
return supportsTessellation(context->format());
else if (type & QOpenGLShader::Compute)
return supportsCompute(context->format());
// Unconditional support of vertex and fragment shaders implicitly assumes
// a minimum OpenGL version of 2.0
return true;
}
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
return !binSupportCheck.get(QOpenGLContext::currentContext())->isSupported();
}
bool QOpenGLShaderProgramPrivate::compileCacheable()
{
Q_Q(QOpenGLShaderProgram);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
if (!s->compileSourceCode(shader.source)) {
log = s->log();
return false;
}
anonShaders.append(s.take());
if (!q->addShader(anonShaders.last()))
return false;
}
return true;
}
bool QOpenGLShaderProgramPrivate::linkBinary()
{
static QOpenGLProgramBinaryCache binCache;
Q_Q(QOpenGLShaderProgram);
const QByteArray cacheKey = binaryProgram.cacheKey();
if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
binaryProgram.shaders.count(), cacheKey.constData());
bool needsCompile = true;
if (binCache.load(cacheKey, q->programId())) {
qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
needsCompile = false;
}
bool needsSave = false;
if (needsCompile) {
qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
if (compileCacheable())
needsSave = true;
else
return false;
}
linkBinaryRecursion = true;
bool ok = q->link();
linkBinaryRecursion = false;
if (ok && needsSave)
binCache.save(cacheKey, q->programId());
return ok;
}
QT_END_NAMESPACE