From 4b611d649ede3bd1e56a73abcbd16aa60db38e3b Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 17 Jan 2020 14:40:36 +0100 Subject: Move QOpenGLShaderProgram from QtGui to QtOpenGL Task-number: QTBUG-74409 Change-Id: I20dfafc0c9bf8e2b68b03e171d70c2cb4ad2bfaf Reviewed-by: Laszlo Agocs --- examples/opengl/contextinfo/CMakeLists.txt | 2 + examples/opengl/contextinfo/contextinfo.pro | 2 +- examples/opengl/contextinfo/renderwindow.cpp | 2 +- examples/opengl/hellowindow/CMakeLists.txt | 2 + examples/opengl/hellowindow/hellowindow.h | 2 +- examples/opengl/hellowindow/hellowindow.pro | 2 +- examples/opengl/paintedwindow/paintedwindow.h | 2 +- src/gui/.prev_CMakeLists.txt | 1 - src/gui/CMakeLists.txt | 1 - src/gui/opengl/opengl.pri | 2 - src/gui/opengl/qopenglprogrambinarycache.cpp | 1 - src/gui/opengl/qopenglprogrambinarycache_p.h | 11 +- src/gui/opengl/qopenglshaderprogram.cpp | 3812 ---------------------- src/gui/opengl/qopenglshaderprogram.h | 318 -- src/gui/rhi/qrhigles2.cpp | 2 - src/opengl/CMakeLists.txt | 1 + src/opengl/opengl.pro | 2 + src/opengl/qopenglshaderprogram.cpp | 3810 +++++++++++++++++++++ src/opengl/qopenglshaderprogram.h | 314 ++ src/opengl/qopengltextureblitter.cpp | 2 +- src/plugins/platforms/eglfs/api/qeglfscursor_p.h | 2 +- 21 files changed, 4145 insertions(+), 4148 deletions(-) delete mode 100644 src/gui/opengl/qopenglshaderprogram.cpp delete mode 100644 src/gui/opengl/qopenglshaderprogram.h create mode 100644 src/opengl/qopenglshaderprogram.cpp create mode 100644 src/opengl/qopenglshaderprogram.h diff --git a/examples/opengl/contextinfo/CMakeLists.txt b/examples/opengl/contextinfo/CMakeLists.txt index d174946ad6..124dfd4b52 100644 --- a/examples/opengl/contextinfo/CMakeLists.txt +++ b/examples/opengl/contextinfo/CMakeLists.txt @@ -14,6 +14,7 @@ set(INSTALL_EXAMPLEDIR "examples/opengl/contextinfo") find_package(Qt6 COMPONENTS Core) find_package(Qt6 COMPONENTS Gui) find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS OpenGL) add_qt_gui_executable(contextinfo main.cpp @@ -23,6 +24,7 @@ add_qt_gui_executable(contextinfo target_link_libraries(contextinfo PUBLIC Qt::Core Qt::Gui + Qt::OpenGL Qt::Widgets ) diff --git a/examples/opengl/contextinfo/contextinfo.pro b/examples/opengl/contextinfo/contextinfo.pro index 3d948dd282..ae8f4067b6 100644 --- a/examples/opengl/contextinfo/contextinfo.pro +++ b/examples/opengl/contextinfo/contextinfo.pro @@ -1,5 +1,5 @@ TEMPLATE = app -QT += widgets +QT += widgets opengl requires(qtConfig(filedialog)) SOURCES += main.cpp \ diff --git a/examples/opengl/contextinfo/renderwindow.cpp b/examples/opengl/contextinfo/renderwindow.cpp index ea9a7a24cb..b778fd1d89 100644 --- a/examples/opengl/contextinfo/renderwindow.cpp +++ b/examples/opengl/contextinfo/renderwindow.cpp @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include RenderWindow::RenderWindow(const QSurfaceFormat &format) diff --git a/examples/opengl/hellowindow/CMakeLists.txt b/examples/opengl/hellowindow/CMakeLists.txt index 58bd3fc362..876c282fbe 100644 --- a/examples/opengl/hellowindow/CMakeLists.txt +++ b/examples/opengl/hellowindow/CMakeLists.txt @@ -13,6 +13,7 @@ set(INSTALL_EXAMPLEDIR "examples/opengl/hellowindow") find_package(Qt6 COMPONENTS Core) find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS OpenGL) add_qt_gui_executable(hellowindow hellowindow.cpp hellowindow.h @@ -23,6 +24,7 @@ target_link_libraries(hellowindow PUBLIC Qt::CorePrivate Qt::Gui Qt::GuiPrivate + Qt::OpenGL ) install(TARGETS hellowindow diff --git a/examples/opengl/hellowindow/hellowindow.h b/examples/opengl/hellowindow/hellowindow.h index e6d7970cfc..938c6409a4 100644 --- a/examples/opengl/hellowindow/hellowindow.h +++ b/examples/opengl/hellowindow/hellowindow.h @@ -52,7 +52,7 @@ #include #include -#include +#include #include #include #include diff --git a/examples/opengl/hellowindow/hellowindow.pro b/examples/opengl/hellowindow/hellowindow.pro index cc220fd344..27c274a378 100644 --- a/examples/opengl/hellowindow/hellowindow.pro +++ b/examples/opengl/hellowindow/hellowindow.pro @@ -1,4 +1,4 @@ -QT += gui-private core-private +QT += gui-private core-private opengl HEADERS += hellowindow.h SOURCES += hellowindow.cpp main.cpp diff --git a/examples/opengl/paintedwindow/paintedwindow.h b/examples/opengl/paintedwindow/paintedwindow.h index 0dace49a33..972d8d10bd 100644 --- a/examples/opengl/paintedwindow/paintedwindow.h +++ b/examples/opengl/paintedwindow/paintedwindow.h @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include diff --git a/src/gui/.prev_CMakeLists.txt b/src/gui/.prev_CMakeLists.txt index 1f950e27c0..84c3749947 100644 --- a/src/gui/.prev_CMakeLists.txt +++ b/src/gui/.prev_CMakeLists.txt @@ -260,7 +260,6 @@ qt_extend_target(Gui CONDITION QT_FEATURE_opengl opengl/qopenglextrafunctions.h opengl/qopenglfunctions.cpp opengl/qopenglfunctions.h opengl/qopenglprogrambinarycache.cpp opengl/qopenglprogrambinarycache_p.h - opengl/qopenglshaderprogram.cpp opengl/qopenglshaderprogram.h opengl/qopenglversionfunctions.cpp opengl/qopenglversionfunctions.h opengl/qopenglversionfunctionsfactory.cpp opengl/qopenglversionfunctionsfactory_p.h opengl/qopenglvertexarrayobject.cpp opengl/qopenglvertexarrayobject.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 5b812628ea..bd8c59e198 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -342,7 +342,6 @@ qt_extend_target(Gui CONDITION QT_FEATURE_opengl opengl/qopenglextrafunctions.h opengl/qopenglfunctions.cpp opengl/qopenglfunctions.h opengl/qopenglprogrambinarycache.cpp opengl/qopenglprogrambinarycache_p.h - opengl/qopenglshaderprogram.cpp opengl/qopenglshaderprogram.h opengl/qopenglversionfunctions.cpp opengl/qopenglversionfunctions.h opengl/qopenglversionfunctionsfactory.cpp opengl/qopenglversionfunctionsfactory_p.h opengl/qopenglvertexarrayobject.cpp opengl/qopenglvertexarrayobject.h diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index 00ac48fa75..c606e9ec02 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -9,7 +9,6 @@ qtConfig(opengl) { opengl/qopengl_p.h \ opengl/qopenglfunctions.h \ opengl/qopenglbuffer.h \ - opengl/qopenglshaderprogram.h \ opengl/qopenglextensions_p.h \ opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ @@ -20,7 +19,6 @@ qtConfig(opengl) { SOURCES += opengl/qopengl.cpp \ opengl/qopenglfunctions.cpp \ opengl/qopenglbuffer.cpp \ - opengl/qopenglshaderprogram.cpp \ opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ opengl/qopenglvertexarrayobject.cpp \ diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp index 72bdacf43f..89c44e72c0 100644 --- a/src/gui/opengl/qopenglprogrambinarycache.cpp +++ b/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #ifdef Q_OS_UNIX diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h index f1cf24cd87..873e9d7c00 100644 --- a/src/gui/opengl/qopenglprogrambinarycache_p.h +++ b/src/gui/opengl/qopenglprogrambinarycache_p.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -63,10 +64,12 @@ QT_BEGIN_NAMESPACE // therefore stay independent from QOpenGLShader(Program). Must rely only on // QOpenGLContext/Functions. -class QOpenGLProgramBinaryCache +Q_GUI_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache) + +class Q_GUI_EXPORT QOpenGLProgramBinaryCache { public: - struct ShaderDesc { + struct Q_GUI_EXPORT ShaderDesc { ShaderDesc() { } ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray()) : stage(stage), source(source) @@ -74,7 +77,7 @@ public: QShader::Stage stage; QByteArray source; }; - struct ProgramDesc { + struct Q_GUI_EXPORT ProgramDesc { QVector shaders; QByteArray cacheKey() const; }; @@ -114,7 +117,7 @@ private: // per-context basis, not just once per process. QOpenGLSharedResource enables this, // although it's once-per-sharing-context-group, not per-context. Still, this should // be good enough in practice. -class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource +class Q_GUI_EXPORT QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource { public: QOpenGLProgramBinarySupportCheck(QOpenGLContext *context); diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp deleted file mode 100644 index 7e89d9c8d4..0000000000 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ /dev/null @@ -1,3812 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qopenglshaderprogram.h" -#include "qopenglprogrambinarycache_p.h" -#include "qopenglextrafunctions.h" -#include "private/qopenglcontext_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(QT_OPENGL_ES_2) -#include -#endif - -#include - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLShaderProgram - \brief The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used. - \since 5.0 - \ingroup painting-3D - \inmodule QtGui - - \section1 Introduction - - This class supports shader programs written in the OpenGL Shading - Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). - - QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of - compiling and linking vertex and fragment shaders. - - The following example creates a vertex shader program using the - supplied source \c{code}. Once compiled and linked, the shader - program is activated in the current QOpenGLContext by calling - QOpenGLShaderProgram::bind(): - - \snippet code/src_gui_qopenglshaderprogram.cpp 0 - - \section1 Writing Portable Shaders - - Shader programs can be difficult to reuse across OpenGL implementations - because of varying levels of support for standard vertex attributes and - uniform variables. In particular, GLSL/ES lacks all of the - standard variables that are present on desktop OpenGL systems: - \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL - lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. - - The QOpenGLShaderProgram class makes the process of writing portable shaders - easier by prefixing all shader programs with the following lines on - desktop OpenGL: - - \code - #define highp - #define mediump - #define lowp - \endcode - - This makes it possible to run most GLSL/ES shader programs - on desktop systems. The programmer should restrict themselves - to just features that are present in GLSL/ES, and avoid - standard variable names that only work on the desktop. - - \section1 Simple Shader Example - - \snippet code/src_gui_qopenglshaderprogram.cpp 1 - - With the above shader program active, we can draw a green triangle - as follows: - - \snippet code/src_gui_qopenglshaderprogram.cpp 2 - - \section1 Binary Shaders and Programs - - Binary shaders may be specified using \c{glShaderBinary()} on - the return value from QOpenGLShader::shaderId(). The QOpenGLShader instance - containing the binary can then be added to the shader program with - addShader() and linked in the usual fashion with link(). - - Binary programs may be specified using \c{glProgramBinaryOES()} - on the return value from programId(). Then the application should - call link(), which will notice that the program has already been - specified and linked, allowing other operations to be performed - on the shader program. The shader program's id can be explicitly - created using the create() function. - - \section2 Caching Program Binaries - - As of Qt 5.9, support for caching program binaries on disk is built in. To - enable this, switch to using addCacheableShaderFromSourceCode() and - addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support - for \c{GL_ARB_get_program_binary}, this will transparently cache program - binaries under QStandardPaths::GenericCacheLocation or - QStandardPaths::CacheLocation. When support is not available, calling the - cacheable function variants is equivalent to the normal ones. - - \note Some drivers do not have any binary formats available, even though - they advertise the extension or offer OpenGL ES 3.0. In this case program - binary support will be disabled. - - \sa QOpenGLShader -*/ - -/*! - \class QOpenGLShader - \brief The QOpenGLShader class allows OpenGL shaders to be compiled. - \since 5.0 - \ingroup painting-3D - \inmodule QtGui - - This class supports shaders written in the OpenGL Shading Language (GLSL) - and in the OpenGL/ES Shading Language (GLSL/ES). - - QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of - compiling and linking vertex and fragment shaders. - - \sa QOpenGLShaderProgram -*/ - -/*! - \enum QOpenGLShader::ShaderTypeBit - This enum specifies the type of QOpenGLShader that is being created. - - \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). - \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). - \value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL) - (requires OpenGL >= 3.2 or OpenGL ES >= 3.2). - \value TessellationControl Tessellation control shaders written in the OpenGL - shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). - \value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL - shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). - \value Compute Compute shaders written in the OpenGL shading language (GLSL) - (requires OpenGL >= 4.3 or OpenGL ES >= 3.1). -*/ - -Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache) - -// For GLES 3.1/3.2 -#ifndef GL_GEOMETRY_SHADER -#define GL_GEOMETRY_SHADER 0x8DD9 -#endif -#ifndef GL_TESS_CONTROL_SHADER -#define GL_TESS_CONTROL_SHADER 0x8E88 -#endif -#ifndef GL_TESS_EVALUATION_SHADER -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#endif -#ifndef GL_COMPUTE_SHADER -#define GL_COMPUTE_SHADER 0x91B9 -#endif -#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#endif -#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#endif -#ifndef GL_PATCH_VERTICES -#define GL_PATCH_VERTICES 0x8E72 -#endif -#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#endif -#ifndef GL_PATCH_DEFAULT_INNER_LEVEL -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#endif - -#ifndef QT_OPENGL_ES_2 -static inline bool isFormatGLES(const QSurfaceFormat &f) -{ - return (f.renderableType() == QSurfaceFormat::OpenGLES); -} -#endif - -static inline bool supportsGeometry(const QSurfaceFormat &f) -{ - return f.version() >= qMakePair(3, 2); -} - -static inline bool supportsCompute(const QSurfaceFormat &f) -{ -#ifndef QT_OPENGL_ES_2 - if (!isFormatGLES(f)) - return f.version() >= qMakePair(4, 3); - else - return f.version() >= qMakePair(3, 1); -#else - return f.version() >= qMakePair(3, 1); -#endif -} - -static inline bool supportsTessellation(const QSurfaceFormat &f) -{ -#ifndef QT_OPENGL_ES_2 - if (!isFormatGLES(f)) - return f.version() >= qMakePair(4, 0); - else - return f.version() >= qMakePair(3, 2); -#else - return f.version() >= qMakePair(3, 2); -#endif -} - -class QOpenGLShaderPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLShader) -public: - QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type) - : shaderGuard(nullptr) - , shaderType(type) - , compiled(false) - , glfuncs(new QOpenGLExtraFunctions(ctx)) - , supportsGeometryShaders(false) - , supportsTessellationShaders(false) - , supportsComputeShaders(false) - { - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = supportsGeometry(ctx->format()); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = supportsTessellation(ctx->format()); - else if (shaderType & QOpenGLShader::Compute) - supportsComputeShaders = supportsCompute(ctx->format()); - } - ~QOpenGLShaderPrivate(); - - QOpenGLSharedResourceGuard *shaderGuard; - QOpenGLShader::ShaderType shaderType; - bool compiled; - QString log; - - QOpenGLExtraFunctions *glfuncs; - - // Support for geometry shaders - bool supportsGeometryShaders; - // Support for tessellation shaders - bool supportsTessellationShaders; - // Support for compute shaders - bool supportsComputeShaders; - - - bool create(); - bool compile(QOpenGLShader *q); - void deleteShader(); -}; - -namespace { - void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteShader(id); - } -} - -QOpenGLShaderPrivate::~QOpenGLShaderPrivate() -{ - delete glfuncs; - if (shaderGuard) - shaderGuard->free(); -} - -bool QOpenGLShaderPrivate::create() -{ - QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); - if (!context) - return false; - GLuint shader = 0; - if (shaderType == QOpenGLShader::Vertex) { - shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); - } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { - shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); - } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { - shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); - } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { - shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); - } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { - shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); - } else if (shaderType == QOpenGLShader::Fragment) { - shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); - } - if (!shader) { - qWarning("QOpenGLShader: could not create shader"); - return false; - } - shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc); - return true; -} - -bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) -{ - GLuint shader = shaderGuard ? shaderGuard->id() : 0; - if (!shader) - return false; - - // Try to compile shader - glfuncs->glCompileShader(shader); - GLint value = 0; - - // Get compilation status - glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value); - compiled = (value != 0); - - if (!compiled) { - // Compilation failed, try to provide some information about the failure - QString name = q->objectName(); - - const char *types[] = { - "Fragment", - "Vertex", - "Geometry", - "Tessellation Control", - "Tessellation Evaluation", - "Compute", - "" - }; - - const char *type = types[6]; - switch (shaderType) { - case QOpenGLShader::Fragment: - type = types[0]; break; - case QOpenGLShader::Vertex: - type = types[1]; break; - case QOpenGLShader::Geometry: - type = types[2]; break; - case QOpenGLShader::TessellationControl: - type = types[3]; break; - case QOpenGLShader::TessellationEvaluation: - type = types[4]; break; - case QOpenGLShader::Compute: - type = types[5]; break; - } - - // Get info and source code lengths - GLint infoLogLength = 0; - GLint sourceCodeLength = 0; - char *logBuffer = nullptr; - char *sourceCodeBuffer = nullptr; - - // Get the compilation info log - glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); - - if (infoLogLength > 1) { - GLint temp; - logBuffer = new char [infoLogLength]; - glfuncs->glGetShaderInfoLog(shader, infoLogLength, &temp, logBuffer); - } - - // Get the source code - glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceCodeLength); - - if (sourceCodeLength > 1) { - GLint temp; - sourceCodeBuffer = new char [sourceCodeLength]; - glfuncs->glGetShaderSource(shader, sourceCodeLength, &temp, sourceCodeBuffer); - } - - if (logBuffer) - log = QString::fromLatin1(logBuffer); - else - log = QLatin1String("failed"); - - if (name.isEmpty()) - qWarning("QOpenGLShader::compile(%s): %s", type, qPrintable(log)); - else - qWarning("QOpenGLShader::compile(%s)[%s]: %s", type, qPrintable(name), qPrintable(log)); - - // Dump the source code if we got it - if (sourceCodeBuffer) { - qWarning("*** Problematic %s shader source code ***\n" - "%ls\n" - "***", - type, qUtf16Printable(QString::fromLatin1(sourceCodeBuffer))); - } - - // Cleanup - delete [] logBuffer; - delete [] sourceCodeBuffer; - } - - return compiled; -} - -void QOpenGLShaderPrivate::deleteShader() -{ - if (shaderGuard) { - shaderGuard->free(); - shaderGuard = nullptr; - } -} - -/*! - Constructs a new QOpenGLShader object of the specified \a type - and attaches it to \a parent. If shader programs are not supported, - QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false. - - This constructor is normally followed by a call to compileSourceCode() - or compileSourceFile(). - - The shader will be associated with the current QOpenGLContext. - - \sa compileSourceCode(), compileSourceFile() -*/ -QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent) - : QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent) -{ - Q_D(QOpenGLShader); - d->create(); -} - -/*! - Deletes this shader. If the shader has been attached to a - QOpenGLShaderProgram object, then the actual shader will stay around - until the QOpenGLShaderProgram is destroyed. -*/ -QOpenGLShader::~QOpenGLShader() -{ -} - -/*! - Returns the type of this shader. -*/ -QOpenGLShader::ShaderType QOpenGLShader::shaderType() const -{ - Q_D(const QOpenGLShader); - return d->shaderType; -} - -static const char qualifierDefines[] = - "#define lowp\n" - "#define mediump\n" - "#define highp\n"; - -#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES) -// The "highp" qualifier doesn't exist in fragment shaders -// on all ES platforms. When it doesn't exist, use "mediump". -#define QOpenGL_REDEFINE_HIGHP 1 -static const char redefineHighp[] = - "#ifndef GL_FRAGMENT_PRECISION_HIGH\n" - "#define highp mediump\n" - "#endif\n"; -#endif - -// Boiler-plate header to have the layout attributes available we need later -static const char blendEquationAdvancedHeader[] = - "#ifdef GL_KHR_blend_equation_advanced\n" - "#extension GL_ARB_fragment_coord_conventions : enable\n" - "#extension GL_KHR_blend_equation_advanced : enable\n" - "#endif\n"; - -struct QVersionDirectivePosition -{ - Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) - : position(position) - , line(line) - { - } - - Q_DECL_CONSTEXPR bool hasPosition() const - { - return position > 0; - } - - const int position; - const int line; -}; - -static QVersionDirectivePosition findVersionDirectivePosition(const char *source) -{ - Q_ASSERT(source); - - // According to the GLSL spec the #version directive must not be - // preceded by anything but whitespace and comments. - // In order to not get confused by #version directives within a - // multiline comment, we need to do some minimal comment parsing - // while searching for the directive. - enum { - Normal, - StartOfLine, - PreprocessorDirective, - CommentStarting, - MultiLineComment, - SingleLineComment, - CommentEnding - } state = StartOfLine; - - const char *c = source; - while (*c) { - switch (state) { - case PreprocessorDirective: - if (*c == ' ' || *c == '\t') - break; - if (!strncmp(c, "version", strlen("version"))) { - // Found version directive - c += strlen("version"); - while (*c && *c != '\n') - ++c; - int splitPosition = c - source + 1; - int linePosition = int(std::count(source, c, '\n')) + 1; - return QVersionDirectivePosition(splitPosition, linePosition); - } else if (*c == '/') - state = CommentStarting; - else if (*c == '\n') - state = StartOfLine; - else - state = Normal; - break; - case StartOfLine: - if (*c == ' ' || *c == '\t') - break; - else if (*c == '#') { - state = PreprocessorDirective; - break; - } - state = Normal; - Q_FALLTHROUGH(); - case Normal: - if (*c == '/') - state = CommentStarting; - else if (*c == '\n') - state = StartOfLine; - break; - case CommentStarting: - if (*c == '*') - state = MultiLineComment; - else if (*c == '/') - state = SingleLineComment; - else - state = Normal; - break; - case MultiLineComment: - if (*c == '*') - state = CommentEnding; - break; - case SingleLineComment: - if (*c == '\n') - state = Normal; - break; - case CommentEnding: - if (*c == '/') - state = Normal; - else if (*c != QLatin1Char('*')) - state = MultiLineComment; - break; - } - ++c; - } - - return QVersionDirectivePosition(0, 1); -} - -/*! - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const char *source) -{ - Q_D(QOpenGLShader); - // This method breaks the shader code into two parts: - // 1. Up to and including an optional #version directive. - // 2. The rest. - // If a #version directive exists, qualifierDefines and redefineHighp - // are inserted after. Otherwise they are inserted right at the start. - // In both cases a #line directive is appended in order to compensate - // for line number changes in case of compiler errors. - - if (d->shaderGuard && d->shaderGuard->id() && source) { - const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source); - - QVarLengthArray sourceChunks; - QVarLengthArray 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(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(ctx->functions()->glGetString(GL_VERSION)); - if (!version || !strstr(version, "2.1 Mesa 8")) { - // Append #line directive in order to compensate for text insertion - lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); - sourceChunks.append(lineDirective.constData()); - sourceChunkLengths.append(GLint(lineDirective.length())); - } - - // Append rest of shader code - sourceChunks.append(source + versionDirectivePosition.position); - sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position))); - - d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data()); - return d->compile(this); - } else { - return false; - } -} - -/*! - \overload - - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const QByteArray& source) -{ - return compileSourceCode(source.constData()); -} - -/*! - \overload - - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const QString& source) -{ - return compileSourceCode(source.toLatin1().constData()); -} - -/*! - Sets the source code for this shader to the contents of \a fileName - and compiles it. Returns \c true if the file could be opened and the - source compiled, false otherwise. - - \sa compileSourceCode() -*/ -bool QOpenGLShader::compileSourceFile(const QString& fileName) -{ - QFile file(fileName); - if (!file.open(QFile::ReadOnly)) { - qWarning() << "QOpenGLShader: Unable to open file" << fileName; - return false; - } - - QByteArray contents = file.readAll(); - return compileSourceCode(contents.constData()); -} - -/*! - Returns the source code for this shader. - - \sa compileSourceCode() -*/ -QByteArray QOpenGLShader::sourceCode() const -{ - Q_D(const QOpenGLShader); - GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; - if (!shader) - return QByteArray(); - GLint size = 0; - d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); - if (size <= 0) - return QByteArray(); - GLint len = 0; - char *source = new char [size]; - d->glfuncs->glGetShaderSource(shader, size, &len, source); - QByteArray src(source); - delete [] source; - return src; -} - -/*! - Returns \c true if this shader has been compiled; false otherwise. - - \sa compileSourceCode(), compileSourceFile() -*/ -bool QOpenGLShader::isCompiled() const -{ - Q_D(const QOpenGLShader); - return d->compiled; -} - -/*! - Returns the errors and warnings that occurred during the last compile. - - \sa compileSourceCode(), compileSourceFile() -*/ -QString QOpenGLShader::log() const -{ - Q_D(const QOpenGLShader); - return d->log; -} - -/*! - Returns the OpenGL identifier associated with this shader. - - \sa QOpenGLShaderProgram::programId() -*/ -GLuint QOpenGLShader::shaderId() const -{ - Q_D(const QOpenGLShader); - return d->shaderGuard ? d->shaderGuard->id() : 0; -} - -class QOpenGLShaderProgramPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLShaderProgram) -public: - QOpenGLShaderProgramPrivate() - : programGuard(nullptr) - , linked(false) - , inited(false) - , removingShaders(false) - , glfuncs(new QOpenGLExtraFunctions) -#ifndef QT_OPENGL_ES_2 - , tessellationFuncs(nullptr) -#endif - , linkBinaryRecursion(false) - { - } - ~QOpenGLShaderProgramPrivate(); - - QOpenGLSharedResourceGuard *programGuard; - bool linked; - bool inited; - bool removingShaders; - - QString log; - QList shaders; - QList anonShaders; - - QOpenGLExtraFunctions *glfuncs; -#ifndef QT_OPENGL_ES_2 - // for tessellation features not in GLES 3.2 - QOpenGLFunctions_4_0_Core *tessellationFuncs; -#endif - - bool hasShader(QOpenGLShader::ShaderType type) const; - - QOpenGLProgramBinaryCache::ProgramDesc binaryProgram; - bool isCacheDisabled() const; - bool compileCacheable(); - bool linkBinary(); - - bool linkBinaryRecursion; -}; - -namespace { - void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteProgram(id); - } -} - - -QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate() -{ - delete glfuncs; - if (programGuard) - programGuard->free(); -} - -bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const -{ - for (QOpenGLShader *shader : shaders) { - if (shader->shaderType() == type) - return true; - } - return false; -} - -/*! - Constructs a new shader program and attaches it to \a parent. - The program will be invalid until addShader() is called. - - The shader program will be associated with the current QOpenGLContext. - - \sa addShader() -*/ -QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent) - : QObject(*new QOpenGLShaderProgramPrivate, parent) -{ -} - -/*! - Deletes this shader program. -*/ -QOpenGLShaderProgram::~QOpenGLShaderProgram() -{ -} - -/*! - Requests the shader program's id to be created immediately. Returns \c true - if successful; \c false otherwise. - - This function is primarily useful when combining QOpenGLShaderProgram - with other OpenGL functions that operate directly on the shader - program id, like \c {GL_OES_get_program_binary}. - - When the shader program is used normally, the shader program's id will - be created on demand. - - \sa programId() - - \since 5.3 - */ -bool QOpenGLShaderProgram::create() -{ - return init(); -} - -bool QOpenGLShaderProgram::init() -{ - Q_D(QOpenGLShaderProgram); - if ((d->programGuard && d->programGuard->id()) || d->inited) - return true; - d->inited = true; - QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); - if (!context) - return false; - d->glfuncs->initializeOpenGLFunctions(); - -#ifndef QT_OPENGL_ES_2 - if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) { - d->tessellationFuncs = context->versionFunctions(); - 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 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(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(&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(&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(&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(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(&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(&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(&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(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(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(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(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(values[0].constData())); \ - } else { \ - QVarLengthArray 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 \ - (values[0].constData()); \ - colfunc(location, count * cols, data); \ - } else { \ - QVarLengthArray 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 &levels) -{ -#ifndef QT_OPENGL_ES_2 - Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) { - QVector 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 QOpenGLShaderProgram::defaultOuterTessellationLevels() const -{ -#ifndef QT_OPENGL_ES_2 - QVector 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(); -#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 &levels) -{ -#ifndef QT_OPENGL_ES_2 - Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) { - QVector 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 QOpenGLShaderProgram::defaultInnerTessellationLevels() const -{ -#ifndef QT_OPENGL_ES_2 - QVector 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(); -#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(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 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 diff --git a/src/gui/opengl/qopenglshaderprogram.h b/src/gui/opengl/qopenglshaderprogram.h deleted file mode 100644 index c79101fd4d..0000000000 --- a/src/gui/opengl/qopenglshaderprogram.h +++ /dev/null @@ -1,318 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOPENGLSHADERPROGRAM_H -#define QOPENGLSHADERPROGRAM_H - -#include - -#ifndef QT_NO_OPENGL - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - - -class QOpenGLContext; -class QOpenGLShaderProgram; -class QOpenGLShaderPrivate; - -class Q_GUI_EXPORT QOpenGLShader : public QObject -{ - Q_OBJECT -public: - enum ShaderTypeBit - { - Vertex = 0x0001, - Fragment = 0x0002, - Geometry = 0x0004, - TessellationControl = 0x0008, - TessellationEvaluation = 0x0010, - Compute = 0x0020 - }; - Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit) - - explicit QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent = nullptr); - ~QOpenGLShader(); - - QOpenGLShader::ShaderType shaderType() const; - - bool compileSourceCode(const char *source); - bool compileSourceCode(const QByteArray& source); - bool compileSourceCode(const QString& source); - bool compileSourceFile(const QString& fileName); - - QByteArray sourceCode() const; - - bool isCompiled() const; - QString log() const; - - GLuint shaderId() const; - - static bool hasOpenGLShaders(ShaderType type, QOpenGLContext *context = nullptr); - -private: - friend class QOpenGLShaderProgram; - - Q_DISABLE_COPY(QOpenGLShader) - Q_DECLARE_PRIVATE(QOpenGLShader) -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLShader::ShaderType) - - -class QOpenGLShaderProgramPrivate; - -class Q_GUI_EXPORT QOpenGLShaderProgram : public QObject -{ - Q_OBJECT -public: - explicit QOpenGLShaderProgram(QObject *parent = nullptr); - ~QOpenGLShaderProgram(); - - bool addShader(QOpenGLShader *shader); - void removeShader(QOpenGLShader *shader); - QList shaders() const; - - bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); - bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source); - bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source); - bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName); - - bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); - bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source); - bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source); - bool addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName); - - void removeAllShaders(); - - virtual bool link(); - bool isLinked() const; - QString log() const; - - bool bind(); - void release(); - - bool create(); - - GLuint programId() const; - - int maxGeometryOutputVertices() const; - - void setPatchVertexCount(int count); - int patchVertexCount() const; - - void setDefaultOuterTessellationLevels(const QVector &levels); - QVector defaultOuterTessellationLevels() const; - - void setDefaultInnerTessellationLevels(const QVector &levels); - QVector defaultInnerTessellationLevels() const; - - void bindAttributeLocation(const char *name, int location); - void bindAttributeLocation(const QByteArray& name, int location); - void bindAttributeLocation(const QString& name, int location); - - int attributeLocation(const char *name) const; - int attributeLocation(const QByteArray& name) const; - int attributeLocation(const QString& name) const; - - void setAttributeValue(int location, GLfloat value); - void setAttributeValue(int location, GLfloat x, GLfloat y); - void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z); - void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void setAttributeValue(int location, const QVector2D& value); - void setAttributeValue(int location, const QVector3D& value); - void setAttributeValue(int location, const QVector4D& value); - void setAttributeValue(int location, const QColor& value); - void setAttributeValue(int location, const GLfloat *values, int columns, int rows); - - void setAttributeValue(const char *name, GLfloat value); - void setAttributeValue(const char *name, GLfloat x, GLfloat y); - void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z); - void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void setAttributeValue(const char *name, const QVector2D& value); - void setAttributeValue(const char *name, const QVector3D& value); - void setAttributeValue(const char *name, const QVector4D& value); - void setAttributeValue(const char *name, const QColor& value); - void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); - - void setAttributeArray - (int location, const GLfloat *values, int tupleSize, int stride = 0); - void setAttributeArray - (int location, const QVector2D *values, int stride = 0); - void setAttributeArray - (int location, const QVector3D *values, int stride = 0); - void setAttributeArray - (int location, const QVector4D *values, int stride = 0); - void setAttributeArray - (int location, GLenum type, const void *values, int tupleSize, int stride = 0); - void setAttributeArray - (const char *name, const GLfloat *values, int tupleSize, int stride = 0); - void setAttributeArray - (const char *name, const QVector2D *values, int stride = 0); - void setAttributeArray - (const char *name, const QVector3D *values, int stride = 0); - void setAttributeArray - (const char *name, const QVector4D *values, int stride = 0); - void setAttributeArray - (const char *name, GLenum type, const void *values, int tupleSize, int stride = 0); - - void setAttributeBuffer - (int location, GLenum type, int offset, int tupleSize, int stride = 0); - void setAttributeBuffer - (const char *name, GLenum type, int offset, int tupleSize, int stride = 0); - - void enableAttributeArray(int location); - void enableAttributeArray(const char *name); - void disableAttributeArray(int location); - void disableAttributeArray(const char *name); - - int uniformLocation(const char *name) const; - int uniformLocation(const QByteArray& name) const; - int uniformLocation(const QString& name) const; - - void setUniformValue(int location, GLfloat value); - void setUniformValue(int location, GLint value); - void setUniformValue(int location, GLuint value); - void setUniformValue(int location, GLfloat x, GLfloat y); - void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z); - void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void setUniformValue(int location, const QVector2D& value); - void setUniformValue(int location, const QVector3D& value); - void setUniformValue(int location, const QVector4D& value); - void setUniformValue(int location, const QColor& color); - void setUniformValue(int location, const QPoint& point); - void setUniformValue(int location, const QPointF& point); - void setUniformValue(int location, const QSize& size); - void setUniformValue(int location, const QSizeF& size); - void setUniformValue(int location, const QMatrix2x2& value); - void setUniformValue(int location, const QMatrix2x3& value); - void setUniformValue(int location, const QMatrix2x4& value); - void setUniformValue(int location, const QMatrix3x2& value); - void setUniformValue(int location, const QMatrix3x3& value); - void setUniformValue(int location, const QMatrix3x4& value); - void setUniformValue(int location, const QMatrix4x2& value); - void setUniformValue(int location, const QMatrix4x3& value); - void setUniformValue(int location, const QMatrix4x4& value); - void setUniformValue(int location, const GLfloat value[2][2]); - void setUniformValue(int location, const GLfloat value[3][3]); - void setUniformValue(int location, const GLfloat value[4][4]); - void setUniformValue(int location, const QTransform& value); - - void setUniformValue(const char *name, GLfloat value); - void setUniformValue(const char *name, GLint value); - void setUniformValue(const char *name, GLuint value); - void setUniformValue(const char *name, GLfloat x, GLfloat y); - void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z); - void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void setUniformValue(const char *name, const QVector2D& value); - void setUniformValue(const char *name, const QVector3D& value); - void setUniformValue(const char *name, const QVector4D& value); - void setUniformValue(const char *name, const QColor& color); - void setUniformValue(const char *name, const QPoint& point); - void setUniformValue(const char *name, const QPointF& point); - void setUniformValue(const char *name, const QSize& size); - void setUniformValue(const char *name, const QSizeF& size); - void setUniformValue(const char *name, const QMatrix2x2& value); - void setUniformValue(const char *name, const QMatrix2x3& value); - void setUniformValue(const char *name, const QMatrix2x4& value); - void setUniformValue(const char *name, const QMatrix3x2& value); - void setUniformValue(const char *name, const QMatrix3x3& value); - void setUniformValue(const char *name, const QMatrix3x4& value); - void setUniformValue(const char *name, const QMatrix4x2& value); - void setUniformValue(const char *name, const QMatrix4x3& value); - void setUniformValue(const char *name, const QMatrix4x4& value); - void setUniformValue(const char *name, const GLfloat value[2][2]); - void setUniformValue(const char *name, const GLfloat value[3][3]); - void setUniformValue(const char *name, const GLfloat value[4][4]); - void setUniformValue(const char *name, const QTransform& value); - - void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize); - void setUniformValueArray(int location, const GLint *values, int count); - void setUniformValueArray(int location, const GLuint *values, int count); - void setUniformValueArray(int location, const QVector2D *values, int count); - void setUniformValueArray(int location, const QVector3D *values, int count); - void setUniformValueArray(int location, const QVector4D *values, int count); - void setUniformValueArray(int location, const QMatrix2x2 *values, int count); - void setUniformValueArray(int location, const QMatrix2x3 *values, int count); - void setUniformValueArray(int location, const QMatrix2x4 *values, int count); - void setUniformValueArray(int location, const QMatrix3x2 *values, int count); - void setUniformValueArray(int location, const QMatrix3x3 *values, int count); - void setUniformValueArray(int location, const QMatrix3x4 *values, int count); - void setUniformValueArray(int location, const QMatrix4x2 *values, int count); - void setUniformValueArray(int location, const QMatrix4x3 *values, int count); - void setUniformValueArray(int location, const QMatrix4x4 *values, int count); - - void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize); - void setUniformValueArray(const char *name, const GLint *values, int count); - void setUniformValueArray(const char *name, const GLuint *values, int count); - void setUniformValueArray(const char *name, const QVector2D *values, int count); - void setUniformValueArray(const char *name, const QVector3D *values, int count); - void setUniformValueArray(const char *name, const QVector4D *values, int count); - void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count); - void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count); - void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count); - void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count); - void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count); - void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count); - void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count); - void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); - void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); - - static bool hasOpenGLShaderPrograms(QOpenGLContext *context = nullptr); - -private Q_SLOTS: - void shaderDestroyed(); - -private: - Q_DISABLE_COPY(QOpenGLShaderProgram) - Q_DECLARE_PRIVATE(QOpenGLShaderProgram) - - bool init(); -}; - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 62f808ce81..3b6c022399 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -289,8 +289,6 @@ QT_BEGIN_NAMESPACE #define GL_MAP_READ_BIT 0x0001 #endif -Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache) - /*! Constructs a new QRhiGles2InitParams. diff --git a/src/opengl/CMakeLists.txt b/src/opengl/CMakeLists.txt index 5ddb50b664..17366f7cf0 100644 --- a/src/opengl/CMakeLists.txt +++ b/src/opengl/CMakeLists.txt @@ -17,6 +17,7 @@ qt_add_module(OpenGL qopenglpaintengine.cpp qopenglpaintengine_p.h qopenglpixeltransferoptions.cpp qopenglpixeltransferoptions.h qopenglshadercache_p.h + qopenglshaderprogram.cpp qopenglshaderprogram.h qopengltexture.cpp qopengltexture.h qopengltexture_p.h qopengltextureblitter.cpp qopengltextureblitter.h qopengltexturecache.cpp qopengltexturecache_p.h diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index ef81f3aec9..950a72cc03 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -22,6 +22,7 @@ HEADERS += \ qopenglpaintengine_p.h \ qopenglpixeltransferoptions.h \ qopenglshadercache_p.h \ + qopenglshaderprogram.h \ qopengltexture.h \ qopengltexture_p.h \ qopengltexturehelper_p.h \ @@ -41,6 +42,7 @@ SOURCES += \ qopenglpaintdevice.cpp \ qopenglpaintengine.cpp \ qopenglpixeltransferoptions.cpp \ + qopenglshaderprogram.cpp \ qopengltexture.cpp \ qopengltexturehelper.cpp \ qopengltextureblitter.cpp \ diff --git a/src/opengl/qopenglshaderprogram.cpp b/src/opengl/qopenglshaderprogram.cpp new file mode 100644 index 0000000000..c5e61859ee --- /dev/null +++ b/src/opengl/qopenglshaderprogram.cpp @@ -0,0 +1,3810 @@ +/**************************************************************************** +** +** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(QT_OPENGL_ES_2) +#include +#endif + +#include + +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 + +#ifndef QT_OPENGL_ES_2 +static inline bool isFormatGLES(const QSurfaceFormat &f) +{ + return (f.renderableType() == QSurfaceFormat::OpenGLES); +} +#endif + +static inline bool supportsGeometry(const QSurfaceFormat &f) +{ + return f.version() >= qMakePair(3, 2); +} + +static inline bool supportsCompute(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return f.version() >= qMakePair(4, 3); + else + return f.version() >= qMakePair(3, 1); +#else + return f.version() >= qMakePair(3, 1); +#endif +} + +static inline bool supportsTessellation(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return f.version() >= qMakePair(4, 0); + else + return f.version() >= qMakePair(3, 2); +#else + return f.version() >= qMakePair(3, 2); +#endif +} + +class QOpenGLShaderPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLShader) +public: + QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type) + : shaderGuard(nullptr) + , shaderType(type) + , compiled(false) + , glfuncs(new QOpenGLExtraFunctions(ctx)) + , supportsGeometryShaders(false) + , supportsTessellationShaders(false) + , supportsComputeShaders(false) + { + if (shaderType & QOpenGLShader::Geometry) + supportsGeometryShaders = supportsGeometry(ctx->format()); + else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + supportsTessellationShaders = supportsTessellation(ctx->format()); + else if (shaderType & QOpenGLShader::Compute) + supportsComputeShaders = supportsCompute(ctx->format()); + } + ~QOpenGLShaderPrivate(); + + QOpenGLSharedResourceGuard *shaderGuard; + QOpenGLShader::ShaderType shaderType; + bool compiled; + QString log; + + QOpenGLExtraFunctions *glfuncs; + + // Support for geometry shaders + bool supportsGeometryShaders; + // Support for tessellation shaders + bool supportsTessellationShaders; + // Support for compute shaders + bool supportsComputeShaders; + + + bool create(); + bool compile(QOpenGLShader *q); + void deleteShader(); +}; + +namespace { + void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteShader(id); + } +} + +QOpenGLShaderPrivate::~QOpenGLShaderPrivate() +{ + delete glfuncs; + if (shaderGuard) + shaderGuard->free(); +} + +bool QOpenGLShaderPrivate::create() +{ + QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); + if (!context) + return false; + GLuint shader = 0; + if (shaderType == QOpenGLShader::Vertex) { + shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); + } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { + shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); + } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { + shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); + } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { + shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); + } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { + shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); + } else if (shaderType == QOpenGLShader::Fragment) { + shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); + } + if (!shader) { + qWarning("QOpenGLShader: could not create shader"); + return false; + } + shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc); + return true; +} + +bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) +{ + GLuint shader = shaderGuard ? shaderGuard->id() : 0; + if (!shader) + return false; + + // Try to compile shader + glfuncs->glCompileShader(shader); + GLint value = 0; + + // Get compilation status + glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value); + compiled = (value != 0); + + if (!compiled) { + // Compilation failed, try to provide some information about the failure + QString name = q->objectName(); + + const char *types[] = { + "Fragment", + "Vertex", + "Geometry", + "Tessellation Control", + "Tessellation Evaluation", + "Compute", + "" + }; + + const char *type = types[6]; + switch (shaderType) { + case QOpenGLShader::Fragment: + type = types[0]; break; + case QOpenGLShader::Vertex: + type = types[1]; break; + case QOpenGLShader::Geometry: + type = types[2]; break; + case QOpenGLShader::TessellationControl: + type = types[3]; break; + case QOpenGLShader::TessellationEvaluation: + type = types[4]; break; + case QOpenGLShader::Compute: + type = types[5]; break; + } + + // Get info and source code lengths + GLint infoLogLength = 0; + GLint sourceCodeLength = 0; + char *logBuffer = nullptr; + char *sourceCodeBuffer = nullptr; + + // Get the compilation info log + glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + + if (infoLogLength > 1) { + GLint temp; + logBuffer = new char [infoLogLength]; + glfuncs->glGetShaderInfoLog(shader, infoLogLength, &temp, logBuffer); + } + + // Get the source code + glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceCodeLength); + + if (sourceCodeLength > 1) { + GLint temp; + sourceCodeBuffer = new char [sourceCodeLength]; + glfuncs->glGetShaderSource(shader, sourceCodeLength, &temp, sourceCodeBuffer); + } + + if (logBuffer) + log = QString::fromLatin1(logBuffer); + else + log = QLatin1String("failed"); + + if (name.isEmpty()) + qWarning("QOpenGLShader::compile(%s): %s", type, qPrintable(log)); + else + qWarning("QOpenGLShader::compile(%s)[%s]: %s", type, qPrintable(name), qPrintable(log)); + + // Dump the source code if we got it + if (sourceCodeBuffer) { + qWarning("*** Problematic %s shader source code ***\n" + "%ls\n" + "***", + type, qUtf16Printable(QString::fromLatin1(sourceCodeBuffer))); + } + + // Cleanup + delete [] logBuffer; + delete [] sourceCodeBuffer; + } + + return compiled; +} + +void QOpenGLShaderPrivate::deleteShader() +{ + if (shaderGuard) { + shaderGuard->free(); + shaderGuard = nullptr; + } +} + +/*! + Constructs a new QOpenGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false. + + This constructor is normally followed by a call to compileSourceCode() + or compileSourceFile(). + + The shader will be associated with the current QOpenGLContext. + + \sa compileSourceCode(), compileSourceFile() +*/ +QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent) + : QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent) +{ + Q_D(QOpenGLShader); + d->create(); +} + +/*! + Deletes this shader. If the shader has been attached to a + QOpenGLShaderProgram object, then the actual shader will stay around + until the QOpenGLShaderProgram is destroyed. +*/ +QOpenGLShader::~QOpenGLShader() +{ +} + +/*! + Returns the type of this shader. +*/ +QOpenGLShader::ShaderType QOpenGLShader::shaderType() const +{ + Q_D(const QOpenGLShader); + return d->shaderType; +} + +static const char qualifierDefines[] = + "#define lowp\n" + "#define mediump\n" + "#define highp\n"; + +#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES) +// The "highp" qualifier doesn't exist in fragment shaders +// on all ES platforms. When it doesn't exist, use "mediump". +#define QOpenGL_REDEFINE_HIGHP 1 +static const char redefineHighp[] = + "#ifndef GL_FRAGMENT_PRECISION_HIGH\n" + "#define highp mediump\n" + "#endif\n"; +#endif + +// Boiler-plate header to have the layout attributes available we need later +static const char blendEquationAdvancedHeader[] = + "#ifdef GL_KHR_blend_equation_advanced\n" + "#extension GL_ARB_fragment_coord_conventions : enable\n" + "#extension GL_KHR_blend_equation_advanced : enable\n" + "#endif\n"; + +struct QVersionDirectivePosition +{ + Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) + : position(position) + , line(line) + { + } + + Q_DECL_CONSTEXPR bool hasPosition() const + { + return position > 0; + } + + const int position; + const int line; +}; + +static QVersionDirectivePosition findVersionDirectivePosition(const char *source) +{ + Q_ASSERT(source); + + // According to the GLSL spec the #version directive must not be + // preceded by anything but whitespace and comments. + // In order to not get confused by #version directives within a + // multiline comment, we need to do some minimal comment parsing + // while searching for the directive. + enum { + Normal, + StartOfLine, + PreprocessorDirective, + CommentStarting, + MultiLineComment, + SingleLineComment, + CommentEnding + } state = StartOfLine; + + const char *c = source; + while (*c) { + switch (state) { + case PreprocessorDirective: + if (*c == ' ' || *c == '\t') + break; + if (!strncmp(c, "version", strlen("version"))) { + // Found version directive + c += strlen("version"); + while (*c && *c != '\n') + ++c; + int splitPosition = c - source + 1; + int linePosition = int(std::count(source, c, '\n')) + 1; + return QVersionDirectivePosition(splitPosition, linePosition); + } else if (*c == '/') + state = CommentStarting; + else if (*c == '\n') + state = StartOfLine; + else + state = Normal; + break; + case StartOfLine: + if (*c == ' ' || *c == '\t') + break; + else if (*c == '#') { + state = PreprocessorDirective; + break; + } + state = Normal; + Q_FALLTHROUGH(); + case Normal: + if (*c == '/') + state = CommentStarting; + else if (*c == '\n') + state = StartOfLine; + break; + case CommentStarting: + if (*c == '*') + state = MultiLineComment; + else if (*c == '/') + state = SingleLineComment; + else + state = Normal; + break; + case MultiLineComment: + if (*c == '*') + state = CommentEnding; + break; + case SingleLineComment: + if (*c == '\n') + state = Normal; + break; + case CommentEnding: + if (*c == '/') + state = Normal; + else if (*c != QLatin1Char('*')) + state = MultiLineComment; + break; + } + ++c; + } + + return QVersionDirectivePosition(0, 1); +} + +/*! + Sets the \a source code for this shader and compiles it. + Returns \c true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const char *source) +{ + Q_D(QOpenGLShader); + // This method breaks the shader code into two parts: + // 1. Up to and including an optional #version directive. + // 2. The rest. + // If a #version directive exists, qualifierDefines and redefineHighp + // are inserted after. Otherwise they are inserted right at the start. + // In both cases a #line directive is appended in order to compensate + // for line number changes in case of compiler errors. + + if (d->shaderGuard && d->shaderGuard->id() && source) { + const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source); + + QVarLengthArray sourceChunks; + QVarLengthArray 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(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(ctx->functions()->glGetString(GL_VERSION)); + if (!version || !strstr(version, "2.1 Mesa 8")) { + // Append #line directive in order to compensate for text insertion + lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); + sourceChunks.append(lineDirective.constData()); + sourceChunkLengths.append(GLint(lineDirective.length())); + } + + // Append rest of shader code + sourceChunks.append(source + versionDirectivePosition.position); + sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position))); + + d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data()); + return d->compile(this); + } else { + return false; + } +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns \c true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const QByteArray& source) +{ + return compileSourceCode(source.constData()); +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns \c true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const QString& source) +{ + return compileSourceCode(source.toLatin1().constData()); +} + +/*! + Sets the source code for this shader to the contents of \a fileName + and compiles it. Returns \c true if the file could be opened and the + source compiled, false otherwise. + + \sa compileSourceCode() +*/ +bool QOpenGLShader::compileSourceFile(const QString& fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "QOpenGLShader: Unable to open file" << fileName; + return false; + } + + QByteArray contents = file.readAll(); + return compileSourceCode(contents.constData()); +} + +/*! + Returns the source code for this shader. + + \sa compileSourceCode() +*/ +QByteArray QOpenGLShader::sourceCode() const +{ + Q_D(const QOpenGLShader); + GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; + if (!shader) + return QByteArray(); + GLint size = 0; + d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); + if (size <= 0) + return QByteArray(); + GLint len = 0; + char *source = new char [size]; + d->glfuncs->glGetShaderSource(shader, size, &len, source); + QByteArray src(source); + delete [] source; + return src; +} + +/*! + Returns \c true if this shader has been compiled; false otherwise. + + \sa compileSourceCode(), compileSourceFile() +*/ +bool QOpenGLShader::isCompiled() const +{ + Q_D(const QOpenGLShader); + return d->compiled; +} + +/*! + Returns the errors and warnings that occurred during the last compile. + + \sa compileSourceCode(), compileSourceFile() +*/ +QString QOpenGLShader::log() const +{ + Q_D(const QOpenGLShader); + return d->log; +} + +/*! + Returns the OpenGL identifier associated with this shader. + + \sa QOpenGLShaderProgram::programId() +*/ +GLuint QOpenGLShader::shaderId() const +{ + Q_D(const QOpenGLShader); + return d->shaderGuard ? d->shaderGuard->id() : 0; +} + +class QOpenGLShaderProgramPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLShaderProgram) +public: + QOpenGLShaderProgramPrivate() + : programGuard(nullptr) + , linked(false) + , inited(false) + , removingShaders(false) + , glfuncs(new QOpenGLExtraFunctions) +#ifndef QT_OPENGL_ES_2 + , tessellationFuncs(nullptr) +#endif + , linkBinaryRecursion(false) + { + } + ~QOpenGLShaderProgramPrivate(); + + QOpenGLSharedResourceGuard *programGuard; + bool linked; + bool inited; + bool removingShaders; + + QString log; + QList shaders; + QList anonShaders; + + QOpenGLExtraFunctions *glfuncs; +#ifndef QT_OPENGL_ES_2 + // for tessellation features not in GLES 3.2 + QOpenGLFunctions_4_0_Core *tessellationFuncs; +#endif + + bool hasShader(QOpenGLShader::ShaderType type) const; + + QOpenGLProgramBinaryCache::ProgramDesc binaryProgram; + bool isCacheDisabled() const; + bool compileCacheable(); + bool linkBinary(); + + bool linkBinaryRecursion; +}; + +namespace { + void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteProgram(id); + } +} + + +QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate() +{ + delete glfuncs; + if (programGuard) + programGuard->free(); +} + +bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const +{ + for (QOpenGLShader *shader : shaders) { + if (shader->shaderType() == type) + return true; + } + return false; +} + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with the current QOpenGLContext. + + \sa addShader() +*/ +QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent) + : QObject(*new QOpenGLShaderProgramPrivate, parent) +{ +} + +/*! + Deletes this shader program. +*/ +QOpenGLShaderProgram::~QOpenGLShaderProgram() +{ +} + +/*! + Requests the shader program's id to be created immediately. Returns \c true + if successful; \c false otherwise. + + This function is primarily useful when combining QOpenGLShaderProgram + with other OpenGL functions that operate directly on the shader + program id, like \c {GL_OES_get_program_binary}. + + When the shader program is used normally, the shader program's id will + be created on demand. + + \sa programId() + + \since 5.3 + */ +bool QOpenGLShaderProgram::create() +{ + return init(); +} + +bool QOpenGLShaderProgram::init() +{ + Q_D(QOpenGLShaderProgram); + if ((d->programGuard && d->programGuard->id()) || d->inited) + return true; + d->inited = true; + QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); + if (!context) + return false; + d->glfuncs->initializeOpenGLFunctions(); + +#ifndef QT_OPENGL_ES_2 + if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) { + d->tessellationFuncs = context->versionFunctions(); + 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 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(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(&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(&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(&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(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(&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(&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(&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(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(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(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(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(values[0].constData())); \ + } else { \ + QVarLengthArray 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 \ + (values[0].constData()); \ + colfunc(location, count * cols, data); \ + } else { \ + QVarLengthArray 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 &levels) +{ +#ifndef QT_OPENGL_ES_2 + Q_D(QOpenGLShaderProgram); + if (d->tessellationFuncs) { + QVector 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 QOpenGLShaderProgram::defaultOuterTessellationLevels() const +{ +#ifndef QT_OPENGL_ES_2 + QVector 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(); +#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 &levels) +{ +#ifndef QT_OPENGL_ES_2 + Q_D(QOpenGLShaderProgram); + if (d->tessellationFuncs) { + QVector 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 QOpenGLShaderProgram::defaultInnerTessellationLevels() const +{ +#ifndef QT_OPENGL_ES_2 + QVector 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(); +#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(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 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 diff --git a/src/opengl/qopenglshaderprogram.h b/src/opengl/qopenglshaderprogram.h new file mode 100644 index 0000000000..87da4fc072 --- /dev/null +++ b/src/opengl/qopenglshaderprogram.h @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QOPENGLSHADERPROGRAM_H +#define QOPENGLSHADERPROGRAM_H + +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +class QOpenGLContext; +class QOpenGLShaderProgram; +class QOpenGLShaderPrivate; + +class Q_OPENGL_EXPORT QOpenGLShader : public QObject +{ + Q_OBJECT +public: + enum ShaderTypeBit + { + Vertex = 0x0001, + Fragment = 0x0002, + Geometry = 0x0004, + TessellationControl = 0x0008, + TessellationEvaluation = 0x0010, + Compute = 0x0020 + }; + Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit) + + explicit QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent = nullptr); + ~QOpenGLShader(); + + QOpenGLShader::ShaderType shaderType() const; + + bool compileSourceCode(const char *source); + bool compileSourceCode(const QByteArray& source); + bool compileSourceCode(const QString& source); + bool compileSourceFile(const QString& fileName); + + QByteArray sourceCode() const; + + bool isCompiled() const; + QString log() const; + + GLuint shaderId() const; + + static bool hasOpenGLShaders(ShaderType type, QOpenGLContext *context = nullptr); + +private: + friend class QOpenGLShaderProgram; + + Q_DISABLE_COPY(QOpenGLShader) + Q_DECLARE_PRIVATE(QOpenGLShader) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLShader::ShaderType) + + +class QOpenGLShaderProgramPrivate; + +class Q_OPENGL_EXPORT QOpenGLShaderProgram : public QObject +{ + Q_OBJECT +public: + explicit QOpenGLShaderProgram(QObject *parent = nullptr); + ~QOpenGLShaderProgram(); + + bool addShader(QOpenGLShader *shader); + void removeShader(QOpenGLShader *shader); + QList shaders() const; + + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source); + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source); + bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName); + + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source); + bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source); + bool addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName); + + void removeAllShaders(); + + virtual bool link(); + bool isLinked() const; + QString log() const; + + bool bind(); + void release(); + + bool create(); + + GLuint programId() const; + + int maxGeometryOutputVertices() const; + + void setPatchVertexCount(int count); + int patchVertexCount() const; + + void setDefaultOuterTessellationLevels(const QVector &levels); + QVector defaultOuterTessellationLevels() const; + + void setDefaultInnerTessellationLevels(const QVector &levels); + QVector defaultInnerTessellationLevels() const; + + void bindAttributeLocation(const char *name, int location); + void bindAttributeLocation(const QByteArray& name, int location); + void bindAttributeLocation(const QString& name, int location); + + int attributeLocation(const char *name) const; + int attributeLocation(const QByteArray& name) const; + int attributeLocation(const QString& name) const; + + void setAttributeValue(int location, GLfloat value); + void setAttributeValue(int location, GLfloat x, GLfloat y); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(int location, const QVector2D& value); + void setAttributeValue(int location, const QVector3D& value); + void setAttributeValue(int location, const QVector4D& value); + void setAttributeValue(int location, const QColor& value); + void setAttributeValue(int location, const GLfloat *values, int columns, int rows); + + void setAttributeValue(const char *name, GLfloat value); + void setAttributeValue(const char *name, GLfloat x, GLfloat y); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(const char *name, const QVector2D& value); + void setAttributeValue(const char *name, const QVector3D& value); + void setAttributeValue(const char *name, const QVector4D& value); + void setAttributeValue(const char *name, const QColor& value); + void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); + + void setAttributeArray + (int location, const GLfloat *values, int tupleSize, int stride = 0); + void setAttributeArray + (int location, const QVector2D *values, int stride = 0); + void setAttributeArray + (int location, const QVector3D *values, int stride = 0); + void setAttributeArray + (int location, const QVector4D *values, int stride = 0); + void setAttributeArray + (int location, GLenum type, const void *values, int tupleSize, int stride = 0); + void setAttributeArray + (const char *name, const GLfloat *values, int tupleSize, int stride = 0); + void setAttributeArray + (const char *name, const QVector2D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector3D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector4D *values, int stride = 0); + void setAttributeArray + (const char *name, GLenum type, const void *values, int tupleSize, int stride = 0); + + void setAttributeBuffer + (int location, GLenum type, int offset, int tupleSize, int stride = 0); + void setAttributeBuffer + (const char *name, GLenum type, int offset, int tupleSize, int stride = 0); + + void enableAttributeArray(int location); + void enableAttributeArray(const char *name); + void disableAttributeArray(int location); + void disableAttributeArray(const char *name); + + int uniformLocation(const char *name) const; + int uniformLocation(const QByteArray& name) const; + int uniformLocation(const QString& name) const; + + void setUniformValue(int location, GLfloat value); + void setUniformValue(int location, GLint value); + void setUniformValue(int location, GLuint value); + void setUniformValue(int location, GLfloat x, GLfloat y); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(int location, const QVector2D& value); + void setUniformValue(int location, const QVector3D& value); + void setUniformValue(int location, const QVector4D& value); + void setUniformValue(int location, const QColor& color); + void setUniformValue(int location, const QPoint& point); + void setUniformValue(int location, const QPointF& point); + void setUniformValue(int location, const QSize& size); + void setUniformValue(int location, const QSizeF& size); + void setUniformValue(int location, const QMatrix2x2& value); + void setUniformValue(int location, const QMatrix2x3& value); + void setUniformValue(int location, const QMatrix2x4& value); + void setUniformValue(int location, const QMatrix3x2& value); + void setUniformValue(int location, const QMatrix3x3& value); + void setUniformValue(int location, const QMatrix3x4& value); + void setUniformValue(int location, const QMatrix4x2& value); + void setUniformValue(int location, const QMatrix4x3& value); + void setUniformValue(int location, const QMatrix4x4& value); + void setUniformValue(int location, const GLfloat value[2][2]); + void setUniformValue(int location, const GLfloat value[3][3]); + void setUniformValue(int location, const GLfloat value[4][4]); + void setUniformValue(int location, const QTransform& value); + + void setUniformValue(const char *name, GLfloat value); + void setUniformValue(const char *name, GLint value); + void setUniformValue(const char *name, GLuint value); + void setUniformValue(const char *name, GLfloat x, GLfloat y); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(const char *name, const QVector2D& value); + void setUniformValue(const char *name, const QVector3D& value); + void setUniformValue(const char *name, const QVector4D& value); + void setUniformValue(const char *name, const QColor& color); + void setUniformValue(const char *name, const QPoint& point); + void setUniformValue(const char *name, const QPointF& point); + void setUniformValue(const char *name, const QSize& size); + void setUniformValue(const char *name, const QSizeF& size); + void setUniformValue(const char *name, const QMatrix2x2& value); + void setUniformValue(const char *name, const QMatrix2x3& value); + void setUniformValue(const char *name, const QMatrix2x4& value); + void setUniformValue(const char *name, const QMatrix3x2& value); + void setUniformValue(const char *name, const QMatrix3x3& value); + void setUniformValue(const char *name, const QMatrix3x4& value); + void setUniformValue(const char *name, const QMatrix4x2& value); + void setUniformValue(const char *name, const QMatrix4x3& value); + void setUniformValue(const char *name, const QMatrix4x4& value); + void setUniformValue(const char *name, const GLfloat value[2][2]); + void setUniformValue(const char *name, const GLfloat value[3][3]); + void setUniformValue(const char *name, const GLfloat value[4][4]); + void setUniformValue(const char *name, const QTransform& value); + + void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize); + void setUniformValueArray(int location, const GLint *values, int count); + void setUniformValueArray(int location, const GLuint *values, int count); + void setUniformValueArray(int location, const QVector2D *values, int count); + void setUniformValueArray(int location, const QVector3D *values, int count); + void setUniformValueArray(int location, const QVector4D *values, int count); + void setUniformValueArray(int location, const QMatrix2x2 *values, int count); + void setUniformValueArray(int location, const QMatrix2x3 *values, int count); + void setUniformValueArray(int location, const QMatrix2x4 *values, int count); + void setUniformValueArray(int location, const QMatrix3x2 *values, int count); + void setUniformValueArray(int location, const QMatrix3x3 *values, int count); + void setUniformValueArray(int location, const QMatrix3x4 *values, int count); + void setUniformValueArray(int location, const QMatrix4x2 *values, int count); + void setUniformValueArray(int location, const QMatrix4x3 *values, int count); + void setUniformValueArray(int location, const QMatrix4x4 *values, int count); + + void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize); + void setUniformValueArray(const char *name, const GLint *values, int count); + void setUniformValueArray(const char *name, const GLuint *values, int count); + void setUniformValueArray(const char *name, const QVector2D *values, int count); + void setUniformValueArray(const char *name, const QVector3D *values, int count); + void setUniformValueArray(const char *name, const QVector4D *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); + + static bool hasOpenGLShaderPrograms(QOpenGLContext *context = nullptr); + +private Q_SLOTS: + void shaderDestroyed(); + +private: + Q_DISABLE_COPY(QOpenGLShaderProgram) + Q_DECLARE_PRIVATE(QOpenGLShaderProgram) + + bool init(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/opengl/qopengltextureblitter.cpp b/src/opengl/qopengltextureblitter.cpp index ba2eaf7754..6f0ee863d7 100644 --- a/src/opengl/qopengltextureblitter.cpp +++ b/src/opengl/qopengltextureblitter.cpp @@ -39,8 +39,8 @@ #include "qopengltextureblitter.h" +#include #include -#include #include #include #include diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h index 8768f9dd8c..7a6044aca0 100644 --- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h @@ -54,9 +54,9 @@ #include "qeglfsglobal_p.h" #include #include +#include #include #include -#include #include #include -- cgit v1.2.3