The QT_OPENGL_ES* macros are leftovers from an earlier, ad hoc configuration system, which has since been replaced by QT_CONFIG. To clean things up in Qt 6, we use the new way instead. Task-number: QTBUG-83467 Change-Id: I578dc7695bff9d5ee303b22e44f60fee22fe0c28 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
3812 lines
118 KiB
C++
3812 lines
118 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the QtOpenGL 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 "qopenglextrafunctions.h"
|
|
#include "private/qopenglcontext_p.h"
|
|
#include <QtOpenGL/QOpenGLVersionFunctionsFactory>
|
|
#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/private/qopenglprogrambinarycache_p.h>
|
|
#include <QtGui/qtransform.h>
|
|
#include <QtGui/QColor>
|
|
#include <QtGui/QSurfaceFormat>
|
|
|
|
#if !QT_CONFIG(opengles2)
|
|
#include <QtOpenGL/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 QtOpenGL
|
|
|
|
\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 QtOpenGL
|
|
|
|
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).
|
|
*/
|
|
|
|
// 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
|
|
|
|
#if !QT_CONFIG(opengles2)
|
|
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)
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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)
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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 QT_CONFIG(opengles2) && !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)
|
|
#if !QT_CONFIG(opengles2)
|
|
, tessellationFuncs(nullptr)
|
|
#endif
|
|
, linkBinaryRecursion(false)
|
|
{
|
|
}
|
|
~QOpenGLShaderProgramPrivate();
|
|
|
|
QOpenGLSharedResourceGuard *programGuard;
|
|
bool linked;
|
|
bool inited;
|
|
bool removingShaders;
|
|
|
|
QString log;
|
|
QList<QOpenGLShader *> shaders;
|
|
QList<QOpenGLShader *> anonShaders;
|
|
|
|
QOpenGLExtraFunctions *glfuncs;
|
|
#if !QT_CONFIG(opengles2)
|
|
// 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();
|
|
|
|
#if !QT_CONFIG(opengles2)
|
|
if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) {
|
|
d->tessellationFuncs = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_0_Core>(context);
|
|
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)
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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)
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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
|
|
{
|
|
#if !QT_CONFIG(opengles2)
|
|
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
|